Completely custom individuals

3,013 views
Skip to first unread message

Dražen Lučanin

unread,
Mar 3, 2014, 2:44:08 AM3/3/14
to deap-...@googlegroups.com
Hi all,

I'm trying to use deap for solving a multiple constraint optimisation problem. Since my model is rather big, with many components and not really abiding to any list- or tree-like structure, I would like to completely implement it myself with all the operators and fitness function and let deap handle just the meta-optimisation work for me - selection, generation propagation, parametrisation of the frequency of certain operations etc. Can something like this be achieved in deap?

I would like to provide a class similar to this to DEAP:

class MyUnit():

    def mutation(self):
        ...
        return mutated_unit

    def cross-over(self, other_unit):
        ...
        return child

    def fitness(self):
        ...
        return my_fitness

And also a function for generating or a pre-made initial list of individuals.

If this is possible, could you please point me at the relevant docs or an example of how to achieve it? In the official docs I mostly found instructions for creating models using deap's tools.

Cheers,
Dražen

François-Michel De Rainville

unread,
Mar 4, 2014, 12:23:40 PM3/4/14
to deap-...@googlegroups.com
The model in DEAP is to use functions for crossover, mutation, and evaluation, not class methods. An individual is not responsible for mating or mutating itself.  But, your mutation, crossover, and evaluation functions can rely on specific attributes to perform their task. This would result in something like 

# Container module: utils.py

Class MyContainer(object):
    # This class does not require the fitness attribute
    # it will be  added later by the creator
    def __init__(self, attributes):
        # Some initialisation with received values
        self.attr1 = attributes[0]

def initIndividual(ind_class, size):
    # ind_class will receive a class inheriting from MyContainer
    ind = ind_class(random.random() for _ in range(size))
    return ind

def mutation(individual):
    individual.attr1 += 42
    return (individual,)

# ...


# Execution module: main.py

import utils

creator.create("FitnessMin", base.Fitness, weights=(-1.0, -1.0))
creator.create("Individual", utils.MyContainer, fitness=creator.Fitness)

toolbox = base.Toolbox()
toolbox.register("individual", utils.initIndividual, creator.Individual, size=8)
toolbox.register("mutate", utils.mutation)

test_ind = toolbox.individual()
issubclass(type(test_ind), utils.MyContainer)
test_ind.fitness.values = 4, 5
toolbox.mutate(test_ind)

#...

With this intialization the creator is still responsible to add a fitness to your individuals (so it can be switched easily in the main module) and your container can be anything with your crossover, mutation, and evaluation functions applying on it.

Using a similar initialisation you can fill your individual with precomputed data instead of relying on a random number generator.

I hope this is useful,
Have fun with DEAP,
François-Michel


--
You received this message because you are subscribed to the Google Groups "deap-users" group.
To unsubscribe from this group and stop receiving emails from it, send an email to deap-users+...@googlegroups.com.
For more options, visit https://groups.google.com/groups/opt_out.

Dražen Lučanin

unread,
Mar 4, 2014, 12:40:06 PM3/4/14
to deap-...@googlegroups.com
Hi François-Michel,

thanks for the response! This is exactly what I had in mind. I'll give it a try.

Cheers,
Dražen

Jitesh Khandelwal

unread,
Nov 3, 2014, 5:12:36 AM11/3/14
to deap-...@googlegroups.com
Hi,

Could you please expand on this as in what is the exact api that needs to be implemented for using custom individuals with deap.

Thanks
Jitesh

adam.g...@gmail.com

unread,
May 16, 2017, 9:09:06 AM5/16/17
to deap-users
Hi,

I was trying to run this example as is to try to define a custom individual but it seemed I get an error like this if I run the example as it is written in the previous reply:

 creator.create("Individual", utils.MyContainer, fitness=creator.Fitness)
AttributeError: 'module' object has no attribute 'Fitness'

I wanted to modify the example to construct a 2 d numpy array individual similar to this: [[a,b],[c,d]...] where a,b,c,d are floating point values in a set range with an condition that first element in the 2 element arrays are always lower than the second... Any pointers on how to achieve something like this would be appreciated, I am also new to DEAP and was having some difficulty finding examples of custom individuals...

Thanks in advance,

Adam

ag

unread,
May 18, 2017, 3:32:36 AM5/18/17
to deap-users
Hello, 

I have tried implementing the 2d array using the pattern described and ended up with the code copied below for possible interest as is related to some other questions on constructing custom containers / representation.

