Skip to content

fix: gate NSGA feasibility at the pool median instead of the 75th percentile - #19

Merged
rasros merged 1 commit into
mainfrom
tune-feasibility-gate
Jul 28, 2026
Merged

fix: gate NSGA feasibility at the pool median instead of the 75th percentile#19
rasros merged 1 commit into
mainfrom
tune-feasibility-gate

Conversation

@rasros

@rasros rasros commented Jul 28, 2026

Copy link
Copy Markdown
Owner

Settles the doc/code split over the constraint-first score gate. The README claimed the gate treated the top 25% by visual error as feasible; _percentile_75 actually admitted roughly the best 75% — measured, 7 of 10 candidates. Neither number survives.

Picking 25% looked like the obvious reading of the intent, and it is wrong. Measured over the real select_parent, moving the gate from 75% to 25% buys almost nothing, because with a tiny feasible group most binary-tournament comparisons are between two infeasible candidates, where the gate contributes nothing and three-objective dominance is already weak. At the loose end the gate barely filters. Splitting at the median maximises the share of comparisons the gate actually decides, and it measures better than either extreme.

Through the real select_parent, share of parents drawn from the better-scoring half of a 20-node pool:

gate 75% (old): 74.4%
gate 50% (new): 81.2%

_percentile_75 becomes _feasibility_threshold, with the fraction as a named FEASIBLE_FRACTION constant — the old name hardcoded a percentile into the identifier, so it could not survive changing the fraction. Both call sites (select_parent, epoch_seeds) pick the change up, so parent selection and epoch re-seeding stay consistent.

Tests now pin the property rather than the arithmetic: that the gate admits exactly FEASIBLE_FRACTION of the pool, that the admitted set is the best-scoring prefix rather than an arbitrary subset, and that the gate is scale-free (a quantile of the pool, not a fixed error value — it must behave the same for errors around 0.001 and around 1000).

README: the gate's fraction is now named instead of left vague, with the reasoning for the median split recorded since it is not self-evident. Two other corrections in that section. The extensibility claim read "adding a fourth objective is a matter of extending the vector", which overstated things — only the algorithm is arity-agnostic; a new measure still has to be threaded through the worker, node model, and run artifacts, and the text now says so. And it now warns that dominance dilutes as objectives multiply, with the measured first-front growth (8 nodes at three objectives to 11 at five on a 12-node pool) as the reason to be sparing.

Two caveats I could not settle here. The percentages come from uncorrelated synthetic objectives; in a real run score and complexity correlate and the pool is the survivor set of prior selection, so the ranking of options should hold but the magnitudes will not. And sharper selection is not automatically better output — it converges faster and raises premature-convergence risk, which feeds into the --epoch-diversity transitions. Confirming the end-to-end effect needs a real search; a local LLM-free sweep is possible and is the obvious follow-up.

Not changed here: tournament size is still hardcoded at 2, and it is the larger lever — at the existing gate, raising it to 4 moved score primacy from 76% to 91% in simulation. Left alone deliberately, since it is a behavioural change nobody asked for yet.

402 passed, 13 skipped, ruff clean.

@rasros
rasros merged commit c838a23 into main Jul 28, 2026
1 check passed
@rasros
rasros deleted the tune-feasibility-gate branch July 28, 2026 15:33
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant