Genetic Algorithms - Deap - eaSimple error

84 Views Asked by At

I am developing a simple genetic algorithm using Python and the Deap library . At the end of all I am launching the eaSimple function to have the population evolved, but I keep having the following error : "object 'int' has no len()'. The algorithm is very basic and its mostly cut and pasted from a model algorithm taken from a course, which is allegedly working fine. Here is the involved section of code :

def safediv (dividend, divisor):
    if divisor != 0:
        return dividend / divisor
    else:
        return dividend
        
        
#select the primitives 
pset = gp.PrimitiveSet("main", 6)    #arity is 6 because as we'll see, the primitiveset 's function is calculated over 6 param (f12,d12, f1, etc..)'
pset.addPrimitive(operator.add, 2)
pset.addPrimitive(operator.mul, 2)
pset.addPrimitive(operator.sub, 2)
pset.addPrimitive(safediv,2)
            
creator.create ("MyFitness", base.Fitness, weights=(-1.0,))    
creator.create ("Individual", gp.PrimitiveTree, fitness = creator.MyFitness)

toolbox = base.Toolbox()
toolbox.register("expr",
               gp.genGrow, 
               pset=pset, 
               min_ = 1,  # minimum depth of primitivetree 
               max_ = 4)  # maximum depth of primitivetree (max of nested primitive calls)

toolbox.register("individual",      #function for creating the single individual
               tools.initIterate,    #initIterate takes the first arg (creator.Individual) and builds it with the structur coming from the second
               creator.Individual, # (tools.expr)
               toolbox.expr)

toolbox.register ("compile", gp.compile, pset = pset)

toolbox.register("population", 
                tools.initRepeat,
                list,
                toolbox.individual)

#parameters to pass to the eaSimple algorithm
toolbox.register("evaluate", MyError,y_train = y_train_set, x_train_ambo = x_train_set_ambo, x_train_extract =x_train_set_extract )
toolbox.register("mate",tools.cxUniform , indpb = 0.3)  #Uniform swaps individual bits between the two parents, rather than segments
                                                     #(see book)
toolbox.register("expr_mut", gp.genFull, min_=0,max_=2)    
toolbox.register("mutate",gp.mutUniform, expr=toolbox.expr_mut,pset= pset)
toolbox.register("select", tools.selTournament, tournSize = 3) #tournaments allow to distribute the selection between multiple processors
                                                            #as picking individuals by 3 at a time can have each #tournament performed
                                                            #on a different cpu and then the selection parallelized
#decorators to limit the growth of the PrimitiveTree       
toolbox.decorate("mate", gp.staticLimit(key=operator.attrgetter("height"), max_value=17))
toolbox.decorate("mutate", gp.staticLimit(key=operator.attrgetter("height"), max_value=17))        

pop = toolbox.population(n=300)
hof = tools.HallOfFame(1)
stat_fit = tools.Statistics (key=lambda ind: ind.fitness.values)
stat_size = tools.Statistics ( key=len)


mstats = tools.MultiStatistics(fitness = stat_fit, size = stat_size)

mstats.register ("min", np.min)
mstats.register ("max", np.max)
mstats.register ("avg", np.mean)
mstats.register ("std", np.std)

pop, log = algorithms.eaSimple(population = pop,  
                               toolbox = toolbox, 
                               cxpb = 0.5,    
                               mutpb = 0.1,    
                               ngen = num_gen,     
                               stats= mstats,
                               halloffame=hof
                               , 
                               verbose=True
                              )
    

The MyError function returns an int, I am confident its working fine since I debugged it accurately, thats why I didn't include the code.

Any idea ?

1

There are 1 best solutions below

0
Yahred Gastélum Velázquez On

The evaluation function needs to return a tuple for DEAP to work, the function "MyError" is returning an int, you only need to change the return value of the function to a tuple, like this:

def MyError(individual):
  return (sum(individual), )

Notice that I'm returning a tuple that contains two elements, the first one is the fitness of my individual and the second one is empty.