It does seem to be possible to run the mutation and to initialise the individual inheriting from a numpy array. But I just wonder if I am using the DEAP library in the optimal way - it just seems a little bit clumsy.

For example I found in the initIndividual method the parameter ind_class (a class of an individual that implementing a numpy array as set in MyContainer) that it was quite difficult to set the solution variables/genes/parameters because cannot find where the individual constructor is defined and it seems the normal definition of ndarray is changed (e.g. constructor behaves differently) and also is possible depending on seemingly unrelated code to lose the variables that store fitness in the individual... 

Another issue was it seemed not possible access the variable used in the above example in initialisation  attributes[0]... 

Thanks in advance,
Adam

# Container module: utils.py

creator.create("FitnessMin", base.Fitness, weights=(-1.0,))
creator.create("Individual", utils.MyContainer, fitness=creator.FitnessMin)

toolbox = base.Toolbox()
toolbox.register("individual", utils.initIndividual, creator.Individual, size=16) # size is number of variables
toolbox.register("mutate", utils.mutation)

test_ind = toolbox.individual( )

issubclass(type(test_ind), utils.MyContainer)

test_ind.fitness.values = 4,
toolbox.mutate(test_ind)

#print "attr1 = %s"  % (test_ind.attr1)
print test_ind.fitness
print  test_ind 

#...

# Execution module: main.py

import random
import numpy as np

class MyContainer(np.ndarray):
    # This class does not require the fitness attribute
    # it will be  added later by the creator
    def __init__(self, attributes):
        # Some initialisation with received values
        pass

def initIndividual(ind_class, size):
    # ind_class will receive a class inheriting from MyContainer
    #ind = ind_class(random.random() for _ in range(size))

    ind = ind_class((size/2,2))
    for i in range(size/2):  
        ind[i,0] = random.randint(53,67)
        ind[i,1] = ind[i,0] + random.randint(1,5)         
    
    return ind

def mutation(ind):
    print "mutate" + str(ind)
    for i in range(ind.size / 2):
        if random.random() < 1.0 / (float(ind.size) / 2.0):
            print "swap " + str(i)
            ind[i,0] = random.randint(53,67)
            ind[i,1] = ind[i,0] + random.randint(1,5)
    return (ind,)

# ...

François-Michel De Rainville

unread,
May 25, 2017, 8:52:19 AM5/25/17
to deap-users
Your code sounds about right.

Basically, the Individual constructor is inherited from the type you use as base class. Plus, for convenience, we added a constructor that takes an iterable for numpy arrays. Thus, you can do something like Individual(range(10)) in Python 3 or use initRepeat and initIterate.

The problem with "loosing type" is a tradeoff between requiring users to construct a new individual after each crossover and mutation or just be carefull to do the crossover and mutation in-place. The later being orders faster than the former, we chose asking users to be carefull.

Regards,

To unsubscribe from this group and stop receiving emails from it, send an email to deap-users+unsubscribe@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.

Lirong

unread,
May 31, 2018, 8:02:42 AM5/31/18
to deap-users
Hi François-Michel,

With your inspiration from this post, I implemented my individual initialization as follows, but I got: AttributeError: 'list' object has no attribute 'fitness'. Could you please shred some light? I'm searched all other related posts here but still haven't found any answer.


class MyContainer(list):

   
def __init__(self, attributes):
       
# Some initialisation with received values

       
# self.attr1 = attributes[0]
       
pass


def generate_individual(ind_class, size):

   
# ind_class will receive a class inheriting from MyContainer

   
# individual = ind_class(random.random() for _ in range(size))
   individual
= ind_class(random.sample(range(IND_SIZE), k=size))
   individual
= make_individual_valid(individual, other_parameters)
   
# make_individual_valid is the self-defined order constraint function
   
return individual

creator
.create('FitnessMin', base.Fitness, weights=(-1.0,))
creator
.create('Individual', MyContainer, fitness=creator.FitnessMin)

toolbox
= base.Toolbox()
toolbox
.register('individual', generate_individual, creator.Individual, size=IND_SIZE)
toolbox
.register('population', tools.initRepeat, list, toolbox.individual)

François-Michel De Rainville

unread,
May 31, 2018, 1:48:59 PM5/31/18
to deap-users
My guess would be your mutation and crossover operators. Are you sure they return a creator.Individual object?

To unsubscribe from this group and stop receiving emails from it, send an email to deap-users+unsubscribe@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.

Reply all
Reply to author
Forward
0 new messages