Quick Start

Introduction

Let’s assume we are trying to solve a problem where we want to generate N integers where their values are equal to their index.

For instance, for N = 5, we would want to generate the following list of integers:

[0, 1, 2, 3, 4]

We will solve this problem by generating an entire population of random lists of integers and evolving them towards our expected solution.

So let’s start by defining the constraints of our problem:

final int numEntries = 10; (1)
final int minValue = 0; (2)
final int maxValue = 20; (3)
1 This represent the size N of our list of Integers
2 Minimum value an integer can take
3 Maximum value an integer can take

Dependencies

Let’s add the repository:

<repositories>
    <repository>
        <id>gitlab-maven</id>
        <url>https://gitlab.com/api/v4/projects/13863766/packages/maven</url>
    </repository>
</repositories>

Then the dependency on the core module:

<dependency>
    <groupId>net.bmahe.genetics4j</groupId>
    <artifactId>core</artifactId>
    <version>4.0</version>
</dependency>

Problem definition

And now, let’s define what we want to solve. One of the features of Genetics4j is that it cleanly separates What we want to achieve from the How we will solve it. It enables us to tweak the operators' implementation or explore different contexts, which facilitate benchmarks and exploration.

The definition of the problem is done through a fluent set of classes:

final Builder<Integer> eaConfigurationBuilder = new EAConfiguration.Builder<>();
eaConfigurationBuilder.chromosomeSpecs(IntChromosomeSpec.of(numEntries, minValue, maxValue))
                .parentSelectionPolicy(Tournament.of(5))
                .combinationPolicy(MultiPointCrossover.of(2))
                .mutationPolicies(RandomMutation.of(0.15))
                .fitness((genoType) -> {
                        final IntChromosome intChromosome = genoType.getChromosome(0, IntChromosome.class);
                        int correctCount = 0;
                        for (int i = 0; i < intChromosome.getNumAlleles(); i++) {
                                if (i == intChromosome.getAllele(i)) {
                                        correctCount++;
                                }
                        }

                        return correctCount;
                })
                .termination(or(Terminations.ofFitnessAtLeast(numEntries), Terminations.ofMaxGeneration(50)));
final EAConfiguration<Integer> eaConfiguration = eaConfigurationBuilder.build();

Execution specification

We can next focus on the execution method through the configuration of the Evolutionary Algorithm Execution Context, which includes elements such as:

  • Population size

  • The different handlers for selection, mutation and combination

  • The different handlers for chromosome generation

  • Definition of some listeners

  • Configuration of the instance of java.util.Random to be used throughout the system

final EAExecutionContext<Integer> eaExecutionContext = EAExecutionContexts.<Integer>forScalarFitness()
                .populationSize(100)
                .addEvolutionListeners(EvolutionListeners.ofLogTopN(logger, 3))
                .build();

Note: We have a set of factory methods to generate a EAExecutionContext. These factory methods are quite helpful as they will take care of some extra configuration. For instance, knowing the fitness value will be a scalar number enables the factory method to pre-configure some additional operators and simplify our code. See EAExecutionContexts API documentation.

Evolution

As we have defined What we want to achieve as well as How we want to do it, we can instantiate a Evolutionary Algorithm System which will be in charge of doing the actual evolution:

final EASystem<Integer> eaSystem = EASystemFactory.from(eaConfiguration, eaExecutionContext);

Finally, we can run and observe the evolution of our system and what is the best solution it finds:

final EvolutionResult<Integer> evolutionResult = eaSystem.evolve();
logger.info("Best genotype: {}", evolutionResult.bestGenotype());
logger.info("  with fitness: {}", evolutionResult.bestFitness());
logger.info("  at generation: {}", evolutionResult.generation());

And here is an example of the output of such execution:

20:59:24.015 INFO  n.b.g.c.EASystem - Starting evolution
20:59:24.020 INFO  n.b.g.c.EASystem - Generating initial population of 100 individuals
20:59:24.022 INFO  n.b.g.c.EASystem - Generating 100 individuals
20:59:24.025 INFO  n.b.g.c.EASystem - Evaluating initial population
20:59:24.032 INFO  n.b.g.c.EASystem - Going through evolution of generation 0
20:59:24.032 INFO  n.b.g.s.QuickStart - Top 3 individuals at generation 0
20:59:24.045 INFO  n.b.g.s.QuickStart -   Fitness: 3 -> Genotype [chromosomes=[IntChromosome [size=10, minValue=0, maxValue=20, values=[0, 4, 15, 3, 13, 5, 15, 0, 10, 3]]]]
20:59:24.045 INFO  n.b.g.s.QuickStart -   Fitness: 3 -> Genotype [chromosomes=[IntChromosome [size=10, minValue=0, maxValue=20, values=[12, 4, 2, 12, 9, 9, 6, 4, 15, 9]]]]
20:59:24.045 INFO  n.b.g.s.QuickStart -   Fitness: 3 -> Genotype [chromosomes=[IntChromosome [size=10, minValue=0, maxValue=20, values=[0, 12, 4, 15, 14, 1, 6, 1, 8, 2]]]]
20:59:24.045 INFO  n.b.g.c.EASystem - Selecting 200 parents as we expect to generate 100 children
20:59:24.046 INFO  n.b.g.c.EASystem - Combining parents into offsprings
20:59:24.057 INFO  n.b.g.c.EASystem - Generated 200 offsprings
20:59:24.057 INFO  n.b.g.c.EASystem - Mutating children
20:59:24.058 INFO  n.b.g.c.EASystem - Evaluating offsprings
20:59:24.059 INFO  n.b.g.c.EASystem - Executing replacement strategy
20:59:24.060 INFO  n.b.g.c.r.ElitismImpl - Selecting 95 offsprings
20:59:24.060 INFO  n.b.g.c.r.ElitismImpl - Selecting 5 survivors
20:59:24.060 INFO  n.b.g.c.EASystem - Going through evolution of generation 1
20:59:24.060 INFO  n.b.g.s.QuickStart - Top 3 individuals at generation 1
20:59:24.061 INFO  n.b.g.s.QuickStart -   Fitness: 4 -> Genotype [chromosomes=[IntChromosome [size=10, minValue=0, maxValue=20, values=[0, 4, 2, 12, 9, 9, 6, 4, 15, 9]]]]
20:59:24.061 INFO  n.b.g.s.QuickStart -   Fitness: 4 -> Genotype [chromosomes=[IntChromosome [size=10, minValue=0, maxValue=20, values=[0, 4, 15, 3, 13, 5, 15, 0, 12, 9]]]]
20:59:24.061 INFO  n.b.g.s.QuickStart -   Fitness: 4 -> Genotype [chromosomes=[IntChromosome [size=10, minValue=0, maxValue=20, values=[0, 4, 2, 12, 9, 9, 6, 4, 15, 9]]]]
20:59:24.061 INFO  n.b.g.c.EASystem - Selecting 200 parents as we expect to generate 100 children
20:59:24.062 INFO  n.b.g.c.EASystem - Combining parents into offsprings
20:59:24.067 INFO  n.b.g.c.EASystem - Generated 200 offsprings
20:59:24.067 INFO  n.b.g.c.EASystem - Mutating children
20:59:24.068 INFO  n.b.g.c.EASystem - Evaluating offsprings
20:59:24.068 INFO  n.b.g.c.EASystem - Executing replacement strategy
20:59:24.068 INFO  n.b.g.c.r.ElitismImpl - Selecting 95 offsprings
20:59:24.068 INFO  n.b.g.c.r.ElitismImpl - Selecting 5 survivors
20:59:24.068 INFO  n.b.g.c.EASystem - Going through evolution of generation 2
20:59:24.068 INFO  n.b.g.s.QuickStart - Top 3 individuals at generation 2
20:59:24.069 INFO  n.b.g.s.QuickStart -   Fitness: 5 -> Genotype [chromosomes=[IntChromosome [size=10, minValue=0, maxValue=20, values=[0, 4, 15, 3, 13, 5, 6, 0, 12, 9]]]]
20:59:24.069 INFO  n.b.g.s.QuickStart -   Fitness: 5 -> Genotype [chromosomes=[IntChromosome [size=10, minValue=0, maxValue=20, values=[0, 4, 15, 3, 13, 5, 6, 4, 15, 9]]]]
20:59:24.069 INFO  n.b.g.s.QuickStart -   Fitness: 5 -> Genotype [chromosomes=[IntChromosome [size=10, minValue=0, maxValue=20, values=[0, 4, 15, 3, 13, 5, 6, 4, 15, 9]]]]
20:59:24.069 INFO  n.b.g.c.EASystem - Selecting 200 parents as we expect to generate 100 children
20:59:24.069 INFO  n.b.g.c.EASystem - Combining parents into offsprings
20:59:24.073 INFO  n.b.g.c.EASystem - Generated 200 offsprings
20:59:24.073 INFO  n.b.g.c.EASystem - Mutating children
20:59:24.073 INFO  n.b.g.c.EASystem - Evaluating offsprings
20:59:24.074 INFO  n.b.g.c.EASystem - Executing replacement strategy
20:59:24.074 INFO  n.b.g.c.r.ElitismImpl - Selecting 95 offsprings
20:59:24.074 INFO  n.b.g.c.r.ElitismImpl - Selecting 5 survivors
20:59:24.074 INFO  n.b.g.c.EASystem - Going through evolution of generation 3
20:59:24.074 INFO  n.b.g.s.QuickStart - Top 3 individuals at generation 3
20:59:24.074 INFO  n.b.g.s.QuickStart -   Fitness: 7 -> Genotype [chromosomes=[IntChromosome [size=10, minValue=0, maxValue=20, values=[0, 1, 8, 3, 4, 10, 6, 1, 8, 9]]]]
20:59:24.075 INFO  n.b.g.s.QuickStart -   Fitness: 6 -> Genotype [chromosomes=[IntChromosome [size=10, minValue=0, maxValue=20, values=[0, 4, 2, 3, 13, 5, 6, 0, 12, 9]]]]
20:59:24.075 INFO  n.b.g.s.QuickStart -   Fitness: 6 -> Genotype [chromosomes=[IntChromosome [size=10, minValue=0, maxValue=20, values=[0, 4, 2, 3, 13, 5, 6, 0, 12, 9]]]]
20:59:24.075 INFO  n.b.g.c.EASystem - Selecting 200 parents as we expect to generate 100 children
20:59:24.075 INFO  n.b.g.c.EASystem - Combining parents into offsprings
20:59:24.078 INFO  n.b.g.c.EASystem - Generated 200 offsprings
20:59:24.078 INFO  n.b.g.c.EASystem - Mutating children
20:59:24.079 INFO  n.b.g.c.EASystem - Evaluating offsprings
20:59:24.079 INFO  n.b.g.c.EASystem - Executing replacement strategy
20:59:24.079 INFO  n.b.g.c.r.ElitismImpl - Selecting 95 offsprings
20:59:24.079 INFO  n.b.g.c.r.ElitismImpl - Selecting 5 survivors
20:59:24.080 INFO  n.b.g.c.EASystem - Going through evolution of generation 4
20:59:24.080 INFO  n.b.g.s.QuickStart - Top 3 individuals at generation 4
20:59:24.080 INFO  n.b.g.s.QuickStart -   Fitness: 8 -> Genotype [chromosomes=[IntChromosome [size=10, minValue=0, maxValue=20, values=[0, 1, 8, 3, 4, 5, 6, 1, 8, 9]]]]
20:59:24.080 INFO  n.b.g.s.QuickStart -   Fitness: 8 -> Genotype [chromosomes=[IntChromosome [size=10, minValue=0, maxValue=20, values=[0, 1, 8, 3, 4, 5, 6, 1, 8, 9]]]]
20:59:24.080 INFO  n.b.g.s.QuickStart -   Fitness: 7 -> Genotype [chromosomes=[IntChromosome [size=10, minValue=0, maxValue=20, values=[0, 19, 2, 3, 4, 5, 6, 4, 15, 9]]]]
20:59:24.080 INFO  n.b.g.c.EASystem - Selecting 200 parents as we expect to generate 100 children
20:59:24.080 INFO  n.b.g.c.EASystem - Combining parents into offsprings
20:59:24.083 INFO  n.b.g.c.EASystem - Generated 200 offsprings
20:59:24.083 INFO  n.b.g.c.EASystem - Mutating children
20:59:24.083 INFO  n.b.g.c.EASystem - Evaluating offsprings
20:59:24.084 INFO  n.b.g.c.EASystem - Executing replacement strategy
20:59:24.084 INFO  n.b.g.c.r.ElitismImpl - Selecting 95 offsprings
20:59:24.084 INFO  n.b.g.c.r.ElitismImpl - Selecting 5 survivors
20:59:24.084 INFO  n.b.g.c.EASystem - Going through evolution of generation 5
20:59:24.084 INFO  n.b.g.s.QuickStart - Top 3 individuals at generation 5
20:59:24.084 INFO  n.b.g.s.QuickStart -   Fitness: 9 -> Genotype [chromosomes=[IntChromosome [size=10, minValue=0, maxValue=20, values=[0, 1, 2, 3, 4, 5, 6, 1, 8, 9]]]]
20:59:24.085 INFO  n.b.g.s.QuickStart -   Fitness: 8 -> Genotype [chromosomes=[IntChromosome [size=10, minValue=0, maxValue=20, values=[0, 1, 9, 3, 4, 5, 6, 1, 8, 9]]]]
20:59:24.085 INFO  n.b.g.s.QuickStart -   Fitness: 8 -> Genotype [chromosomes=[IntChromosome [size=10, minValue=0, maxValue=20, values=[0, 1, 2, 3, 4, 4, 6, 1, 8, 9]]]]
20:59:24.085 INFO  n.b.g.c.EASystem - Selecting 200 parents as we expect to generate 100 children
20:59:24.086 INFO  n.b.g.c.EASystem - Combining parents into offsprings
20:59:24.090 INFO  n.b.g.c.EASystem - Generated 200 offsprings
20:59:24.090 INFO  n.b.g.c.EASystem - Mutating children
20:59:24.091 INFO  n.b.g.c.EASystem - Evaluating offsprings
20:59:24.091 INFO  n.b.g.c.EASystem - Executing replacement strategy
20:59:24.091 INFO  n.b.g.c.r.ElitismImpl - Selecting 95 offsprings
20:59:24.091 INFO  n.b.g.c.r.ElitismImpl - Selecting 5 survivors
20:59:24.091 INFO  n.b.g.c.EASystem - Going through evolution of generation 6
20:59:24.092 INFO  n.b.g.s.QuickStart - Top 3 individuals at generation 6
20:59:24.092 INFO  n.b.g.s.QuickStart -   Fitness: 9 -> Genotype [chromosomes=[IntChromosome [size=10, minValue=0, maxValue=20, values=[0, 1, 2, 3, 4, 5, 6, 4, 8, 9]]]]
20:59:24.092 INFO  n.b.g.s.QuickStart -   Fitness: 9 -> Genotype [chromosomes=[IntChromosome [size=10, minValue=0, maxValue=20, values=[0, 1, 2, 3, 4, 5, 6, 1, 8, 9]]]]
20:59:24.092 INFO  n.b.g.s.QuickStart -   Fitness: 9 -> Genotype [chromosomes=[IntChromosome [size=10, minValue=0, maxValue=20, values=[0, 1, 2, 3, 4, 5, 6, 1, 8, 9]]]]
20:59:24.092 INFO  n.b.g.c.EASystem - Selecting 200 parents as we expect to generate 100 children
20:59:24.092 INFO  n.b.g.c.EASystem - Combining parents into offsprings
20:59:24.095 INFO  n.b.g.c.EASystem - Generated 200 offsprings
20:59:24.095 INFO  n.b.g.c.EASystem - Mutating children
20:59:24.095 INFO  n.b.g.c.EASystem - Evaluating offsprings
20:59:24.096 INFO  n.b.g.c.EASystem - Executing replacement strategy
20:59:24.096 INFO  n.b.g.c.r.ElitismImpl - Selecting 95 offsprings
20:59:24.096 INFO  n.b.g.c.r.ElitismImpl - Selecting 5 survivors
20:59:24.096 INFO  n.b.g.c.EASystem - Going through evolution of generation 7
20:59:24.096 INFO  n.b.g.s.QuickStart - Top 3 individuals at generation 7
20:59:24.096 INFO  n.b.g.s.QuickStart -   Fitness: 9 -> Genotype [chromosomes=[IntChromosome [size=10, minValue=0, maxValue=20, values=[0, 1, 2, 3, 4, 5, 6, 1, 8, 9]]]]
20:59:24.096 INFO  n.b.g.s.QuickStart -   Fitness: 9 -> Genotype [chromosomes=[IntChromosome [size=10, minValue=0, maxValue=20, values=[0, 1, 2, 3, 4, 5, 6, 4, 8, 9]]]]
20:59:24.097 INFO  n.b.g.s.QuickStart -   Fitness: 9 -> Genotype [chromosomes=[IntChromosome [size=10, minValue=0, maxValue=20, values=[0, 1, 2, 3, 4, 5, 6, 4, 8, 9]]]]
20:59:24.097 INFO  n.b.g.c.EASystem - Selecting 200 parents as we expect to generate 100 children
20:59:24.097 INFO  n.b.g.c.EASystem - Combining parents into offsprings
20:59:24.099 INFO  n.b.g.c.EASystem - Generated 200 offsprings
20:59:24.099 INFO  n.b.g.c.EASystem - Mutating children
20:59:24.099 INFO  n.b.g.c.EASystem - Evaluating offsprings
20:59:24.099 INFO  n.b.g.c.EASystem - Executing replacement strategy
20:59:24.099 INFO  n.b.g.c.r.ElitismImpl - Selecting 95 offsprings
20:59:24.100 INFO  n.b.g.c.r.ElitismImpl - Selecting 5 survivors
20:59:24.100 INFO  n.b.g.c.EASystem - Evolution has terminated
20:59:24.100 INFO  n.b.g.s.QuickStart - Top 3 individuals at generation 8
20:59:24.100 INFO  n.b.g.s.QuickStart -   Fitness: 10 -> Genotype [chromosomes=[IntChromosome [size=10, minValue=0, maxValue=20, values=[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]]]]
20:59:24.100 INFO  n.b.g.s.QuickStart -   Fitness: 10 -> Genotype [chromosomes=[IntChromosome [size=10, minValue=0, maxValue=20, values=[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]]]]
20:59:24.100 INFO  n.b.g.s.QuickStart -   Fitness: 10 -> Genotype [chromosomes=[IntChromosome [size=10, minValue=0, maxValue=20, values=[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]]]]
20:59:24.103 INFO  n.b.g.s.QuickStart - Best genotype: Genotype [chromosomes=[IntChromosome [size=10, minValue=0, maxValue=20, values=[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]]]]
20:59:24.104 INFO  n.b.g.s.QuickStart -   with fitness: 10
20:59:24.104 INFO  n.b.g.s.QuickStart -   at generation: 8

We can observe the top evolution of the top 3 solutions at each generation and how their fitnesses progressively increased, until a solution was found at the 8th generation.