add crossGenomes implementation

This commit is contained in:
Michael Peters 2024-08-27 22:04:41 -07:00
parent 566759e781
commit 465ac4b9dd

View File

@ -382,11 +382,11 @@ export function chooseSurvivors(population: Population, fitness: Map<Genome, num
return survivors;
}
interface BreedingConfig {
interface MateChoiceConfig {
asexual_rate: number;
interspecies_rate: number;
}
export function chooseMate(genome: Genome, population: Population, config: BreedingConfig) {
export function chooseMate(genome: Genome, population: Population, config: MateChoiceConfig) {
const { asexual_rate, interspecies_rate } = config;
if (Math.random() < asexual_rate) return genome;
@ -421,12 +421,46 @@ export function chooseMate(genome: Genome, population: Population, config: Breed
// TODO: function crossGenomes(mom: Genome, dad: Genome, fitness: Map<Genome, number>) { ... }
interface CrossConfig {
reenable_rate: number;
reenable_rate: number;
}
export function crossGenomes(mom: Genome, dad: Genome, fitness: Map<Genome, number>, config: CrossConfig) {
const { reenable_rate } = config;
const alignment = alignGenomes(mom, dad);
const { reenable_rate } = config;
const alignment = alignGenomes(mom, dad);
const crossed: Genome = [];
// matching
for (const { mom: momGene, dad: dadGene } of alignment.matching) {
const newWeight = Math.random() < 0.5 ? momGene.data.weight : dadGene.data.weight;
const wasDisabled = !momGene.data.enabled || !dadGene.data.enabled;
const newEnabled = !wasDisabled || Math.random() < reenable_rate;
const newGene = { ...momGene, data: { ...momGene.data, weight: newWeight, enabled: newEnabled } };
crossed.push(newGene);
}
// disjoint
const momFitness = fitness.get(mom)!;
const dadFitness = fitness.get(dad)!;
const mostFit = momFitness === dadFitness ? 'equal' : momFitness > dadFitness ? 'mom' : 'dad';
for (const { mom: momGene, dad: dadGene } of alignment.disjoint) {
if (momGene === null) crossed.push(dadGene as Gene);
else if (dadGene === null) crossed.push(momGene);
else if (mostFit === 'mom') crossed.push(momGene);
else if (mostFit === 'dad') crossed.push(dadGene);
// both are equally fit - select at random
else if (Math.random() < 0.5) crossed.push(momGene);
else crossed.push(dadGene);
}
// excess
for (const { mom: momGene, dad: dadGene } of alignment.excess) {
if (momGene === null) crossed.push(dadGene as Gene);
else if (dadGene === null) crossed.push(momGene as Gene);
else throw Error(`invalid excess alignment: alignment=${JSON.stringify(alignment)}`);
}
return crossed;
}
export function mutateAssign(gene: Gene, newWeight: number): Gene {