evol package

Submodules

evol.evolution module

Evolution objects in evol are objects that describe how the evolutionary algorithm will change members of a population. Evolution objects contain the same methods as population objects but because an evolution is separate from a population you can play around with them more easily.

class evol.evolution.Evolution[source]

Bases: object

Describes the process a Population goes through when evolving.

breed(parent_picker: Callable[[...], Sequence[evol.individual.Individual]], combiner: Callable, population_size: Optional[int] = None, name: Optional[str] = None, **kwargs) → evol.evolution.Evolution[source]

Add a breed step to the Evolution.

Create new individuals by combining existing individuals.

Parameters:
  • parent_picker – Function that selects parents.
  • combiner – Function that combines chromosomes into a new chromosome. Must be able to handle the number of chromosomes that the combiner returns.
  • population_size – Intended population size after breeding. If None, take the previous intended population size. Defaults to None.
  • name – Name of the breed step.
  • kwargs – Kwargs to pass to the parent_picker and combiner. Arguments are only passed to the functions if they accept them.
Returns:

self

callback(callback_function: Callable[[...], Any], every: int = 1, name: Optional[str] = None, **kwargs) → evol.evolution.Evolution[source]

Call a function as a step in this evolution.

This will call the provided function with the population as argument.

Note that you can raise evol.exceptions.StopEvolution from within the callback to stop further evolution.

Parameters:
  • callback_function – Function to call.
  • every – Only call the function once per every iterations. Defaults to 1; every iteration.
  • name – Name of the callback step.
Returns:

self

checkpoint(target: Optional[str] = None, method: str = 'pickle', name: Optional[str] = None, every: int = 1) → evol.evolution.Evolution[source]

Add a checkpoint step to the Evolution.

Parameters:
  • target – Directory to write checkpoint to. If None, the Serializer default target is taken, which can be provided upon initialisation. Defaults to None.
  • method – One of ‘pickle’ or ‘json’. When ‘json’, the chromosomes need to be json-serializable. Defaults to ‘pickle’.
  • name – Name of the map step.
  • every – Checkpoint once every ‘every’ iterations. Defaults to 1.
evaluate(lazy: bool = False, name: Optional[str] = None) → evol.evolution.Evolution[source]

Add an evaluation step to the Evolution.

This evaluates the fitness of all individuals. If lazy is True, the fitness is only evaluated when a fitness value is not yet known. In most situations adding an explicit evaluation step is not needed, as lazy evaluation is implicitly included in the steps that need it (most notably in the survive step).

Parameters:
  • lazy – If True, do no re-evaluate the fitness if the fitness is known.
  • name – Name of the evaluation step.
Returns:

This Evolution with an additional step.

filter(func: Callable[[...], bool], name: Optional[str] = None, **kwargs) → evol.evolution.Evolution[source]

Add a filter step to the Evolution.

This filters the individuals in the population using the provided function.

Parameters:
  • func – Function to filter the individuals in the population by.
  • name – Name of the filter step.
  • kwargs – Arguments to pass to the function.
Returns:

This Evolution with an additional step.

map(func: Callable[[...], evol.individual.Individual], name: Optional[str] = None, **kwargs) → evol.evolution.Evolution[source]

Add a map step to the Evolution.

This applies the provided function to each individual in the population, in place.

Parameters:
  • func – Function to apply to the individuals in the population.
  • name – Name of the map step.
  • kwargs – Arguments to pass to the function.
Returns:

This Evolution with an additional step.

mutate(mutate_function: Callable[[...], Any], probability: float = 1.0, elitist: bool = False, name: Optional[str] = None, **kwargs) → evol.evolution.Evolution[source]

Add a mutate step to the Evolution.

This mutates the chromosome of each individual.

Parameters:
  • mutate_function – Function that accepts a chromosome and returns a mutated chromosome.
  • probability – Probability that the individual mutates. The function is only applied in the given fraction of cases. Defaults to 1.0.
  • elitist – If True, do not mutate the current best individual(s). Note that this only applies to evaluated individuals. Any unevaluated individual will be treated as normal. Defaults to False.
  • name – Name of the mutate step.
  • kwargs – Kwargs to pass to the parent_picker and combiner. Arguments are only passed to the functions if they accept them.
Returns:

self

repeat(evolution: evol.evolution.Evolution, n: int = 1, name: Optional[str] = None, grouping_function: Optional[Callable] = None, **kwargs) → evol.evolution.Evolution[source]

Add an evolution as a step to this evolution.

This will add a step to the evolution that repeats another evolution several times. Optionally this step can be performed in groups.

Note: if your population uses multiple concurrent workers and you use grouping, any callbacks inside the evolution you apply here may not have the desired effect.

Parameters:
  • evolution – Evolution to apply.
  • n – Number of times to perform the evolution. Defaults to 1.
  • name – Name of the repeat step.
  • grouping_function – Optional function to use for grouping the population. You can find built-in grouping functions in evol.helpers.groups.
  • kwargs – Kwargs to pass to the grouping function, for example n_groups.
Returns:

self

survive(fraction: Optional[float] = None, n: Optional[int] = None, luck: bool = False, name: Optional[str] = None, evaluate: bool = True) → evol.evolution.Evolution[source]

Add a survive step to the Evolution.

This filters the individuals in the population according to fitness.

Parameters:
  • fraction – Fraction of the original population that survives. Defaults to None.
  • n – Number of individuals of the population that survive. Defaults to None.
  • luck – If True, individuals randomly survive (with replacement!) with chances proportional to their fitness. Defaults to False.
  • name – Name of the filter step.
  • evaluate – If True, add a lazy evaluate step before the survive step. Defaults to True.
Returns:

This Evolution with an additional step.

evol.individual module

Individual objects in evol are a wrapper around a chromosome. Internally we work with individuals because that allows us to separate the fitness calculation from the data structure. This saves a lot of CPU power.

class evol.individual.Individual(chromosome: Any, fitness: Optional[float] = None)[source]

Bases: object

Represents an individual in a population. The individual has a chromosome.

Parameters:
  • chromosome – The chromosome of the individual.
  • fitness – The fitness of the individual, or None. Defaults to None.
evaluate(eval_function: Callable[[...], float], lazy: bool = False)[source]

Evaluate the fitness of the individual.

Parameters:
  • eval_function – Function that reduces a chromosome to a fitness.
  • lazy – If True, do no re-evaluate the fitness if the fitness is known.
classmethod from_dict(data: dict) → evol.individual.Individual[source]

Load an Individual from a dictionary.

Parameters:data – Dictionary containing the keys ‘age’, ‘chromosome’, ‘fitness’ and ‘id’.
Returns:Individual
mutate(mutate_function: Callable[[...], Any], probability: float = 1.0, **kwargs)[source]

Mutate the chromosome of the individual.

Parameters:
  • mutate_function – Function that accepts a chromosome and returns a mutated chromosome.
  • probability – Probability that the individual mutates. The function is only applied in the given fraction of cases. Defaults to 1.0.
  • kwargs – Arguments to pass to the mutation function.
evol.individual.random() → x in the interval [0, 1).

evol.logger module

Loggers help keep track of the workings of your evolutionary algorithm. By default, each Population is initialized with a BaseLogger, which you can use by using the .log() method of the population. If you want more complex behaviour, you can supply another logger to the Population on initialisation.

class evol.logger.BaseLogger(target=None, stdout=False, fmt='%(asctime)s, %(message)s')[source]

Bases: object

The evol.BaseLogger is the most basic logger in evol. You can supply it to a population so that the population knows how to handle the .log() verb.

static check_population(population: evol.population.BasePopulation) → None[source]
log(population, **kwargs)[source]

The logger method of the Logger object determines what will be logged. :param population: evol.Population object :return: nothing, it merely logs to a file and perhaps stdout

class evol.logger.MultiLogger(file_individuals, file_population)[source]

Bases: object

The evol.Multilogger is a logger object that can handle writing to two files. It is here for demonstration purposes to show how you could customize the logging. The only thing that matters is that all logging is handled by the .log() call. So we are free to record to multiple files if we want as well. This is not per se best practice but it would work.

