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