tycho-solver
Version:
Evolutionary computation and optimization library
78 lines • 3.49 kB
JavaScript
import { SequentialOperator } from '../../../core/pipeline/SequentialOperator';
/**
* Orchestrates the main evolutionary loop for the Memetic Algorithm.
* This is a standalone component to keep the core class minimal.
*/
export async function memeticLoop(population, config, localSearcher, updateBest, applyLocalSearch, rng) {
let bestIndividual = null;
for (let gen = 0; gen < config.generations; gen++) {
// Step 1: Selection and offspring creation
const selectionAndOffspringStep = {
apply: async (pop) => {
const newPopulation = [];
const fitnesses = pop.map(ind => ind.fitness);
while (newPopulation.length < config.populationSize) {
const parents = config.selectionOperator.select(pop, fitnesses, 2);
const parent1 = parents[0];
const parent2 = parents[1] ?? parent1;
const r1 = rng ? rng.random() : Math.random();
let offspringGenome;
if (r1 < config.crossoverRate) {
const crossRes = config.crossoverOperator.crossover(parent1.genome, parent2.genome);
const children = crossRes && typeof crossRes.then === 'function'
? await crossRes
: crossRes;
offspringGenome = children[0];
}
else {
offspringGenome = parent1.genome;
}
const r2 = rng ? rng.random() : Math.random();
if (r2 < config.mutationRate) {
offspringGenome = config.mutationOperator.mutate(offspringGenome);
}
const r3 = rng ? rng.random() : Math.random();
if (r3 < config.localSearchRate) {
offspringGenome = await applyLocalSearch(offspringGenome, config, localSearcher);
}
const offspringFitness = await config.evaluationOperator.evaluate(offspringGenome);
newPopulation.push({
genome: offspringGenome,
fitness: offspringFitness
});
}
return newPopulation;
}
};
// Step 2: Replacement
const replacementStep = {
apply: async (newPopulation) => {
if (config.replacementOperator) {
const replaced = await config.replacementOperator.replace(population, newPopulation, newPopulation.map(ind => ind.fitness));
population = replaced;
}
else {
population = newPopulation;
}
return population;
}
};
const pipeline = new SequentialOperator([
selectionAndOffspringStep,
replacementStep
]);
population = await pipeline.apply(population);
bestIndividual = updateBest(population);
// Termination (optional)
if (config.terminationOperator &&
config.terminationOperator.shouldTerminate({
generation: gen,
fitness: bestIndividual?.fitness,
population
})) {
break;
}
}
return bestIndividual;
}
//# sourceMappingURL=LoopOperator.js.map