handle(ind_generator, dict_to_log)[source]

The handler method of the Logger object determines how it will be logged. In this case we print if there is no file and we append to a file otherwise.

log(population, **kwargs)[source]

The logger method of the Logger object determines what will be logged. :param population: population to log :return: generator of strings to be handled

class evol.logger.SummaryLogger(target=None, stdout=False, fmt='%(asctime)s, %(message)s')[source]

Bases: evol.logger.BaseLogger

The evol.SummaryLogger merely logs statistics per population and nothing else. You are still able to log to stdout as well.

log(population, **kwargs)[source]

The logger method of the Logger object determines what will be logged. :param population: evol.Population object :return: nothing, it merely logs to a file and perhaps stdout

evol.population module

Population objects in evol are a collection of chromosomes at some point in an evolutionary algorithm. You can apply evolutionary steps by directly calling methods on the population or by applying an evol.Evolution object.

class evol.population.BasePopulation(chromosomes: Iterable[Any], eval_function: Callable, checkpoint_target: Optional[str] = None, concurrent_workers: Optional[int] = 1, maximize: bool = True, generation: int = 0, intended_size: Optional[int] = None, serializer=None)[source]

Bases: object

breed(parent_picker: Callable[[...], Sequence[evol.individual.Individual]], combiner: Callable, population_size: Optional[int] = None, **kwargs) → evol.population.BasePopulation[source]

Create new individuals by combining existing individuals.

This increments the generation of the Population.

Parameters:
  • parent_picker – Function that selects parents from a collection of individuals.
  • combiner – Function that combines chromosomes into a new chromosome. Must be able to handle the number of chromosomes that the combiner returns.
  • population_size – Intended population size after breeding. If None, take the previous intended population size. Defaults to None.
  • kwargs – Kwargs to pass to the parent_picker and combiner. Arguments are only passed to the functions if they accept them.
Returns:

self

callback(callback_function: Callable[[...], None], **kwargs) → evol.population.BasePopulation[source]

Performs a callback function on the population. Can be used for custom logging/checkpointing. :param callback_function: Function that accepts the population as a first argument. :return:

checkpoint(target: Optional[str] = None, method: str = 'pickle') → evol.population.BasePopulation[source]

Checkpoint the population.

Parameters:
  • target – Directory to write checkpoint to. If None, the Serializer default target is taken, which can be provided upon initialisation. Defaults to None.
  • method – One of ‘pickle’ or ‘json’. When ‘json’, the chromosomes need to be json-serializable. Defaults to ‘pickle’.
Returns:

Population

chromosomes
classmethod combine(*populations, intended_size: Optional[int] = None, pool: Optional[multiprocess.pool.Pool] = None) → evol.population.BasePopulation[source]

Combine multiple island populations into a single population.

The resulting population is reduced to its intended size.

Parameters:
  • populations – Populations to combine.
  • intended_size – Intended size of the resulting population. Defaults to the sum of the intended sizes of the islands.
  • pool – Optionally provide a multiprocessing pool to be used by the population.
Returns:

Population

current_best
current_worst
evaluate(lazy: bool = False) → evol.population.BasePopulation[source]
evolve(evolution: Evolution, n: int = 1) → BasePopulation[source]

Evolve the population according to an Evolution.

Parameters:
  • evolution – Evolution to follow
  • n – Times to apply the evolution. Defaults to 1.
Returns:

Population

filter(func: Callable[[...], bool], **kwargs) → evol.population.BasePopulation[source]

Add a filter step to the Evolution.

Filters the individuals in the population using the provided function.

Parameters:
  • func – Function to filter the individuals in the population by, which returns a boolean when called on an individual.
  • kwargs – Arguments to pass to the function.
Returns:

self

classmethod generate(init_function: Callable[[], Any], eval_function: Callable[[...], float], size: int = 100, **kwargs) → evol.population.BasePopulation[source]

Generate a population from an initialisation function.

Parameters:
  • init_function – Function that returns a chromosome.
  • eval_function – Function that reduces a chromosome to a fitness.
  • size – Number of individuals to generate. Defaults to 100.
