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.
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.