tycho-solver
Version:
Evolutionary computation and optimization library
77 lines (76 loc) • 4.07 kB
JavaScript
;
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
return new (P || (P = Promise))(function (resolve, reject) {
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.memeticLoop = memeticLoop;
const SequentialOperator_1 = require("../../../core/pipeline/SequentialOperator");
/**
* Orchestrates the main evolutionary loop for the Memetic Algorithm.
* This is a standalone component to keep the core class minimal.
*/
function memeticLoop(population, config, localSearcher, updateBest, applyLocalSearch) {
return __awaiter(this, void 0, void 0, function* () {
let bestIndividual = null;
for (let gen = 0; gen < config.generations; gen++) {
const fitnesses = population.map(ind => ind.fitness);
// Step 1: Selection and offspring creation
const selectionAndOffspringStep = {
apply: (pop) => __awaiter(this, void 0, void 0, function* () {
const newPopulation = [];
const fitnesses = pop.map(ind => ind.fitness);
while (newPopulation.length < config.populationSize) {
const parents = config.selectionOperator.select(pop, fitnesses, 2);
const [parent1, parent2] = parents;
let offspringGenome = Math.random() < config.crossoverRate
? config.crossoverOperator.crossover(parent1.genome, parent2.genome)[0]
: parent1.genome;
if (Math.random() < config.mutationRate) {
offspringGenome = config.mutationOperator.mutate(offspringGenome);
}
if (Math.random() < config.localSearchRate) {
offspringGenome = yield applyLocalSearch(offspringGenome, config, localSearcher);
}
const offspringFitness = yield config.evaluationOperator.evaluate(offspringGenome);
newPopulation.push({ genome: offspringGenome, fitness: offspringFitness });
}
return newPopulation;
})
};
// Step 2: Replacement
const replacementStep = {
apply: (newPopulation) => __awaiter(this, void 0, void 0, function* () {
if (config.replacementOperator) {
const replaced = yield config.replacementOperator.replace(population, newPopulation, newPopulation.map(ind => ind.fitness));
population = replaced;
}
else {
population = newPopulation;
}
return population;
})
};
const pipeline = new SequentialOperator_1.SequentialOperator([
selectionAndOffspringStep,
replacementStep
]);
population = yield pipeline.apply(population);
bestIndividual = updateBest(population);
// Termination (optional)
if (config.terminationOperator && config.terminationOperator.shouldTerminate({
generation: gen,
fitness: bestIndividual === null || bestIndividual === void 0 ? void 0 : bestIndividual.fitness,
population
})) {
break;
}
}
return bestIndividual;
});
}