Returns:

BasePopulation

group(grouping_function: Callable[[...], List[List[int]]] = <function group_random>, **kwargs) → List[evol.population.BasePopulation][source]

Group a population into islands.

Divides the population into multiple island populations, each of which contains a subset of the original population. An individual from the original population may end up in multiple (>= 0) island populations.

Parameters:
  • grouping_function – Function that allocates individuals to the island populations. It will be passed a list of individuals plus the kwargs passed to this method, and must return a list of lists of integers, each sub-list representing an island and the integers representing the index of an individual in the list. Each island must contain at least one individual, and individual may be copied to multiple islands.
  • kwargs – Additional keyworded arguments are passed to the grouping function.
Returns:

List[Population]

is_evaluated
classmethod load(target: str, eval_function: Callable[[...], float], **kwargs) → evol.population.BasePopulation[source]

Load a population from a checkpoint.

Parameters:
  • target – Path to checkpoint directory or file.
  • eval_function – Function that reduces a chromosome to a fitness.
  • kwargs – Any argument the init method accepts.
Returns:

Population

map(func: Callable[[...], evol.individual.Individual], **kwargs) → evol.population.BasePopulation[source]

Apply the provided function to each individual in the population.

Parameters:
  • func – A function to apply to each individual in the population, which when called returns a modified individual.
  • kwargs – Arguments to pass to the function.
Returns:

self

mutate(mutate_function: Callable[[...], Any], probability: float = 1.0, elitist: bool = False, **kwargs) → evol.population.BasePopulation[source]

Mutate the chromosome of each individual.

Parameters:
  • mutate_function – Function that accepts a chromosome and returns a mutated chromosome.
  • probability – Probability that the individual mutates. The function is only applied in the given fraction of cases. Defaults to 1.0.
  • elitist – If True, do not mutate the current best individual(s). Note that this only applies to evaluated individuals. Any unevaluated individual will be treated as normal. Defaults to False.
  • kwargs – Arguments to pass to the mutation function.
Returns:

self

survive(fraction: Optional[float] = None, n: Optional[int] = None, luck: bool = False) → evol.population.BasePopulation[source]

Let part of the population survive.

Remove part of the population. If both fraction and n are specified, the minimum resulting population size is taken.

Parameters:
  • fraction – Fraction of the original population that survives. Defaults to None.
  • n – Number of individuals of the population that survive. Defaults to None.
  • luck – If True, individuals randomly survive (with replacement!) with chances proportional to their fitness. Defaults to False.
Returns:

self

class evol.population.Contest(competitors: Iterable[evol.individual.Individual])[source]

Bases: object

A single contest among a group of competitors.

This is encapsulated in an object so that scores for many sets of competitors can be evaluated concurrently without resorting to a dict or some similar madness to correlate score vectors with an ever-widening matrix of contests and competitors.

Parameters:competitors – Iterable of Individuals in this Contest.
assign_scores(scores: Sequence[float]) → None[source]
competitor_chromosomes
classmethod generate(individuals: Sequence[evol.individual.Individual], individuals_per_contest: int, contests_per_round: int) → List[evol.population.Contest][source]

Generate contests for a round of evaluations.

Parameters:
  • individuals – A sequence of competing Individuals.
  • individuals_per_contest – Number of Individuals participating in each Contest.
  • contests_per_round – Minimum number of contests each individual takes part in for each evaluation round. The actual number of contests per round is a multiple of individuals_per_contest.
Returns:

List of Contests

class evol.population.ContestPopulation(chromosomes: Iterable[T_co], eval_function: Callable[[...], Sequence[float]], maximize: bool = True, individuals_per_contest=2, contests_per_round=10, generation: int = 0, intended_size: Optional[int] = None, checkpoint_target: Optional[int] = None, serializer=None, concurrent_workers: Optional[int] = 1)[source]

Bases: evol.population.BasePopulation

Population which is evaluated through contests.

This variant of the Population is used when individuals cannot be evaluated on a one-by-one basis, but instead can only be compared to each other. This is typically the case for AI that performs some task (i.e. plays a game), but can be useful in many other cases.

For each round of evaluation, each individual participates in a given number of contests, in which a given number of individuals take part. The resulting scores of these contests are summed to form the fitness.

Since the fitness of an individual is dependent on the other individuals in the population, the fitness of all individuals is recalculated when new individuals are present, and the fitness of all individuals is reset when the population is modified (e.g. by calling survive, mutate etc).

Parameters:
  • chromosomes – Iterable of initial chromosomes of the Population.
  • eval_function – Function that reduces a chromosome to a fitness.
  • maximize – If True, fitness will be maximized, otherwise minimized. Defaults to True.
  • individuals_per_contest – Number of individuals that take part in each contest. The size of the population must be divisible by this number. Defaults to 2.
  • contests_per_round – Minimum number of contests each individual takes part in for each evaluation round. The actual number of contests per round is a multiple of individuals_per_contest. Defaults to 10.
  • generation – Generation of the Population. This is incremented after echo survive call. Defaults to 0.
  • intended_size – Intended size of the Population. The population will be replenished to this size by .breed(). Defaults to the number of chromosomes provided.
  • checkpoint_target – Target for the serializer of the Population. If a serializer is provided, this target is ignored. Defaults to None.
  • serializer – Serializer for the Population. If None, a new SimpleSerializer is created. Defaults to None.
  • concurrent_workers – If > 1, evaluate individuals in {concurrent_workers} separate processes. If None, concurrent_workers is set to n_cpus. Defaults to 1.
evaluate(lazy: bool = False, contests_per_round: Optional[int] = None, individuals_per_contest: Optional[int] = None) → evol.population.ContestPopulation[source]

Evaluate the individuals in the population.

This evaluates the fitness of all individuals. For each round of evaluation, each individual participates in a given number of contests, in which a given number of individuals take part. The resulting scores of these contests are summed to form the fitness. This means that the score of the individual is influenced by other chromosomes in the population.

Note that in the ContestPopulation two settings are passed at initialisation which affect how we are evaluating individuals: contests_per_round and individuals_per_contest. You may overwrite them here if you wish.

If lazy is True, the fitness is only evaluated when a fitness value is not yet known for all individuals. In most situations adding an explicit evaluation step is not needed, as lazy evaluation is implicitly included in the operations that need it (most notably in the survive operation).

Parameters:
  • lazy – If True, do no re-evaluate the fitness if the fitness is known.
  • contests_per_round – If set, overwrites the population setting for the

number of contests there will be every round. :param individuals_per_contest: If set, overwrites the population setting for number of individuals to have in a contest during the evaluation. :return: self

filter(func: Callable[[...], bool], **kwargs) → evol.population.ContestPopulation[source]

Add a filter step to the Evolution.

Filters the individuals in the population using the provided function. Resets the fitness of all individuals.

Parameters:
  • func – Function to filter the individuals in the population by, which returns a boolean when called on an individual.
  • kwargs – Arguments to pass to the function.
Returns:

self

map(func: Callable[[...], evol.individual.Individual], **kwargs) → evol.population.ContestPopulation[source]

Apply the provided function to each individual in the population.

Resets the fitness of all individuals.

Parameters:
  • func – A function to apply to each individual in the population, which when called returns a modified individual.
  • kwargs – Arguments to pass to the function.
Returns:

self

reset_fitness()[source]

Reset the fitness of all individuals.

survive(fraction: Optional[float] = None, n: Optional[int] = None, luck: bool = False) → evol.population.ContestPopulation[source]

Let part of the population survive.

Remove part of the population. If both fraction and n are specified, the minimum resulting population size is taken. Resets the fitness of all individuals.

Parameters:
  • fraction – Fraction of the original population that survives. Defaults to None.
  • n – Number of individuals of the population that survive. Defaults to None.
  • luck – If True, individuals randomly survive (with replacement!) with chances proportional to their fitness. Defaults to False.
Returns:

self

