architecture/network/evolve

Network-level neuroevolution loop for improving one runnable graph in place.

This chapter sits between the lightweight Network facade and the broader neat/ subsystem. Call network.evolve() when the question is "improve this graph against a supervised dataset" without first wiring a separate experiment harness. The method treats the current network as a seed genome, configures a short-lived NEAT runtime around it, evaluates descendants, then copies the best discovered structure back into the original instance.

The folder is split by the same stages the public call executes. setup validates dataset shape and resolves defaults. fitness turns prediction error into a comparable score. loop owns generation-to-generation stopping logic. finalize adopts the winning genome and tears down worker resources. Keeping those shelves separate makes the README read like an evolution run rather than an alphabetical pile of helpers.

flowchart LR
  Seed[Seed Network] --> Normalize[Normalize options and dataset]
  Normalize --> Fitness[Build fitness evaluator]
  Fitness --> Neat[Create temporary NEAT runtime]
  Neat --> Loop[Run evolve loop]
  Loop --> Adopt[Adopt best genome into original network]

Use this boundary when you want a bounded local search over network structure, not a long-lived population controller. error answers "stop when good enough", iterations answers "stop after this many generations", and growth answers "how much should extra structure cost while searching".

For compact background reading on the wider search family behind this folder, see Wikipedia contributors, Evolutionary algorithm. The implementation here is intentionally narrower: it keeps the public call site small while reusing the repo's NEAT runtime under the hood.

Example: stop when the network gets below an error target or hits a generation cap.

const summary = await network.evolve(trainingSet, {
  error: 0.02,
  iterations: 500,
  growth: 0.0005,
});

Example: cap the search more tightly and fan evaluation across workers when dataset scoring dominates.

const summary = await network.evolve(trainingSet, {
  iterations: 120,
  threads: 2,
  log: 20,
});

architecture/network/evolve/network.evolve.utils.ts

evolveNetwork

evolveNetwork(
  set: TrainingSample[],
  options: EvolveOptions,
): Promise<{ error: number; iterations: number; time: number; }>

Evolves a network with a NEAT-style search loop until an error target or generation limit is reached.

Overview:

Typical usage guidance:

Parameters:

Returns: Final summary containing best error estimate, generations processed, and elapsed milliseconds.

Example:

const summary = await network.evolve(trainingSet, {
  error: 0.02,
  iterations: 500,
  growth: 0.0005,
  threads: 2,
});
console.log(summary.error, summary.iterations, summary.time);

architecture/network/evolve/network.evolve.setup.utils.ts

applySmallPopulationHeuristics

applySmallPopulationHeuristics(
  neatInstance: NeatRuntime,
  evolveOptions: EvolveOptions,
): void

Apply conservative mutation-rate and mutation-amount defaults for tiny populations to reduce early stagnation risk while avoiding aggressive overrides when callers already configured explicit mutation controls.

Parameters:

Returns: Nothing.

assertEvolutionDatasetCompatibility

assertEvolutionDatasetCompatibility(
  network: default,
  dataSet: TrainingSample[],
): void

Validate that training samples exist and that each sample shape matches the network input and output arity before any evolution work starts.

Parameters:

Returns: Nothing.

configureNeatOptions

configureNeatOptions(
  network: default,
  evolveOptions: EvolveOptions,
): void

Normalize options consumed by the NEAT constructor, including compatibility mapping between populationSize and popsize, plus default speciation behavior needed for historical evolve-call consistency.

Parameters:

Returns: Nothing.

createEvolutionConfig

createEvolutionConfig(
  settingsToSummarize: EvolutionSettings,
): EvolutionConfig | undefined

Build a structured evolution-config snapshot for diagnostics, callback payloads, and log hooks whenever scheduling metadata exists, while keeping omitted schedule paths represented as an explicit undefined result.

Parameters:

Returns: Optional summary config.

createNeatInstance

createNeatInstance(
  network: default,
  fitnessFunction: EvolutionFitnessFunction,
  evolveOptions: EvolveOptions,
): Promise<NeatRuntime>

Lazy-load the NEAT runtime class and create an instance bound to the prepared fitness evaluator and normalized options so evolution setup can remain lightweight until construction is truly needed.

Parameters:

Returns: Constructed NEAT instance.

getNormalizedOptions

getNormalizedOptions(
  evolveOptions: EvolveOptions,
): EvolveOptions

Return the normalized evolve-options object that every downstream setup helper reads so defaults, compatibility shims, and diagnostics all start from one stable and predictable structure.

Parameters:

Returns: Safe options object.

prepareFitnessFunction

prepareFitnessFunction(
  dataSet: TrainingSample[],
  resolvedSettings: EvolutionSettings,
  evolveOptions: EvolveOptions,
): Promise<FitnessSetup>

