Fix warm_x0 to honour operator-specified ratios on new splits

When a compound operator (e.g. level_compound_fix) creates a new
internal node and explicitly sets its division ratio, that ratio was
silently overridden: warm_x0 received parent.ratios which had no entry
for the new node, so Nelder-Mead started at the default 0.5 instead
of the operator's intended 0.25 (for rrl/rrr).  Result: NM evaluated
the compound topology at the wrong geometry and scored 3 fails instead
of 1 — so lex always rejected the compound child, making
level_compound_fix invisible to the outer search.

Fix: for nodes that are genuinely newly divided (not divided in the
parent tree at the same path), inherit the child's operator-set ratio
rather than defaulting to 0.5.  Structural mutations (e.g. swap) can
reveal hidden level-N nodes that retain stale pre-writeback ratios —
those are correctly excluded by checking parent_node.divided.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
Bruno Postle 2026-06-15 07:27:03 +01:00
parent d330a9171c
commit 65085d5c3d

View file

@ -251,7 +251,20 @@ def search(
child_root, desc = operators.mutate(parent.root, rng, types,
weights=_MUTATION_WEIGHTS,
reqs=reqs)
ratios = parent.ratios
# Carry operator-specified ratios for nodes that are genuinely
# newly divided (existed as leaves in the parent, are now
# divided in the child). Structural mutations (e.g. swap) can
# reveal previously-hidden nodes whose stale pre-writeback
# ratios must NOT be propagated — those default to 0.5.
parent_lvls = dom.levels(parent.root)
new_splits = {
(li, path): val
for (li, path), val in innerloop.ratio_map(child_root).items()
if li >= len(parent_lvls)
or not (pn := parent_lvls[li].by_id(path))
or not pn.divided
}
ratios = {**new_splits, **parent.ratios}
x0 = innerloop.warm_x0(child_root, ratios)
tasks.append((child_root, x0, child_budget, inner_kw, desc))
_run_batch(tasks)