class evol.population.Population(chromosomes: Iterable[T_co], eval_function: Callable[[...], float], maximize: bool = True, generation: int = 0, intended_size: Optional[int] = None, checkpoint_target: Optional[str] = None, serializer=None, concurrent_workers: Optional[int] = 1)[source]

Bases: evol.population.BasePopulation

Population of Individuals

Parameters:
  • chromosomes – Iterable of initial chromosomes of the Population.
  • eval_function – Function that reduces a chromosome to a fitness.
  • maximize – If True, fitness will be maximized, otherwise minimized. Defaults to True.
  • generation – Generation of the Population. This is incremented after each breed call. Defaults to 0.
  • intended_size – Intended size of the Population. The population will be replenished to this size by .breed(). Defaults to the number of chromosomes provided.
  • checkpoint_target – Target for the serializer of the Population. If a serializer is provided, this target is ignored. Defaults to None.
  • serializer – Serializer for the Population. If None, a new SimpleSerializer is created. Defaults to None.
  • concurrent_workers – If > 1, evaluate individuals in {concurrent_workers} separate processes. If None, concurrent_workers is set to n_cpus. Defaults to 1.
evaluate(lazy: bool = False) → evol.population.Population[source]

Evaluate the individuals in the population.

This evaluates the fitness of all individuals. If lazy is True, the fitness is only evaluated when a fitness value is not yet known. In most situations adding an explicit evaluation step is not needed, as lazy evaluation is implicitly included in the operations that need it (most notably in the survive operation).

Parameters:lazy – If True, do no re-evaluate the fitness if the fitness is known.
Returns:self

evol.serialization module

Serializers help store (checkpoint) the state of your population during or after running your evolutionary algorithm. By default, each Population is initialized with a SimpleSerializer, which you can use to store the individuals in your population in pickle or json format using the .checkpoint() method of the population. Currently no other serializers are available.

class evol.serialization.SimpleSerializer(target: Optional[str] = None)[source]

Bases: object

The SimpleSerializer handles serialization to and from pickle and json.

Parameters:target – Default location (directory) to store checkpoint. This may be overridden in the checkpoint method. Defaults to None.
checkpoint(individuals: List[evol.individual.Individual], target: Optional[str] = None, method: str = 'pickle') → None[source]

Checkpoint a list of individuals.

Parameters:
  • individuals – List of individuals to checkpoint.
  • target – Directory to write checkpoint to. If None, the Serializer default target is taken, which can be provided upon initialisation. Defaults to None.
  • method – One of ‘pickle’ or ‘json’. When ‘json’, the chromosomes need to be json-serializable. Defaults to ‘pickle’.
load(target: Optional[str] = None) → List[evol.individual.Individual][source]

Load a checkpoint.

If path is a file, load that file. If it is a directory, load the most recent checkpoint. The checkpoint file must end with a ‘.json’ or ‘.pkl’ extension.

Parameters:target – Path to checkpoint directory or file.
Returns:List of individuals from checkpoint.

evol.step module

class evol.step.BreedStep(name: Optional[str], **kwargs)[source]

Bases: evol.step.EvolutionStep

apply(population: evol.population.BasePopulation) → evol.population.BasePopulation[source]
class evol.step.CallbackStep(name, every: int = 1, **kwargs)[source]

Bases: evol.step.EvolutionStep

apply(population: evol.population.BasePopulation) → evol.population.BasePopulation[source]
class evol.step.CheckpointStep(name, every=1, **kwargs)[source]

Bases: evol.step.EvolutionStep

apply(population: evol.population.BasePopulation) → evol.population.BasePopulation[source]
class evol.step.EvaluationStep(name: Optional[str], **kwargs)[source]

Bases: evol.step.EvolutionStep

apply(population: evol.population.BasePopulation) → evol.population.BasePopulation[source]
class evol.step.EvolutionStep(name: Optional[str], **kwargs)[source]

Bases: object

apply(population: evol.population.BasePopulation) → evol.population.BasePopulation[source]
class evol.step.FilterStep(name: Optional[str], **kwargs)[source]

Bases: evol.step.EvolutionStep