Build the effective fitness evaluator by selecting either single-thread or worker-backed execution from resolved threading settings, then return both the callable function and the resolved runtime thread count.

Parameters:

Returns: Fitness function and resolved thread count.

resolveEvolutionSettings

resolveEvolutionSettings(
  evolveOptions: EvolveOptions,
): EvolutionSettings

Resolve scalar evolution settings with explicit and stable defaults so later setup phases can run deterministically without repeating option-default logic in several different orchestration branches.

Parameters:

Returns: Normalized scalar settings.

resolveStopConditions

resolveStopConditions(
  evolveOptions: EvolveOptions,
  initialTargetError: number,
): EvolutionStopConditions

Resolve stopping conditions while preserving legacy iteration-and-error semantics so existing callers keep the same termination behavior, including compatibility with historical zero-iteration and disabled-error workflows.

Parameters:

Returns: Final stop conditions.

warnIfNoBestGenomeMayOccur

warnIfNoBestGenomeMayOccur(
  neatInstance: NeatRuntime,
  evolveOptions: EvolveOptions,
): void

Emit a best-genome advisory warning for zero-iteration runs where legacy flows can complete without setting a champion, preventing silent confusion when a caller expects a populated best network.

Parameters:

Returns: Nothing.

architecture/network/evolve/network.evolve.fitness.utils.ts

buildMultiThreadFitness

buildMultiThreadFitness(
  set: TrainingSample[],
  cost: CostFunctionOrRef,
  amount: number,
  growth: number,
  threads: number,
  options: Record<string, unknown>,
): Promise<FitnessSetup>

Build worker-based population fitness setup that serializes the dataset once and assigns a population-scoring function. When worker construction fails, this helper falls back to the single-thread evaluator automatically.

Parameters:

Returns: Population fitness setup.

buildPopulationWorkerFitnessFunction

buildPopulationWorkerFitnessFunction(
  workers: TestWorkerInstance[],
  growth: number,
): PopulationFitnessFunction

Build population-level fitness function powered by worker queue.

Parameters:

Returns: Population-level fitness function.

buildSingleThreadFitness

buildSingleThreadFitness(
  set: TrainingSample[],
  cost: EvolveCostFunction,
  amount: number,
  growth: number,
): SingleGenomeFitnessFunction

Build a single-threaded genome fitness evaluator that repeats scoring, applies complexity penalty, and normalizes by evaluation count. This path is the deterministic fallback when worker-based evaluation is unavailable.

Parameters:

Returns: Single-genome fitness function.

cacheComplexityBase

cacheComplexityBase(
  genome: default,
  structureCounts: GenomeStructureCounts,
  complexityBase: number,
): void

Store complexity base cache entry for future reuse.

Parameters:

Returns: Nothing.

claimNextGenome

claimNextGenome(
  context: PopulationWorkerEvaluationContext,
): default | undefined

Claims the next genome index from shared queue state.

Parameters:

Returns: Next genome, or undefined when queue is exhausted.

computeComplexityBase

computeComplexityBase(
  genome: default,
  structureCounts: GenomeStructureCounts,
): number

Compute non-scaled complexity base from structural counts.

Parameters:

Returns: Base complexity value before growth scaling.

computeComplexityPenalty

computeComplexityPenalty(
  genome: default,
  growth: number,
): number

Compute structural complexity penalty scaled by growth so larger genomes receive deterministic parsimony pressure during fitness scoring. Cached structure counts avoid repeated recomputation for unchanged genome objects.

Parameters:

Returns: Complexity penalty.

createPopulationWorkerEvaluationContext

createPopulationWorkerEvaluationContext(
  sourceWorkers: TestWorkerInstance[],
  sourcePopulation: default[],
  sourceGrowth: number,
  sourceResolve: () => void,
): PopulationWorkerEvaluationContext

Creates the shared evaluation context for one population run.

Parameters:

Returns: Population evaluation context.

createSingleThreadFallbackFitness

createSingleThreadFallbackFitness(
  set: TrainingSample[],
  cost: CostFunctionOrRef,
  amount: number,
  growth: number,
): FitnessSetup

Build single-thread fallback fitness setup.

Parameters:

Returns: Single-thread fitness setup.

createWorkerTraversalContext

createWorkerTraversalContext(
  context: PopulationWorkerEvaluationContext,
  worker: TestWorkerInstance,
): WorkerTraversalContext

Creates traversal context for one worker.

Parameters:

Returns: Worker traversal context.

evaluateGenomeAmountTimes

evaluateGenomeAmountTimes(
  genome: default,
  set: TrainingSample[],
  cost: EvolveCostFunction,
  amount: number,
): number

Evaluate one genome repeatedly and accumulate negative error.

Parameters:

Returns: Accumulated negative error or -Infinity on failure.

evaluateGenomeErrorSafely

evaluateGenomeErrorSafely(
  genome: default,
  set: TrainingSample[],
  cost: EvolveCostFunction,
): number | null

Evaluate one genome and return error, with warning-protected failure handling.

Parameters:

Returns: Error value, or null when evaluation fails.

evaluateGenomeWithWorker

evaluateGenomeWithWorker(
  worker: TestWorkerInstance,
  genome: default,
  growth: number,
): Promise<void>

Evaluate one genome with a worker and assign a penalized score that includes structural complexity pressure. Non-numeric worker results are ignored so calling loops can continue safely.

Parameters:

Returns: Promise resolving when score assignment completes.

finalizeWorker

finalizeWorker(
  context: PopulationWorkerEvaluationContext,
): void

Marks one worker as completed and resolves when all workers finish.

Parameters:

Returns: Nothing.

getCachedComplexityBase

getCachedComplexityBase(
  genome: default,
  structureCounts: GenomeStructureCounts,
): number | null

Retrieve cached complexity base if cached structure counts still match.

Parameters:

Returns: Cached complexity base or null when cache miss occurs.

getGenomeStructureCounts

getGenomeStructureCounts(
  genome: default,
): GenomeStructureCounts

Get structural counts used by complexity heuristic.

Parameters:

Returns: Structural counts used for complexity computation.

hasNoWorkers

hasNoWorkers(
  context: PopulationWorkerEvaluationContext,
): boolean

Checks whether there are workers available to process genomes.

Parameters:

Returns: True when worker pool is empty.

installWorkerTerminationHook

installWorkerTerminationHook(
  options: Record<string, unknown>,
  workers: TestWorkerInstance[],
): void

Register a worker termination hook onto the evolve options object so spawned workers can be cleaned up deterministically. Termination errors are swallowed to avoid masking primary evolution outcomes.

Parameters:

Returns: Nothing.

resolveCostName

resolveCostName(
  cost: CostFunctionOrRef,
): string

Resolve serializable cost name for worker payload.

Parameters:

Returns: Cost name string.

resolveEvaluation

resolveEvaluation(
  context: PopulationWorkerEvaluationContext,
): void

Resolves the population evaluation promise.

Parameters:

Returns: Nothing.

resolveTestWorkerConstructor

resolveTestWorkerConstructor(): Promise<TestWorkerConstructor | null>

Resolve worker constructor for current runtime environment.

Returns: Worker constructor or null when unavailable.

runWorkerTraversalStep

runWorkerTraversalStep(
  traversalContext: WorkerTraversalContext,
): void

Runs one asynchronous traversal step for a worker.

Parameters:

Returns: Nothing.

spawnTestWorkers

spawnTestWorkers(
  workerConstructor: TestWorkerConstructor,
  serializedSet: number[],
  cost: CostFunctionOrRef,
  threads: number,
): TestWorkerInstance[]

Spawn worker instances up to requested thread count.

Parameters:

Returns: Spawned worker instances.

startWorkerTraversal

startWorkerTraversal(
  context: PopulationWorkerEvaluationContext,
): void

Starts traversal loops for all workers.

Parameters:

Returns: Nothing.

warnGenomeEvaluationFailure

warnGenomeEvaluationFailure(
  error: unknown,
): void

Emit warning when genome evaluation fails.

Parameters:

Returns: Nothing.

architecture/network/evolve/network.evolve.loop.utils.ts

applyEvolutionStep

applyEvolutionStep(
  state: EvolutionLoopState,
  evolvedGenome: default,
  growth: number,
): void

Applies one evolve() result to loop state.

Parameters:

Returns: Nothing.

createInitialLoopState

createInitialLoopState(): EvolutionLoopState

Creates initial loop state snapshot.

Returns: Initial loop state.

deriveErrorFromFitness

deriveErrorFromFitness(
  fitness: number,
  genome: default,
  growth: number,
): number

Derive error from fitness by inverting score composition.

Parameters:

Returns: Derived error value.

runEvolutionLoop

runEvolutionLoop(
  neatInstance: NeatRuntime,
  resolvedSettings: EvolutionSettings,
  targetError: number,
  iterations: number | undefined,
): Promise<{ error: number; bestGenome: default | undefined; }>

Run the core evolution loop until error target or iteration limit is reached.

Parameters:

Returns: Loop result snapshot.

runScheduleCallbackSafely

runScheduleCallbackSafely(
  scheduleConfig: { iterations: number; function: (stats: { fitness: number; error: number; iteration: number; }) => void; } | undefined,
  generation: number,
  bestFitness: number,
  error: number,
): void

Run schedule callback if schedule trigger is reached.

Parameters:

Returns: Nothing.

