Closed mhucka closed 1 year ago
Well, the problem is line 54:
base_type = problem.types[0].__class__
is checking just the first type of your chromosome, not all distinct types in your chromosome.
@dhadka Could you post an example with Float and Integer and how do I add custom variators (Integer : GAOperator(HUX(), BitFlip()))
for Integer inside the problem
?
By default in config.py:
self.default_variator = {Real : GAOperator(SBX(), PM()),
Binary : GAOperator(HUX(), BitFlip()),
Integer : GAOperator(HUX(), BitFlip()), # Added by me
Permutation : CompoundOperator(PMX(), Insertion(), Swap()),
Subset : GAOperator(SSX(), Replace())}
The line added by me: Integer : GAOperator(HUX(), BitFlip()),
enable Integer
type with HUX
and BitFlip
. I have done changes in operators.py
for HUX
and BitFlip
:
class HUX(Variator):
def __init__(self, probability = 1.0):
super(HUX, self).__init__(2)
self.probability = probability
def evolve(self, parents):
result1 = copy.deepcopy(parents[0])
result2 = copy.deepcopy(parents[1])
problem = result1.problem
if random.uniform(0.0, 1.0) <= self.probability:
for i in range(problem.nvars):
if isinstance(problem.types[i], Binary):
for j in range(problem.types[i].nbits):
if result1.variables[i][j] != result2.variables[i][j]:
if bool(random.getrandbits(1)):
result1.variables[i][j] = not result1.variables[i][j]
result2.variables[i][j] = not result2.variables[i][j]
result1.evaluated = False
result2.evaluated = False
if isinstance(problem.types[i], Integer):
ax=result1.variables[i]
bx=result2.variables[i]
result1.variables[i]=bx
result2.variables[i]=ax
result1.evaluated = False
result2.evaluated = False
return [result1, result2]
Adding problem.types -> Integer:
... if isinstance(problem.types[i], Integer): ...
and after change to if True:
in config.py
def default_variator(problem):
if len(problem.types) == 0:
raise PlatypusError("problem has no decision variables")
base_type = problem.types[0].__class__
if True: #all([isinstance(t, base_type) for t in problem.types]):
...
I see that when running it, the Integer variables do not mutate or change, and always integer have the same values in population, but Real variables work fine (mutate, etc).
How can I make it work with Integer?
You would need to do something like:
from platypus import *
def mixed_type(x):
print("Evaluating", x)
return [x[0], x[1]]
problem = Problem(2, 2)
problem.types[0] = Real(0, 10)
problem.types[1] = Integer(0, 10)
problem.function = mixed_type
algorithm = NSGAII(problem, variator=CompoundOperator(SBX(), HUX(), PM(), BitFlip()))
algorithm.run(10000)
print("Final solutions:")
for solution in unique(nondominated(algorithm.result)):
print(solution.variables, solution.objectives)
The key here is that you need to provide a custom variator that is capable of mutating both real and int. We can use the CompoundOperator in most cases to combine operators of different types.
@dhadka Thank you! I can confirm that this works in my case, involving 2 integers and 4 reals, with an unmodified config.py
.
This issue is stale and will be closed soon. If you feel this issue is still relevant, please comment to keep it active. Please also consider working on a fix and submitting a PR.
If I attempt to use a
problem.types
array that contains anInteger
type and aReal
, it runs for a while and then I get the errorUnfortunately, I cannot find an explanation in the documentation about what this error means and what I can do about it. Looking at the source code, the error comes from
isinstance
comparisons to the class of the first element in the listproblem.types
. Now, the typeInteger
is defined as a subclass ofBinary
in the file types.py, andBinary
is a type defined inPlatypusConfig.default_variator
, so it seems like it should work and that the failure comes from not detecting the subclass relationship.As a test of this hypothesis, I added definitions of
Integer
to config.py like this (copying the definitions fromBinary
, sinceInteger
is based on it anyway):and then bypassed the tests for
all([isinstance(t, base_type) for t in problem.types])
on lines 56 and 74 in the file config.py (by simply writingif True:
). The result runs and seems to be working.This was a hack and a correct solution is needed, but I wanted to report the problem and a possible direction to explore for fixing it.