Recombination to create a new genotype by swapping chromosomes

109 Views Asked by At

The Jenetics documentation specifies that recombination creates a new chromosome by combining parts of two (or more) parent chromosomes. Based on this, the library also provides concrete implementations for various crossover techniques. Is there an out-of-the-box feature that I can use for the recombination of two (or more) genotypes within the population (i.e. swapping chromosomes) leaving the genes of each chromosome untouched?

Consider an example wherein the initial population consists of 2 genotypes that is comprised of 2 chromosomes each. And I need a crossover between the 2 individuals such that only the chromosomes are exchanged leaving the genes intact.

Illustration of the example

The same example in code is shown below:

    // Create the initial population
    final List<Genotype<CharacterGene>> initialPopulation = List.of( Genotype.of(
            CharacterChromosome.of( "world" ),
            CharacterChromosome.of( "fuzzy" )
    ), Genotype.of(
            CharacterChromosome.of( "stack" ),
            CharacterChromosome.of( "hello" )
    ) );

    // Configure the Engine
    final Engine<CharacterGene, Vec<int[]>> engine =
    Engine.builder( CrossoverExercise::eval, factory ) //
            .populationSize( 2 ) //
            .offspringFraction( 1 ) //
            .alterers( new CustomWordCrossover() ) //
            .build();

    final Phenotype<CharacterGene, Vec<int[]>> result = engine.stream( initialPopulation ) //
    .limit( 10 ) //
    .collect( EvolutionResult.toBestPhenotype() );

Where the CustomWordCrossover class extends the Alterer interface to randomly swap chromosomes between the genotypes.

public class CustomWordCrossover implements Alterer<CharacterGene, Vec<int[]>> {

    @Override
    public AltererResult<CharacterGene, Vec<int[]>> alter( final Seq<Phenotype<CharacterGene, Vec<int[]>>> population,
        final long generation ) {

        final ISeq<Phenotype<CharacterGene, Integer>> newPopulation = swapWords( population, generation );
        return AltererResult.of( newPopulation );

    }

    private ISeq<Phenotype<CharacterGene, Integer>> swapWords( final Seq<Phenotype<CharacterGene, Integer>> population,
        final long generation ) {
        final Phenotype<CharacterGene, Integer> p0 = population.get( 0 );
        final Phenotype<CharacterGene, Integer> p1 = population.get( 1 );

        return ISeq.of(
            Phenotype.of( Genotype.of( p0.getGenotype().get( 1 ), p1.getGenotype().get( 0 ) ), generation ),
            Phenotype.of( Genotype.of( p1.getGenotype().get( 1 ), p0.getGenotype().get( 0 ) ), generation )
        );
    }

}

Is there a better approach to achieve this? A build-in library function perhaps? I could not find anything in the documentation so far.

1

There are 1 best solutions below

2
On

There is no build-in library crossover operation for your specific use case. The reason for this is, that the different chromosomes within one genotype/phenotype are considered to have different constraints. That means, that, in general, two chromosomes with different genotype indexes are not interchangeable.

Genotype<DoubleGene> gt = Genotype.of(
    DoubleChromosome.of(DoubleRange.of(0, 10), 4),
    DoubleChromosome.of(DoubleRange.of(67, 323), 9)
);

In the example above, the two chromosomes have different ranges and different lengths. So it is not possible to swap it, without destroying the encoding. Your specific encoding, on the other hand, allows swapping two chromosomes within a genotype. Your encoding will not be destroyed.

Short answer: No library alterer for this specific case. And your implementation looks fine.