genetic-search
Version:
Multiprocessing genetic algorithm implementation library
143 lines • 5.86 kB
JavaScript
import { zip } from "./itertools";
import { arraySum, calcRangeStatSummary, calcStatSummary, createEmptyGroupedStatSummary, createEmptyRangeStatSummary, createEmptyStatSummary, fullCopyObject, roundGroupedStatSummary, roundRangeStatSummary, roundStatSummary, } from "./utils";
/**
* A manager for the statistics of a population of genomes.
*
* This class implements the [[GenomeStatsManagerInterface]] interface.
*
* @category Statistics
*/
export class GenomeStatsManager {
init(population, origin) {
for (const genome of population) {
this.initItem(genome, origin);
}
}
update(population, phenomeMatrix, fitnessColumn) {
for (const [genome, phenome, fitness] of zip(population, phenomeMatrix, fitnessColumn)) {
this.updateItem(genome, phenome, fitness);
}
}
initItem(genome, origin, parents = []) {
if (genome.stats !== undefined) {
return genome.stats;
}
genome.stats = {
fitness: 0,
age: 0,
phenome: [],
origin,
originCounters: {
crossover: arraySum(parents.map((p) => { var _a, _b, _c; return (_c = (_b = (_a = p.stats) === null || _a === void 0 ? void 0 : _a.originCounters) === null || _b === void 0 ? void 0 : _b.crossover) !== null && _c !== void 0 ? _c : 0; })) + Number(origin === 'crossover'),
mutation: arraySum(parents.map((p) => { var _a, _b, _c; return (_c = (_b = (_a = p.stats) === null || _a === void 0 ? void 0 : _a.originCounters) === null || _b === void 0 ? void 0 : _b.mutation) !== null && _c !== void 0 ? _c : 0; })) + Number(origin === 'mutation'),
},
parentIds: parents.map((p) => p.id),
};
return genome.stats;
}
/**
* Updates the statistics of a genome.
*
* @param genome The genome to update.
* @param phenome The phenome of the genome.
* @param fitness The fitness of the genome.
*
* @returns The updated genome statistics.
*/
updateItem(genome, phenome, fitness) {
const stats = this.initItem(genome, 'initial');
stats.age++;
stats.fitness = fitness;
stats.phenome = phenome;
return stats;
}
}
/**
* A manager for the population summary.
*
* This class implements the [[PopulationSummaryManagerInterface]] interface.
* It is used to manage the population summary, which is a summary of the
* statistics of a population of genomes.
*
* @category Statistics
*/
export class PopulationSummaryManager {
/**
* Constructs a new population summary manager.
*/
constructor() {
/**
* The number of generations since the best genome has changed.
*/
this.stagnationCounter = 0;
this.fitnessSummary = createEmptyStatSummary();
this.groupedFitnessSummary = createEmptyGroupedStatSummary();
this.ageSummary = createEmptyRangeStatSummary();
}
get() {
return {
fitnessSummary: fullCopyObject(this.fitnessSummary),
groupedFitnessSummary: fullCopyObject(this.groupedFitnessSummary),
ageSummary: fullCopyObject(this.ageSummary),
stagnationCounter: this.stagnationCounter,
};
}
getRounded(precision) {
return {
fitnessSummary: roundStatSummary(this.fitnessSummary, precision),
groupedFitnessSummary: roundGroupedStatSummary(this.groupedFitnessSummary, precision),
ageSummary: roundRangeStatSummary(this.ageSummary, precision),
stagnationCounter: this.stagnationCounter,
};
}
update(sortedPopulation) {
var _a;
const bestGenomeId = (_a = sortedPopulation[0]) === null || _a === void 0 ? void 0 : _a.id;
if (this.bestGenomeId !== bestGenomeId) {
this.bestGenomeId = bestGenomeId;
this.stagnationCounter = 0;
}
else {
this.stagnationCounter++;
}
const statsCollection = sortedPopulation
.filter((genome) => genome.stats !== undefined)
.map((genome) => genome.stats);
this.updateSummary(statsCollection);
this.updateGroupedSummary(statsCollection);
this.updateAgeSummary(statsCollection);
}
/**
* Updates the summary of the population.
*
* @param sortedStatsCollection The sorted collection of genome statistics.
*/
updateSummary(sortedStatsCollection) {
this.fitnessSummary = calcStatSummary(sortedStatsCollection.map((stats) => stats.fitness));
}
/**
* Updates the grouped summary of the population.
*
* @param sortedStatsCollection The sorted collection of genome statistics.
*/
updateGroupedSummary(sortedStatsCollection) {
const initialCollection = sortedStatsCollection.filter((stats) => stats.origin === 'initial');
const crossoverCollection = sortedStatsCollection.filter((stats) => stats.origin === 'crossover');
const mutationCollection = sortedStatsCollection.filter((stats) => stats.origin === 'mutation');
this.groupedFitnessSummary = {
initial: calcStatSummary(initialCollection.map((stats) => stats.fitness)),
crossover: calcStatSummary(crossoverCollection.map((stats) => stats.fitness)),
mutation: calcStatSummary(mutationCollection.map((stats) => stats.fitness)),
};
}
/**
* Updates the summary of the age of the population.
*
* @param sortedStatsCollection The sorted collection of genome statistics.
*/
updateAgeSummary(sortedStatsCollection) {
const ageCollection = sortedStatsCollection.map((stats) => stats.age);
this.ageSummary = calcRangeStatSummary(ageCollection);
}
}
//# sourceMappingURL=stats.js.map