The base module provides basic structures to build evolutionary algorithms.
As of version 0.5.0, eap does not provide base types that wrap python base types, instead it is possible to create your own types that inherits from whatever type is more convenient or appropriate, for example, list, array, set, dict, etc. As most of those types are initialized using an iterable, the creator allows to create these objects using internal generators in order to produce objects with different content. See the creator module for more information.
Basic N-ary tree class.
Convert node into the proper object either a Tree or a Node.
Return the state of the Tree as a list of arbitrary elements. It is mainly used for pickling a Tree object.
Return the height of the tree.
The height of a tree is the length of the path from the root to the deepest node in the tree. A (rooted) tree with only one node (the root) has a height of zero.
Return the root element of the tree.
The root node of a tree is the node with no parents. There is at most one root node in a rooted tree.
Search the subtree with the corresponding index based on a breadth-first search.
Search the subtree with the corresponding index based on a depth-first search.
Replace the subtree with the corresponding index by subtree based on a breadth-first search.
Replace the tree with the corresponding index by subtree based on a depth-first search.
Return the number of nodes in the tree.
The size of a node is the number of descendants it has including itself.
The fitness is a measure of quality of a solution.
Fitnesses may be compared using the >, <, >=, <=, ==, !=. The comparison of those operators is made lexicographically. Maximization and minimization are taken care off by a multiplication between the weights and the fitness values. The comparison can be made between fitnesses of different size, if the fitnesses are equal until the extra elements, the longer fitness will be superior to the shorter.
In addition to the comparaison operators that are used to sort lexically the fitnesses, this method returns True if this fitness is dominated by the other fitness and False otherwise. The weights are used to compare minimizing and maximizing fitnesses. If there is more fitness values than weights, the las weight get repeated until the end of the comparaison.
Asses if a fitness is valid or not.
Fitness values. Use directly individual.fitness.values = values in order to set the fitness and del individual.fitness.values in order to clear (invalidate) the fitness. The (unweighted) fitness can be directly accessed via individual.fitness.values.
The weights are used in the fitness comparison. They are shared among all fitnesses of the same type. This member is not meant to be manipulated since it may influence how fitnesses are compared and may result in undesirable effects. However if you wish to manipulate it, in order to make the change effective to all fitnesses of the same type, use FitnessType.weights = new_weights or self.__class__.weights = new_weights or from an individual ind.fitness.__class__.weights = new_weights.
Contains the weighted values of the fitness, the multiplication with the weights is made when the values are set via the property values. Multiplication is made on setting of the values for efficiency.
Generaly it is unnecessary to manipulate wvalues as it is an internal attribute of the fitness used in the comparison operators.
The creator module is the heart and soul of EAP, it allows to create, at runtime, classes that will fulfill the needs of your evolutionary algorithms.
The function create() does create a new class named name inheriting from base in the creator module. The new class can have attributes defined by the subsequent keyworded arguments passed to the function create. If the argument is callable, it is automatically called in the initialisation of an instance of this class and the returned object is added as an attribute of the class’ instance. Otherwise, if the argument is not callable, (for example an int), it is added as a “static” attribute of the class.
For example, using
creator("MyType", object, value=4, data=lambda: random.random())
is the same as defining in the module eap.creator
class MyType(object):
value = 4
def __init__(self):
self.data = random.random()
All application specific structures may be built using the create() function and types defined in python or the base module. Here are some simple recipes to build very simple types.
As described earlier, the eap.base.Fitness instantiate by default a minimizing fitness. This can be changed using the creator and its eap.creator.create() function. A maximizing fitness can be created using
create("FitnessMax", base.Fitness, weights=(1.0,))
There is only one rule when building an individual, it must contain a fitness attribute. The following all produce valid individuals that are suited for most evolutionary algorithms.
The individual list is suited for binary, integer, float and even funky individuals. It may contain any type and/or any type mix that is needed. The IndividualList type is created with
create("IndividualList", list, fitness=creator.FitnessMax)
and an individual of size 5 is instantiated with
content = [random.random() for i in xrange(5)]
ind = creator.IndividualList(content)
Note
For individuals containing only a single numeric type, it may be more suited to use the array base class, as the copy operation is way more efficient.
The individual indices is almost the same as the individual list, except for its content. Here we will use the maximizing fitness describes earlier
create("IndividualIndices", list, fitness=creator.FitnessMax)
and an individual indices of size 5 is instantiated with
content = random.sample(xrange(5), 5)
ind = creator.IndividualIndices(content)
The individual tree is a bit harder to create. We first must define a primitive set and the operator we need in our post-fix trees.
pset = gp.PrimitiveSet("MAIN", 1)
pset.addPrimitive(operator.add, 2)
pset.addPrimitive(operator.sub, 2)
pset.addPrimitive(operator.mul, 2)
Then it is just as easy as other types, the tree class may be initialized from a iterable. The gp module contains some helper functions to build trees. For example, the generate_full() will produce a full tree.
creator.create("IndividualTree", gp.PrimitiveTree, fitness=creator.FitnessMax, pset=pset)
ind = creator.IndividualTree(gp.generate_full(pset=pset, min=3, max=5))
A population is usually a list of individuals or sub-populations, it is no more complicated to create than an individual. When using a Toolbox, it is often not necessary to create a class Population, it is made here just to show how it would be created.
create("Population", list)
A population of 10 individuals of indices is instanciated using
ind_content = lambda: random.sample(xrange(5), 5)
pop_content = [creator.IndividualIndices(ind_content()) for i in xrange(10)]
pop = creator.Population(pop_content)
Note
A deme (sub-population) is no more than a population, it is created the same way as a population (or any other list type).
See also
The First Steps of Evolution shows how to combine the creator and the toolbox to initialize types.