shouldAbortForInvalidErrors

shouldAbortForInvalidErrors(
  state: EvolutionLoopState,
): boolean

Determines whether loop must abort due to invalid-error streak.

Parameters:

Returns: True when invalid-error threshold is reached.

shouldContinueEvolution

shouldContinueEvolution(
  currentError: number,
  targetError: number,
  iterationsSpecified: boolean,
  currentGeneration: number,
  maxIterations: number | undefined,
): boolean

Determine whether evolution loop should continue.

Parameters:

Returns: True when loop should continue.

updateBestGenomeIfImproved

updateBestGenomeIfImproved(
  currentBestFitness: number,
  currentBestGenome: default | undefined,
  candidateFitness: number,
  candidateGenome: default,
): { bestFitness: number; bestGenome: default | undefined; }

Update best fitness/genome snapshot when improved.

Parameters:

Returns: Updated best snapshot.

updateInvalidErrorCounter

updateInvalidErrorCounter(
  currentCount: number,
  currentError: number,
): number

Update invalid-error counter.

Parameters:

Returns: Updated guard state.

architecture/network/evolve/network.evolve.finalize.utils.ts

adoptBestGenomeOrWarn

adoptBestGenomeOrWarn(
  network: default,
  neatInstance: NeatRuntime,
  bestGenome: default | undefined,
  clearState: boolean,
): void

Finalization helper that adopts the best evolved genome into the caller's network when one exists.

If no best genome is available, the optional NEAT warning hook is invoked so callers can surface diagnostic context without throwing from finalize flow.

buildEvolutionSummary

buildEvolutionSummary(
  error: number,
  iterations: number,
  loopStartTime: number,
): EvolutionSummary

Build the final evolution summary payload returned by the evolve loop.

Parameters:

Returns: Evolution summary object.

terminateWorkersSafely

terminateWorkersSafely(
  evolveOptions: EvolveOptions,
): void

Best-effort shutdown for worker terminators attached to evolve options.

This keeps finalize paths resilient when background evaluators were used and avoids leaking worker resources if teardown throws.

Parameters:

Returns: Nothing.

architecture/network/evolve/network.evolve.utils.types.ts

Error message emitted when the supplied dataset dimensions do not match the network input or output size.

DATASET_COMPATIBILITY_ERROR_MESSAGE

Error message emitted when the supplied dataset dimensions do not match the network input or output size.

DEFAULT_EVALUATION_AMOUNT

Default number of repeated fitness evaluations used when no explicit evaluation amount is specified per genome.

DEFAULT_GROWTH

Default per-connection complexity growth penalty applied when computing fitness-adjusted complexity scores in the evolve loop.

DEFAULT_LOG_INTERVAL

Default generation logging frequency; zero disables per-generation log output during the evolve loop.

DEFAULT_TARGET_ERROR

Default target error threshold used when no explicit error stopping condition is provided to the evolve call.

DEFAULT_THREAD_COUNT

Default worker thread count used when no explicit thread override is provided to single-thread evolve calls.

DISABLED_TARGET_ERROR

Sentinel error value indicating that error-based stopping is explicitly disabled and only iteration limits apply.

EvolutionSummary

Shared summary payload returned by the evolve loop containing the best error, generation count, and wall-clock time.

GenomeStructureCounts

Structural node, connection, and gate counts used by complexity growth-penalty heuristics during fitness adjustment.

MAX_CONSECUTIVE_INVALID_ERRORS

Maximum number of consecutive NaN or Infinity fitness values tolerated before the evolve loop aborts early.

SMALL_POPULATION_MUTATION_AMOUNT

Mutation amount fallback applied when the active population falls below the small-population threshold during evolution.

SMALL_POPULATION_MUTATION_RATE

Mutation rate fallback applied when the active population falls below the small-population threshold during evolution.

SMALL_POPULATION_THRESHOLD

Population size threshold below which the evolve loop applies more aggressive fallback mutation rates and amounts.

STOPPING_CONDITION_REQUIRED_ERROR_MESSAGE

Error message emitted when an evolution call is started with neither an iteration limit nor an error target specified.

ZERO_ITERATIONS

Explicit zero used as an initial iteration counter and for stopping-condition comparisons during evolve loop entry.

architecture/network/evolve/network.evolve.errors.ts

Raised when the evolve dataset is missing or does not match network IO.

Example:

throw new NetworkEvolveDatasetCompatibilityError(
  'Dataset should have at least one sample and matching input/output sizes.',
);

NetworkEvolveDatasetCompatibilityError

Contract for NetworkEvolveDatasetCompatibilityError.

NetworkEvolveStoppingConditionRequiredError

Contract for NetworkEvolveStoppingConditionRequiredError.

Generated from source JSDoc • GitHub