neat/multiobjective
Root orchestration for NEAT multi-objective ranking.
This chapter keeps the public ranking flow small and readable: collect the active objective schema, precompute the population value matrix, resolve pairwise dominance into fronts, assign NSGA-II style crowding distances, and archive the leading fronts for later inspection.
The neighboring objectives/, dominance/, fronts/, and crowding/
chapters own the narrow mechanics. This file exists so a reader can learn
the ranking pipeline from top to bottom without digging through those lower-
level helpers first.
Multi-objective ranking answers a different question than ordinary single- score selection. Instead of asking "which genome has the highest score?", this chapter asks "which genomes are still competitive once several goals must be satisfied at the same time?" The result is a layered view of the population:
- Pareto fronts separate clearly dominated genomes from still-competitive ones
- crowding distances prefer spread along the frontier instead of collapsing to one region
- optional archiving preserves the leading fronts for later telemetry and inspection
A useful reading order is:
- this orchestration file for the top-level ranking flow
objectives/for value extraction and direction handlingdominance/for pairwise comparison rulesfronts/andcrowding/for frontier construction and diversity on the frontier
neat/multiobjective/multiobjective.ts
fastNonDominated
fastNonDominated(
pop: default[],
): default[][]
Perform fast non-dominated sorting and compute crowding distances for a population of networks (genomes). This implements a standard NSGA-II style non-dominated sorting followed by crowding distance assignment.
Conceptually, the function runs in four stages:
- read the active objective schema from the controller,
- build one objective-value vector per genome,
- resolve dominance relationships into ordered Pareto fronts,
- assign crowding distances so selection can prefer spread within each front.
That final crowding step matters because a frontier alone only tells you that several genomes are non-dominated. It does not tell you whether those genomes represent a broad tradeoff surface or a tightly clustered patch of nearly identical solutions.
The function annotates genomes with two fields used elsewhere in the codebase:
_moRank: integer Pareto front rank (0 = best/frontier)_moCrowd: numeric crowding distance (higher is better; Infinity for boundary solutions)
This orchestration layer also decides when the leading fronts should be archived for later telemetry or inspection. That keeps the ranking story in one place: compute the competitive ordering now, and optionally preserve the resulting frontier snapshot for later analysis.
Example:
// inside a Neat class that exposes `_getObjectives()` and Pareto archiving options
const fronts = fastNonDominated.call(neatInstance, population);
// fronts[0] contains the current Pareto-optimal genomes
// genomes inside each front now also carry `_moRank` and `_moCrowd`
Read the return value like this:
fronts[0]is the current non-dominated frontierfronts[1]contains genomes dominated only by the first front- larger
_moCrowdvalues indicate genomes that sit in less crowded regions of the same front
Important assumptions:
- Each objective descriptor returned by
_getObjectives()must have anaccessor(genome: Network): numberfunction and may includedirection: 'max' | 'min'to indicate optimization direction. - Accessor failures are guarded and will yield a default value of 0.
Parameters:
this- - Neat instance providing_getObjectives(),optionsand_paretoArchivefields (function is meant to be invoked using.call)pop- - population array ofNetworkgenomes to be ranked
Returns: Array of Pareto fronts; each front is an array of Network genomes.