Darwin

The microgp.darwin.Darwin class is in charge of handling the whole evolutionprocess. It contains:

microgp.darwin

class microgp.darwin.Darwin(constraints: microgp.constraints.Constraints, operators: microgp.operators.Operators, mu: int, lambda_: int, nu: int = None, tau: float = 2.0, strength: float = 0.5, max_age: Optional[int] = None, max_generations: Optional[int] = 42, stopping_conditions: Optional[list] = None)

This class manages the evolution, stores the genetic operators, the population, and the archive. You can set some evolution parameters (lambda, tau, nu, strength, mu) and a list of stopping conditions. A microgp.population.Population and a microgp.population.Archive objects are also initialized.

Parameters:
  • constraints (Constraints) – Constraints object that each individual managed by Darwin must have.
  • operators (Operators) – operators object that contains the set of GenOperators that will manipulate the individuals.
  • mu (int) – Population size.
  • lambda (int) – Number of operators to pick at each generation (except when the population is empty).
  • nu (int) – Number of initialization operators to pick when the population is empty. None if you want mu individuals.
  • tau (float) – Selection pressure. Default value: 2.0
  • strength (float) – Probability and strength of the mutation (to be passed to the mutation GenOperators).
  • max_age (int) – Maximum age that an individual in the population can have. None if you don’t want to filter individuals by age.
  • stopping_conditions

Examples:

  • Initialize a Darwin object:

    >>> mu = 10
    >>> nu = 20
    >>> strength = 0.2
    >>> lambda_ = 7
    >>> max_age = 10
    >>> darwin = ugp4.Darwin(
    >>>     constraints=library,
    >>>     operators=operators,
    >>>     mu=mu,
    >>>     nu=nu,
    >>>     lambda_=lambda_,
    >>>     strength=strength,
    >>>     max_age=max_age)
    
  • Evolve, print results (Population):

    >>> darwin.evolve()
    >>> logging.bare("This is the population:")
    >>> for individual in darwin.population:
    >>>     msg = 'Printing individual ' + individual.id
    >>>     ugp4.print_individual(individual, msg=msg, plot=True)
    >>>     ugp4.logging.bare(individual.fitness)
    
  • Print the Archive that contains the best eve individuals

    >>> logging.bare("These are the best ever individuals:")
    >>> ugp4.print_individual(darwin.archive)
    
do_generation() → None

Perform a generation of the evolution. Pick lambda (or nu) operators, clean the resulting set of individuals given by the operators, join it to population and keep the best mu individuals

evolve() → None

Evolve the population until at least one of the stopping conditions becomes True

filter_offspring(temporary_offspring: Optional[List[Optional[microgp.individual.Individual]]]) → Optional[List[Optional[microgp.individual.Individual]]]

Remove “None” elements and choose the best element in sublist recursively

Parameters:temporary_offspring – the list of individuals to just generated by the operator
Returns:List of valid individuals
get_best_unpacking(individuals: list) → Optional[microgp.individual.Individual]

Find the best value in the given list (recursive)

keep_at_most_mu() → None

Keep in the population at most mu individuals removing the worst

update_archive() → None

Insert in archive the best individuals (and remove the no more good enough individuals)

Population

microgp.population

class microgp.population.Population

This class contains the set of individuals composing the population and manages the selection, insertion, removal of the individuals based on the age or whether their phenotype is already in the population. A non-valid individual can’t be inserted.

Examples:

  • Add a set of individuals in the population
>>> darwin.population += set(list_of_individuals)
  • Add a single individual in the population
>>> darwin.population += set(individual_A)
>>> darwin.population += set(individual_B)
  • Remove a single individual from the population
>>> darwin.population -= set(individual_A)
  • Remove multiple individuals (set) from the population
>>> darwin.population = darwin.population - set(individual_A)
>>> selected_individual = darwin.tournament_selection(tau)
  • Retrieve the entire set of individual contained in the population
>>> population = darwin.population.individuals
filter_by_age(max_age: int = None) → None

Remove from the population the individuals that are too old (individual.age >= max_age)

static filter_clones() → None

Check whether or not there are individuals with the same (canonical) phenotype and then remove them

static grow_old(individuals: Set[microgp.individual.Individual]) → None

Increment the age of a set of individuals. Typically the set is {Population - Archive}

select(tau: float = 2) → microgp.individual.Individual

Select an individual from the population calling the tournament_selection(tau) method

tournament_selection(tau: float = 2) → microgp.individual.Individual

Run several tournaments among a few (floor(tau) or ceil(tau)) individuals and return the best one based on the fitness

Archive

microgp.archive

class microgp.archive.Archive

This class manages the set of individuals not dominated by all other individuals currently or previously contained in the microgp.darwin.Darwin._population.

Examples:

  • Try to insert an individual in the archive:
>>> self._archive += individual

The individual will be inserted only if it is not dominated by all individual already inside the archive. If it is not dominated then the individuals that just became dominated are removed from the archive.

Operators

microgp.operators

class microgp.operators.Operators

This class wraps all operators, manages statistics, and GenOperator selection. The selection is made on the basis of the arity and the success and failure statistics of the operator.

Examples:

  • Create and fill an Operators object to be passed to a Darwin object
>>> operators = ugp4.Operators()
>>> init_op1 = ugp4.GenOperator(ugp4.create_random_individual, 0)
>>> operators += init_op1
>>> mutation_op1 = ugp4.GenOperator(ugp4.remove_node_mutation, 1)
>>> operators += mutation_op1
>>> crossover_op1 = ugp4.GenOperator(ugp4.switch_proc_crossover, 2)
>>> operators += crossover_op1
>>> crossover_op2 = ugp4.GenOperator(ugp4.five_individuals_crossover, 5)
>>> operators += crossover_op2
  • Select k operators that has arity in the given range
>>> selected_operators = operators.select(max_arity=0, k=10)
>>> selected_operators = operators.select(min_arity=1, max_arity=2 k=20)
select(min_arity: int = 0, max_arity: int = None) → microgp.genoperator.GenOperator

Select a set of operators with arity in [min_arity, max_arity]

Parameters:
  • min_arity (int) – minimum arity of the operators that will be returned
  • max_arity (int) – maximum arity of the operators that will be returned
  • k (int) – number of genetic operators to return
Returns:

a valid genetic operator

GenOperator

microgp.genoperator

class microgp.genoperator.GenOperator(function: collections.abc.Callable, arity: int)

Wrapper of a method that implements the algorithm manipulating or building one or more individuals. This class will also manage (in the future versions) the statistics applied to the assigned method. The method wrapped in the GenOperator must have **kwargs in its parameters.

Examples:

  • Build three genetic operators passing the method and the arity
>>> init_op1 = ugp4.GenOperator(ugp4.create_random_individual, 0)
>>> mutation_op1 = ugp4.GenOperator(ugp4.remove_node_mutation, 1)
>>> crossover_op1 = ugp4.GenOperator(ugp4.switch_proc_crossover, 2)
>>> crossover_op2 = ugp4.GenOperator(ugp4.five_individuals_crossover, 5)
  • Call the method inside the genetic operator
>>> selected_crossover_genoperator(individual1, individual2)
>>> selected_mutation_genoperator(individual, strength=0.7, constraints=constraints))
>>> individuals = tuple(ind1, ind2, ind3, ind4, ind5)
>>> kwargs = {'param1': var1, 'param2': var2, 'param3': [a, b, c, d, e]}
>>> selected_crossover_5_individuals(*individuals, kwargs)