UNPKG

tycho-solver

Version:

Evolutionary computation and optimization library

122 lines 5.21 kB
/** * Genetic Algorithm implementation */ import { GALoopOperator } from './components/GALoopOperator'; import { GAInitializationOperator } from './components/InitializationOperator'; import { GAEvaluationOperator } from './components/EvaluationOperator'; import { seededRandom } from '../../utils/rng'; export class GeneticAlgorithm { population; bestSolution; bestFitness; generation; config; fitnessFunction; rng; constructor(fitnessFunction, config) { this.fitnessFunction = fitnessFunction; this.config = config; this.generation = 0; // RNG: create seeded RNG if seed provided, or use provided rng const seed = config.seed; const rng = config.rng || seededRandom(seed); this.rng = rng; // Step 1: Always use InitializationOperator to create the population const initializationOperator = config.initializationOperator || new GAInitializationOperator(); const initResult = initializationOperator.initialize({ populationSize: config.populationSize || 100, individualFactory: config.individualFactory, rng }); // `initialize` may be async in other operators; GeneticAlgorithm constructor is synchronous // so reject async initialization here to keep `this.population` a T[]. if (initResult && typeof initResult.then === 'function') { throw new Error('Asynchronous initialization is not supported in GeneticAlgorithm constructor. Provide a synchronous InitializationOperator or use a factory that awaits initialization.'); } this.population = initResult; if (!Array.isArray(this.population) || this.population.length === 0) { throw new Error('InitializationOperator produced an empty population. This is not allowed.'); } // Step 2: Evaluation const evaluationOperator = config.evaluationOperator || new GAEvaluationOperator(fitnessFunction); this.bestSolution = this.population[0]; const initialEval = evaluationOperator.evaluate(this.bestSolution); if (initialEval && typeof initialEval.then === 'function') { throw new Error('Asynchronous evaluation is not supported in GeneticAlgorithm constructor. Provide a synchronous EvaluationOperator.'); } this.bestFitness = initialEval; for (const individual of this.population) { const fitnessResult = evaluationOperator.evaluate(individual); if (fitnessResult && typeof fitnessResult.then === 'function') { throw new Error('Asynchronous evaluation is not supported in GeneticAlgorithm constructor. Provide a synchronous EvaluationOperator.'); } const fitness = fitnessResult; if (fitness > this.bestFitness) { this.bestFitness = fitness; this.bestSolution = individual; } } } async evolve(generations) { const gens = generations || this.config.maxGenerations; const eliteCount = this.config.eliteCount ?? 1; const fitnessLimit = this.config.fitnessLimit; const gaConfig = { population: this.population, fitnessFunction: this.fitnessFunction, maxGenerations: gens, eliteCount }; if (this.rng) { gaConfig.rng = this.rng; } if (fitnessLimit !== undefined) { gaConfig.fitnessLimit = fitnessLimit; } if (this.config.initializationOperator) { gaConfig.initializationOperator = this.config.initializationOperator; } if (this.config.evaluationOperator) { gaConfig.evaluationOperator = this.config.evaluationOperator; } if (this.config.selectionOperator) { gaConfig.selectionOperator = this.config.selectionOperator; } if (this.config.crossoverOperator) { gaConfig.crossoverOperator = this.config.crossoverOperator; } if (this.config.mutationOperator) { gaConfig.mutationOperator = this.config.mutationOperator; } if (this.config.replacementOperator) { gaConfig.replacementOperator = this.config.replacementOperator; } if (this.config.elitismOperator) { gaConfig.elitismOperator = this.config.elitismOperator; } if (this.config.terminationOperator) { gaConfig.terminationOperator = this.config.terminationOperator; } const result = await GALoopOperator(gaConfig); this.population = result.population; this.bestSolution = result.bestSolution; this.bestFitness = result.bestFitness; this.generation = result.generation; return this.bestSolution; } getBestSolution() { return this.bestSolution; } getBestFitness() { return this.bestFitness; } getPopulation() { return this.population; } getGeneration() { return this.generation; } } // Export components for advanced usage export * from './components'; //# sourceMappingURL=index.js.map