I'm writing my first evolutionary algorithm with DEAP. Everything is working, but the MultiFlipBit mutation operator. When I attempt to mutate a Tree (Individual), I get the following error:
File "Genetic_Programming.py", line 92, in main
halloffame=hof, verbose=True)
offspring = varOr(population, toolbox, lambda_, cxpb, mutpb)
File "/Users/anaconda/lib/python2.7/site-packages/deap/algorithms.py", line 235, in varOr
ind, = toolbox.mutate(ind)
File "/Users/anaconda/lib/python2.7/site-packages/deap/tools/mutation.py", line 132, in mutFlipBit
individual[i] = type(individual[i])(not individual[i])
TypeError: __init__() takes exactly 4 arguments (2 given)
Here is the code:
pset = gp.PrimitiveSet("MAIN", 8)
pset.addPrimitive(operator.and_, 2)
pset.addPrimitive(operator.or_, 2)
pset.addPrimitive(operator.xor, 2)
pset.addPrimitive(operator.not_, 1)
creator.create("FitnessMax", base.Fitness, weights=(1.0,))
creator.create("Individual", gp.PrimitiveTree, fitness=creator.FitnessMax)
toolbox = base.Toolbox()
toolbox.register("expr", gp.genGrow, pset=pset, min_=1, max_=8)
toolbox.register("individual", tools.initIterate, creator.Individual, toolbox.expr)
toolbox.register("population", tools.initRepeat, list, toolbox.individual)
toolbox.register("compile", gp.compile, pset=pset)
def evalSymbReg(individual):
# Transform the tree expression in a callable function
print individual
ind = toolbox.compile(expr=individual)
# Evaluate the mean squared error between the expression
# and the real function : x**4 + x**3 + x**2 + x
performance=Genetic_V0.genetic_backtest(ind)
return performance,
toolbox.register("evaluate", evalSymbReg)
toolbox.register("select", tools.selTournament, tournsize=50)
toolbox.register("mate", gp.cxOnePoint)
#toolbox.register("expr_mut", gp.genGrow, min_=1, max_=4)
#toolbox.register("mutate", tools.mutFlipBit, expr=toolbox.expr_mut, pset=pset)
toolbox.register("mutate", tools.mutFlipBit, indpb=0.95)
def main():
nu=50
pop = toolbox.population(n=nu)
hof = tools.HallOfFame(3)
stats_fit = tools.Statistics(lambda ind: ind.fitness.values)
stats_size = tools.Statistics(len)
mstats = tools.MultiStatistics(fitness=stats_fit, size=stats_size)
mstats.register("avg", numpy.mean)
mstats.register("std", numpy.std)
mstats.register("min", numpy.min)
mstats.register("max", numpy.max)
pop, log = algorithms.eaMuPlusLambda(pop, toolbox, nu/2, nu/2, 0.85, 0.15, 200,stats=mstats,
halloffame=hof, verbose=True)
# print log
return pop, log, hof
if __name__ == "__main__":
main()
Thanks in advance for the help.
python version: 2.7
EDITED: After a suggestion on how solving the problem, I've added to the DEAP mutation library a couple of "print" to better understand what is happening. Here is the same error, as per original question, but with some extra information:
individual is not_(ARG7)
individual[i] is <deap.gp.Primitive object at 0x10746c158>
(not individual[i]) is False
type(individual[i]) is <class 'deap.gp.Primitive'>
type(individual[i])(not individual[i]) is
Traceback (most recent call last):
File "Genetic_Programming.py", line 98, in <module>
main()
File "Genetic_Programming.py", line 92, in main
halloffame=hof, verbose=True)
File "/Users/giorgio/anaconda/lib/python2.7/site-packages/deap/algorithms.py", line 317, in eaMuPlusLambda
offspring = varOr(population, toolbox, lambda_, cxpb, mutpb)
File "/Users/giorgio/anaconda/lib/python2.7/site-packages/deap/algorithms.py", line 235, in varOr
ind, = toolbox.mutate(ind)
File "/Users/giorgio/anaconda/lib/python2.7/site-packages/deap/tools/mutation.py", line 136, in mutFlipBit
print "type(individual[i])(not individual[i]) is ", type(individual[i])(not individual[i])
TypeError: __init__() takes exactly 4 arguments (2 given)
Thanks again for any contributes
The error is complaining that you are trying to use a deap.tools.mutFlipBit
function as a mutator on a indivual that is instance of deap.gp.PrimitiveTree
. From the docs of mutFlipBit:
The individual is expected to be a sequence and the values of the attributes shall stay valid after the not operator is called on them.
So if the code decided to mutate the element i
of individual
, it is trying to evaluate deap.dp.Primitive(not ind[i])
. And the error complains that the constructor of Primitive
takes 4 arguments, self, name, args, ret
instead of the passed self, (not ind[1])
.
The cause of the error is twofold,
A mutBitFlip
mutator is being a applied to an individual that consists of a list of both "symbolic values" and "operators", instead of a list of booleans as expected. So the code could try to negate an operator, e.g. fliping an and, which is not defined. However, the code will produce False
because an object is evaluated to True
in a boolean context, and will end up trying to create a new Primitive
from a single argument which is a boolean value.
Even if mutFlipBit
function could discriminate between a Primitive
and a Terminal
, and would only try to negate Terminal
s, deap
will use symbolic terminals, because the primary target of a PrimitiveTree
is not to find a single expressions equivalent to a value (i.e. constant), but rather a expressions, with arguments, equivalent to a function.
You should revisit what are you trying to evolve, an expression that maps to a boolean equation or a set of arguments to a boolean function. And based on that redesign your code.
INITIAL ANSWER:
Your code is not complete, since the line offspring = varOr(population, toolbox, lambda_, cxpb, mutpb)
is not shown.
However, the problem is caused by the type of one of your invidivuals in your population
variable. The code is assuming that your individuals are a list of booleans, so the code individual[i] = type(individual[i])(not individual[i])
would work:
x = True
print type(x)(not x) # Equivalent of bool(True) => False
The error says that, type(individual[i])
got the init of a class which expects 3 arguments, e.g. self
+ other 3 arguments.