generated from michael/webpack-base
adjust chooseSurvivors -> chooseByFertility to also give the champions
This commit is contained in:
parent
21bf8f781e
commit
4d2e5b4b44
@ -348,12 +348,12 @@ export function initialSpeciate(
|
|||||||
return population;
|
return population;
|
||||||
}
|
}
|
||||||
|
|
||||||
interface SurvivorsConfig {
|
interface FertilityConfig {
|
||||||
survival_threshold: number;
|
fertile_threshold: number;
|
||||||
champion_min_species_size: number;
|
champion_min_species_size: number;
|
||||||
}
|
}
|
||||||
export function chooseSurvivors(population: Population, fitness: Map<Genome, number>, config: SurvivorsConfig) {
|
export function chooseByFertility(population: Population, fitness: Map<Genome, number>, config: FertilityConfig) {
|
||||||
const { survival_threshold, champion_min_species_size } = config;
|
const { fertile_threshold, champion_min_species_size } = config;
|
||||||
|
|
||||||
const species = mapInvert(population);
|
const species = mapInvert(population);
|
||||||
|
|
||||||
@ -364,22 +364,22 @@ export function chooseSurvivors(population: Population, fitness: Map<Genome, num
|
|||||||
return [k, v / speciesSize];
|
return [k, v / speciesSize];
|
||||||
});
|
});
|
||||||
|
|
||||||
const survivors = new Set<Genome>();
|
const fertile = new Set<Genome>();
|
||||||
|
|
||||||
// add sufficiently fit organisms
|
// add sufficiently fit organisms
|
||||||
const genomes: Genome[] = Array.from(population.keys());
|
const genomes: Genome[] = Array.from(population.keys());
|
||||||
const survival_idx = Math.floor(genomes.length * survival_threshold);
|
const survival_idx = Math.floor(genomes.length * fertile_threshold);
|
||||||
genomes.sort((a, b) => adjFitness.get(a)! - adjFitness.get(b)!);
|
genomes.sort((a, b) => adjFitness.get(a)! - adjFitness.get(b)!);
|
||||||
genomes.slice(survival_idx).forEach(o => survivors.add(o));
|
genomes.slice(survival_idx).forEach(o => fertile.add(o));
|
||||||
|
|
||||||
// add species champions
|
// add species champions
|
||||||
const champions = mapMap(species, (k, v) => [k, keyMax(v, o => adjFitness.get(o)!)]);
|
const champions = mapMap(species, (k, v) => [k, keyMax(v, o => adjFitness.get(o)!)]);
|
||||||
for (const [sid, c] of champions.entries()) {
|
for (const [sid, c] of champions.entries()) {
|
||||||
if (species.get(sid)!.size < champion_min_species_size) continue;
|
if (species.get(sid)!.size < champion_min_species_size) continue;
|
||||||
survivors.add(c);
|
fertile.add(c);
|
||||||
}
|
}
|
||||||
|
|
||||||
return survivors;
|
return { fertile, champions };
|
||||||
}
|
}
|
||||||
|
|
||||||
interface MateChoiceConfig {
|
interface MateChoiceConfig {
|
||||||
@ -594,6 +594,26 @@ export function mutate(genome: Genome, config: MutateConfig): Genome {
|
|||||||
return newGenome;
|
return newGenome;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
interface NextGenerationConfig {
|
||||||
|
fc: FertilityConfig;
|
||||||
|
}
|
||||||
|
export function computeNextGeneration(
|
||||||
|
population: Population,
|
||||||
|
fitness: Map<Genome, number>,
|
||||||
|
config: NextGenerationConfig,
|
||||||
|
) {
|
||||||
|
const { fc } = config;
|
||||||
|
|
||||||
|
const { fertile, champions } = chooseByFertility(population, fitness, fc);
|
||||||
|
|
||||||
|
// TODO: only copy over champions, the rest mate to produce the population
|
||||||
|
const nextGeneration = new Map(Array.from(fertile).map(s => [s, population.get(s)!]));
|
||||||
|
const species = mapInvert(nextGeneration);
|
||||||
|
const reps = mapMap(species, (sid, genomes) => [sid, genomes.values().next().value]);
|
||||||
|
|
||||||
|
// TODO: update chooseSurvivors so champions get copied over
|
||||||
|
}
|
||||||
|
|
||||||
export function activate(n: number) {
|
export function activate(n: number) {
|
||||||
// modified sigmoid function from NEAT paper
|
// modified sigmoid function from NEAT paper
|
||||||
return 1 / (1 + Math.exp(-4.9 * n));
|
return 1 / (1 + Math.exp(-4.9 * n));
|
||||||
|
@ -2,7 +2,7 @@ import {
|
|||||||
activate,
|
activate,
|
||||||
alignGenomes,
|
alignGenomes,
|
||||||
chooseMate,
|
chooseMate,
|
||||||
chooseSurvivors,
|
chooseByFertility,
|
||||||
compatibilityDistance,
|
compatibilityDistance,
|
||||||
crossGenomes,
|
crossGenomes,
|
||||||
findAcyclicNewConns,
|
findAcyclicNewConns,
|
||||||
@ -192,11 +192,11 @@ function testChooseSurvivors() {
|
|||||||
|
|
||||||
// (1 - 4/6) = 2/6 survive by fitness alone
|
// (1 - 4/6) = 2/6 survive by fitness alone
|
||||||
// top genome (champion) from all species with at least 3 genomes should always survive
|
// top genome (champion) from all species with at least 3 genomes should always survive
|
||||||
const sc = { survival_threshold: 4 / 6, champion_min_species_size: 3 };
|
const sc = { fertile_threshold: 4 / 6, champion_min_species_size: 3 };
|
||||||
const survivors = chooseSurvivors(population, fitness, sc);
|
const { fertile, champions } = chooseByFertility(population, fitness, sc);
|
||||||
|
|
||||||
assertSetEqual(
|
assertSetEqual(
|
||||||
survivors,
|
fertile,
|
||||||
new Set([
|
new Set([
|
||||||
genomeB, // champion of species 1
|
genomeB, // champion of species 1
|
||||||
genomeD, // #2 fitness
|
genomeD, // #2 fitness
|
||||||
@ -204,6 +204,10 @@ function testChooseSurvivors() {
|
|||||||
// genomeF not included since species is not large enough to have a champion
|
// genomeF not included since species is not large enough to have a champion
|
||||||
]),
|
]),
|
||||||
);
|
);
|
||||||
|
assert(champions.size === 3);
|
||||||
|
assert(champions.get(1)! === genomeB);
|
||||||
|
assert(champions.get(2)! === genomeE);
|
||||||
|
assert(champions.get(3)! === genomeF);
|
||||||
}
|
}
|
||||||
addTest(testChooseSurvivors);
|
addTest(testChooseSurvivors);
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user