Search code examples
pythongenetic-programmingmutationdeap

TypeError with Python DEAP mutFlipBit


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


Solution

  • 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,

    1. 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.

    2. Even if mutFlipBit function could discriminate between a Primitive and a Terminal, and would only try to negate Terminals, 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.