add tests for computeNextGeneration

This commit is contained in:
Michael Peters 2024-08-29 15:54:33 -07:00
parent 4350b425ee
commit 08c9a27266
2 changed files with 71 additions and 6 deletions

View File

@ -228,7 +228,7 @@
* - Effectively pass data from inputs, through hidden nodes, to outputs
*/
import { edgesToNodes, NodeID, Network, Node, topoSort, traceParents, RawEdge } from './network';
import { edgesToNodes, NodeID, traceParents, RawEdge } from './network';
import { keyMax, mapInvert, mapMap, randchoice, randint, randomNegPos, setDifference, setMap } from './util';
export interface GeneData {
@ -589,7 +589,7 @@ export function mutate(genome: Genome, config: MutateConfig): Genome {
return newGenome;
}
interface NextGenerationConfig {
export interface NextGenerationConfig {
fc: FertilityConfig;
mcc: MateChoiceConfig;
cc: CrossConfig;
@ -624,9 +624,5 @@ export function computeNextGeneration(
nextGeneration.set(baby, sid);
}
// TODO: consider adding a test for this function
// TODO: consider renaming the top part of this file "neat.ts" and the
// bottom part (activate and below) to be in a new file "brain-neat.ts"
return nextGeneration;
}

View File

@ -13,6 +13,8 @@ import {
Population,
resetGlobalIDs,
assignSpecies,
NextGenerationConfig,
computeNextGeneration,
} from '../site/snake/neat';
import { assert, addTest, assertSetEqual, assertDeepEqual } from './tests';
@ -405,3 +407,70 @@ function testFindAcyclicNewConns() {
assertDeepEqual(options, expected);
}
addTest(testFindAcyclicNewConns);
function testComputeNextGeneration() {
function makeGenome(weight: number) {
return [{ src_id: 'A', dst_id: 'B', data: { innovation: 1, weight, enabled: true } }];
}
const genomeA = makeGenome(1);
const genomeB = makeGenome(2);
const genomeC = makeGenome(3);
const genomeD = makeGenome(4);
const genomeE = makeGenome(5);
const population = new Map();
population.set(genomeA, 1);
population.set(genomeB, 1);
population.set(genomeC, 1);
population.set(genomeD, 2);
population.set(genomeE, 2);
const fitness = new Map();
fitness.set(genomeA, 1);
fitness.set(genomeB, 2);
fitness.set(genomeC, 1);
fitness.set(genomeD, 1);
fitness.set(genomeE, 2);
const cngc: NextGenerationConfig = {
fc: {
fertile_threshold: 0.6,
champion_min_species_size: 3,
},
mcc: {
asexual_rate: 0.5,
interspecies_rate: 0.2,
},
cc: {
reenable_rate: 0.25,
},
mc: {
mutate_rate: 0.25,
assign_rate: 0.1,
assign_mag: 1.0,
perturb_mag: 0.1,
new_node_rate: 0.2,
new_connection_rate: 0.1,
},
cdc: {
c1: 1,
c2: 1,
c3: 10,
},
cdt: 1.0,
};
resetGlobalIDs({ node_id: 1, innovation_number: 2, species_id: 3 });
const ng = computeNextGeneration(population, fitness, cngc);
// NOTE: these tests are not very detailed as this is difficult
// to test without mocks
assert(ng.size === population.size);
const sids = new Set(ng.values());
assert(sids.has(1));
assert(!sids.has(2));
// it not guaranteed that sids.has(3) since the new genomes may have the
// same species as the species 1 champ
}
addTest(testComputeNextGeneration);