Module crowdless_nsga2
Expand description
The regression sentinel for Nsga2: the same genetic algorithm with
crowding distance deleted.
NSGA-II’s contribution is not that it uses a genetic algorithm on a
multi-objective problem — it is how it ranks a population: non-domination
rank first, crowding distance second. The second half is the entire
diversity mechanism. Rank alone cannot separate two mutually non-dominated
solutions, and once a run has converged nearly the whole population is rank
0, so from that moment on crowding distance is doing all of the deciding —
in the parent tournament and in the survival truncation alike.
A claim like that is only worth asserting if something would notice when it stopped being true, so this module ships the ablation the oracle measures against: NSGA-II with the crowded-comparison operator’s second key replaced by a constant.
§It is an ablation, not a second algorithm
Everything except crowding is the real sampler’s
(crates/atune_core/src/sampler/nsga2/mod.rs), on purpose — including the
operators themselves, which are called rather than re-implemented:
| Piece | Here | Nsga2 |
|---|---|---|
| initial population | random_unit_vector, one uniform draw per gene | same function |
| parent selection | binary_tournament on (rank, **0**) | binary_tournament on (rank, crowding) |
| crossover / mutation | crossover / mutate, η_c = η_m = 20, rate 1/d | same functions, same constants |
| survival | pool parents + children, fast_non_dominated_sort, fill front by front | same |
| splitting-front truncation | by pool order | by decreasing crowding distance |
| admission guard | evaluated-is-the-bred-config, finite objectives | same |
| RNG | ChaCha8Rng seeded seed_for_name(sampler_seed, "nsga2") | same |
The RNG tag is deliberately the same string, so for a given
(study seed, trial number) both samplers consume the identical draw stream:
the sentinel is a paired comparison in which crowding distance is the only
moving part. That is what makes “the crowding-blind variant loses the
diversity margin” a statement about crowding distance rather than about two
unrelated searchers.
Note what the ablation is not: it is not a weak searcher. It keeps elitism, non-dominated sorting and the whole variation machinery, so it still converges toward the front — it simply has no pressure to stay spread along it. That is precisely the failure the diversity axis exists to catch, and precisely the one a hypervolume-only gate can miss.
§Why it is here and not in the facade
It is a benchmark fixture. atune ships one NSGA-II; shipping a second,
deliberately weakened one as public API would be a maintenance liability and
an invitation to use it. atune_bench is publish = false, which is exactly
where an ablation belongs — the same reasoning that put
IsotropicEs and
DeKnobs::degenerate here.
§Determinism
Identical to the real sampler’s: every draw comes from a ChaCha8Rng keyed on
the trial’s sampler_seed, never ambient entropy, so a single-worker run with
a fixed study seed is fully reproducible (docs/design/09-implementation.md §5,
promise 3). Like every population-based sampler it is history-dependent, so it
does not get promise 2 under parallelism — and, being a bench fixture, it
never persists state at all (state returns None).
Structs§
- Crowdless
Nsga2 - NSGA-II with crowding distance deleted: the diversity ablation.