apply(population: evol.population.BasePopulation) → evol.population.BasePopulation[source]
class evol.step.MapStep(name: Optional[str], **kwargs)[source]

Bases: evol.step.EvolutionStep

apply(population: evol.population.BasePopulation) → evol.population.BasePopulation[source]
class evol.step.MutateStep(name: Optional[str], **kwargs)[source]

Bases: evol.step.EvolutionStep

apply(population: evol.population.BasePopulation) → evol.population.BasePopulation[source]
class evol.step.RepeatStep(name: str, evolution: Evolution, n: int, grouping_function: Optional[Callable] = None, **kwargs)[source]

Bases: evol.step.EvolutionStep

apply(population: evol.population.BasePopulation) → evol.population.BasePopulation[source]
class evol.step.SurviveStep(name: Optional[str], **kwargs)[source]

Bases: evol.step.EvolutionStep

apply(population: evol.population.BasePopulation) → evol.population.BasePopulation[source]

Module contents

![Imgur](https://i.imgur.com/7MHcIq1.png)

Evol is clear dsl for composable evolutionary algorithms that optimised for joy.

Evol is a library that helps you make evolutionary algorithms. The goal is to have a library that is fun and clear to use, but not fast.

If you’re looking at the library for the first time we recommend that you first take a look at the examples in the /examples folder on github. It is usually a better starting point to get started.

Any details can be discovered on the docs. We hope that this library makes it fun to write heuristics again.

The Gist

The main idea is that you should be able to define a complex algorithm in a composable way. To explain what we mean by this: let’s consider two evolutionary algorithms for travelling salesman problems.

The first approach takes a collections of solutions and applies:

  1. a survival where only the top 50% solutions survive
  2. the population reproduces using a crossover of genes
  3. certain members mutate
  4. repeat this, maybe 1000 times or more!

<img src=”https://i.imgur.com/is9g07u.png” alt=”Drawing” style=”width: 100%;”/>

We can also think of another approach:

  1. pick the best solution of the population
  2. make random changes to this parent and generate new solutions
  3. repeat this, maybe 1000 times or more!

<img src=”https://i.imgur.com/JRSWbTd.png” alt=”Drawing” style=”width: 100%;”/>

One could even combine the two algorithms into a new one:

  1. run algorithm 1 50 times
  2. run algorithm 2 10 times
  3. repeat this, maybe 1000 times or more!

<img src=”https://i.imgur.com/SZTBWX2.png” alt=”Drawing” style=”width: 100%;”/>

You might notice that many parts of these algorithms are similar and it is the goal of this library is to automate these parts. In fact, you can expect the code for these algorithms to look something like this.

A speudo-example of what is decribed about looks a bit like this:

import random from evol import Population, Evolution

population = Population(init_func=init_func, eval_func=eval_func, size=100)

def pick_n_parents(population, num_parents):
return [random.choice(population) for i in range(num_parents)]
def crossover(*parents):
def random_copy(parent):
evo1 = (Evolution(name=”first_algorithm”)

.survive(fraction=0.5) .breed(parentpicker=pick_n_parents,

combiner=combiner, num_parents=2, n_max=100)

.mutate(lambda x: add_noise(x, 0.1)))

evo2 = (Evolution(name=”second_algorithm”)

.survive(n=1) .breed(parentpicker=pick_n_parents,

combiner=random_copy, num_parents=1, n_max=100))
for i in range(1001):
population.evolve(evo1, n=50).evolve(evo2, n=10)

Getting Started

The best place to get started is the /examples folder on github. This folder contains self contained examples that work out of the box.

Contributing Guide

### Local development

Python can help you. Don’t reinstall all the time, rather use a virtulenv that has a link to the code.

python setup.py develop

When you submit a pull request it will be tested in travis. Once the build is green the review can start. Please try to keep your branch up to date to ensure you’re not missing any tests. Larger commits need to be discussed in github before we can accept them.

### Generating New Documentation

Updating documentation is currently a manual step. From the docs folder:

pdoc –html –overwrite evol cp -rf evol/* . rm -rf evol

If you want to confirm that it works you can open the index.html file.