neat/evolve/adaptive
The evolve-time adaptive bridge coordinates optional controllers and post-mutation maintenance inside one finished generation step.
The root adaptive/ chapter explains the full catalog of adaptive policies:
complexity budgeting, phased growth, acceptance pressure, lineage feedback,
mutation tuning, and operator-stat decay. This file owns the narrower evolve
question: when one generation is already in flight, which of those policies
should be invoked now, which ones must remain best-effort, and which cleanup
steps need to happen after mutation so the next generation starts from a
coherent runtime state?
Read this chapter when you want to understand:
- why evolve keeps optional adaptive imports behind safe bridge helpers,
- which adaptive controllers run before or after population mutation,
- how auto-compatibility tuning stays close to evolve instead of the broader adaptive root chapter,
- why cache invalidation and re-enable adaptation belong beside mutation-time maintenance rather than inside the mutation chapter itself.
The helper flow is easiest to retain as four responsibilities:
- invoke optional controller-level adaptation without breaking narrower runtimes,
- retune compatibility pressure when species counts drift,
- run pruning and mutation as one mutation-phase maintenance block,
- repair mutation-side runtime state such as compatibility caches and re-enable probabilities before the next generation is evaluated.
flowchart TD Ranked[Ranked current generation] --> Controllers[Run optional adaptive controllers] Controllers --> Compat[Retune compatibility coefficients when enabled] Compat --> Mutate[Apply pruning and mutation] Mutate --> Repair[Adapt re-enable probability and clear compat caches] Repair --> Ready[Next generation runtime state ready]
neat/evolve/adaptive/evolve.adaptive.utils.ts
adaptReenableProbability
adaptReenableProbability(
internal: NeatControllerForEvolution,
config: { minSamples: number; target: number; min: number; max: number; deltaScale: number; },
): void
Adapt the re-enable probability based on recent success ratios.
Re-enable adaptation turns the last generation's connection-revival outcomes into one controller-level probability update for the next generation. It aggregates success and attempt counters across the whole population, resets those per-genome counters once consumed, and only adjusts the shared probability when the sample size is large enough to be meaningful.
Parameters:
internal- - NEAT controller instance.
Returns: Nothing.
applyAdaptiveComplexityControllers
applyAdaptiveComplexityControllers(
internal: NeatControllerForEvolution,
): Promise<void>
Apply adaptive complexity controllers if available.
This helper is the evolve bridge into the root adaptive complexity policies. It keeps both optional calls together because they rewrite controller-level structure policy rather than one single genome: budget scheduling can change allowed network size, and phased complexity can flip the controller between growth and simplification modes.
Parameters:
internal- - NEAT controller instance.
Returns: A promise that resolves after optional complexity controllers have run.
applyAncestorUniqAdaptiveSafe
applyAncestorUniqAdaptiveSafe(
internal: NeatControllerForEvolution,
): Promise<void>
Apply ancestor uniqueness adaptation if available.
This helper is the evolve-side bridge from freshly recorded telemetry lineage evidence back into future controller policy. The underlying adaptive rule may change dominance epsilon or lineage-pressure settings, but the bridge itself stays narrow: it only attempts the optional handoff and tolerates runtimes where lineage adaptation is absent.
Parameters:
internal- - NEAT controller instance.
Returns: A promise that resolves after the optional lineage controller runs.
applyAutoCompatibilityTuning
applyAutoCompatibilityTuning(
internal: NeatControllerForEvolution,
config: { targetMin: number; adjustRate: number; minCoeff: number; maxCoeff: number; randomScale: number; },
): void
Apply auto-compatibility tuning if enabled.
This helper keeps one small adaptive loop close to evolve because it depends directly on the just-observed species count from the ranked generation. When the observed registry drifts from the target, the helper nudges excess and disjoint coefficients together so the next speciation pass can tighten or loosen the compatibility boundary.
The fallback behavior when error === 0 is also deliberate: instead of doing
nothing forever at equilibrium, the helper allows a bounded random nudge so
the controller can keep exploring nearby coefficient space.
Parameters:
internal- - NEAT controller instance.config- - Tuning constants.
Returns: Nothing.
applyMinimalCriterionAdaptiveSafe
applyMinimalCriterionAdaptiveSafe(
internal: NeatControllerForEvolution,
): Promise<void>
Apply minimal criterion adaptive controller if available.
Minimal criterion adaptation is one of the few adaptive policies that can rewrite the current generation's score landscape immediately. Keeping it in a safe wrapper lets evolve apply that pressure when configured without forcing every runtime surface to include the full adaptive subtree.
Parameters:
internal- - NEAT controller instance.
Returns: A promise that resolves after the optional acceptance controller runs.
applyOperatorAdaptationSafe
applyOperatorAdaptationSafe(
internal: NeatControllerForEvolution,
): Promise<void>
Apply operator adaptation if available.
Operator adaptation is another best-effort policy-maintenance bridge. It decays long-running operator statistics so later mutation choices weight more recent evidence without forcing evolve to know the details of the adaptive operator-selection subsystem.
Parameters:
internal- - NEAT controller instance.
Returns: A promise that resolves after optional operator-stat decay runs.
applyPruningAndMutation
applyPruningAndMutation(
internal: NeatControllerForEvolution,
): Promise<void>
Apply pruning and mutation phases.
Mutation-time maintenance is grouped here because evolve needs one compact place where structural removal, adaptive pruning, baseline mutation, and optional adaptive mutation all happen in the intended order. The helper does not decide whether the population should be rebuilt; it assumes the next generation already exists and now needs its structural edits.
Example:
await applyPruningAndMutation(internal);
invalidateCompatibilityCaches(internal);
Parameters:
internal- - NEAT controller instance.
Returns: A promise that resolves after mutation-phase maintenance finishes.
invalidateCompatibilityCaches
invalidateCompatibilityCaches(
internal: NeatControllerForEvolution,
): void
Invalidate compatibility caches after mutations.
Structural mutation can make cached compatibility comparisons stale. Clearing those caches here ensures later speciation and distance reads are recomputed from the post-mutation topology instead of reusing scores from the previous generation.
Parameters:
internal- - NEAT controller instance.
Returns: Nothing.