Using the Toolbox

The Toolbox class is the main component of computational evolution, which is a container for all the necessary tools to build genetic algorithms and solve evolutionary problems with. Using a toolbox enables the separation of algorithms from the operators, which makes it easy to hot swap the operators during evolution in a plug-and-play manner as needed.

The two most important methods of a toolbox are register() and unregister(), which are used to add or remove tools from the toolbox. The register() method takes at least two arguments: an alias and a function that is going to be associated with the alias. All subsequent arguments, if there are any, will be implicitly passed into the associated function when the registered method is called.

Attention

Alias names must be valid Python identifiers and can be registered into each toolbox only once.

from deap_er import base

def add_func(a, b, c):
    return a + b + c

toolbox = base.Toolbox()
toolbox.register("first_alias", add_func, a=1, b=2, c=3)  # args are passed implicitly
toolbox.register("other_alias", add_func)                 # args are passed explicitly

result = toolbox.first_alias()         # result == 6
result = toolbox.other_alias(1, 2, 3)  # result == 6

The preceding code registers two aliases in the toolbox: first_alias and other_alias, which point to the same function add_func. In the case of toolbox.first_alias(), the arguments were already passed during registration, so the method needs to be called without arguments. In the case of toolbox.other_alias(1, 2, 3), the arguments must be passed explicitly, because the method was registered without arguments. The difference between the two is that the arguments of first_alias are static, while the arguments of other_alias are dynamic.


Tool Registration

A toolbox is only as useful as the tools registered into it. The tools module contains a number of useful tools that can be registered into a toolbox. While all tools in the module can be registered into a toolbox, some of them such as algorithms or statistics, are equally useful independently. More on tools in the Operators and Algorithms chapter.

Because tools are registered into toolboxes dynamically at runtime, linting hints are not available
for these toolbox methods and IDEs incorrectly mark their usage as erroneous due to lack of object references.

Note

Some commonly used aliases, such as mate, mutate, select, evaluate and others, do have abstract references available, which enables IDE autocompletion support for them. Note that these references are abstract and must be overridden by the user before they can be used.

from deap_er import base, tools

toolbox = base.Toolbox()
toolbox.register("mate", tools.cx_two_point)
toolbox.register("mutate", tools.mut_flip_bit, mut_prob=0.2)
toolbox.register("select", tools.sel_tournament, contestants=3)
toolbox.register("evaluate", tools.bm_sphere)

pop, log = tools.ea_simple(**args)

Tool Decoration

Tool decoration is a powerful feature that allows the precise control of parameters during the evolution process. For example, in the case of constrained domains, a tool decorator can be used on mutation and crossover operators to prevent the individuals from growing out-of-bounds.

The following example defines a decorator that checks if the solution values of offsprings are out-of-bounds and clamps them to the predefined limit values if this is the case. Whenever either of the decorated tools is called, bounds will be checked on the resulting offsprings.

Note

This decorator works for both crossover and mutation operators, because the return type of these operators must be a tuple.

def clamp(min, max):
    def wrapper(func):
        def wrapped(*args, **kwargs):
            offsprings: tuple = func(*args, **kwargs)
            for child in offsprings:
                for i in range(len(child)):
                    if child[i] > max:
                        child[i] = max
                    elif child[i] < min:
                        child[i] = min
            return offspring
        return wrapped
    return wrapper

toolbox.register("mate", tools.cx_blend, alpha=0.2)
toolbox.register("mutate", tools.mut_gaussian,
    mu=0, sigma=2, mut_prob=0.2
)
toolbox.decorate("mate", clamp(MIN, MAX))
toolbox.decorate("mutate", clamp(MIN, MAX))