Namespace OptunaSharp.Samplers.Nsgaiii
Classes
- NSGAIIIElitePopulationSelectionStrategy
The default elite-population selection strategy of NSGAIIISampler. Port of
optuna/samplers/_nsgaiii/_elite_population_selection_strategy.py.Ranks the combined population by (constrained) non-domination (shared RankPopulation(IReadOnlyList<FrozenTrial>, IReadOnlyList<StudyDirection>, bool)), then fills the elite population rank by rank. The rank that overflows
population_size— the borderline front — is truncated by reference-point niching rather than crowding distance: objective values are normalized onto a hyperplane (ideal point + achievement-scalarizing extreme points), each individual is associated with its closest reference point, and survivors are drawn to keep the reference points as evenly populated (sparse) as possible.Bit-exact. The whole pipeline matches Optuna bit-for-bit:
_filter_inf, the ideal-point subtraction, the ASFeinsum/argmin extreme-point pick, the reference-point association (numpy's 4-operandeinsumreplicated term-by-term, verified bit-identical over 2000 cases; its twonp.linalg.norm(axis=...)calls and the axisargmin/minrun through NumSharp, so the row sums take NumPy's pairwise order from eight objectives on — before 2026-11-11 they were left-to-right sums, exact only up to seven objectives), the niching, and — since 2.15 — the hyperplane fit itself: the degeneracy MatrixRank(double[,]) branch and the Solve(double[,], double[]) route through NumSharp'snp.linalg.matrix_rank/solveover the OpenBLAS LAPACK backend, which is byte-identical to NumPy (the earlier managed reciprocal-multiplier LU drifted ~1 ULP on a few percent of the extreme-point systems; the LAPACK route removes even that). Every RNG draw (rng.shuffle) stays in lock-step. Confirmed byte-for-byte over a 400-config differential (5 crossovers × {2,3,4} objectives × 25 seeds + 25 constrained); the many-objective regime (8 and 10 objectives) is pinned by the liveNsgaiiiSamplerParityTests.ManyObjectives_FullState_IsBitIdentical.