Platypus
Platypus copied to clipboard
Cannot use Integer type with others?
If I attempt to use a problem.types
array that contains an Integer
type and a Real
, it runs for a while and then I get the error
platypus.core.PlatypusError: must define variator for mixed types
Unfortunately, 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 list problem.types
. Now, the type Integer
is defined as a subclass of Binary
in the file types.py, and Binary
is a type defined in PlatypusConfig.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 from Binary
, since Integer
is based on it anyway):
class _PlatypusConfig(object):
def __init__(self):
super(_PlatypusConfig, self).__init__()
self.default_variator = {Real : GAOperator(SBX(), PM()),
Binary : GAOperator(HUX(), BitFlip()),
Integer : GAOperator(HUX(), BitFlip()),
Permutation : CompoundOperator(PMX(), Insertion(), Swap()),
Subset : GAOperator(SSX(), Replace())}
self.default_mutator = {Real : PM(),
Binary : BitFlip(),
Integer : BitFlip(),
Permutation : CompoundMutation(Insertion(), Swap()),
Subset : Replace()}
...
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 writing if 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.
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.