Re-ran the §13.1/§13.2-style per-leaf fail-breakdown diagnostic on real driver.search_staged runs (budget 20000, seeds 0-2, harbor-house and maple-court) under the current full default stack (leaf-sharing x3, depth-balanced, interior-O, share-aware edge cap) -- never decomposed by category since those defaults were flipped on. Finding: crinkliness (48%) and size (20.6%) now dominate the residual on both programmes (~69% combined); construction-completeness fails (missing space, adjacency, level, connectivity) are down to a small tail (<=6% each). This revises erc.1's old recommendation to deprioritise compactness-cuts in favour of leaf-sharing -- leaf-sharing is now fully deployed and crinkliness is proportionally more dominant than ever, so DESIGN.md §13.11 recommends reopening a compactness/crinkliness-targeted construction lever as the next concrete step. Also files two bugs found while validating the methodology: dumping and reloading a .dom under leaf_sharing+collapse_insearch does not reproduce the search's own in-process fail count (homemaker-py-iio), and run_staged_search.py's own sanity rescore omits the collapse_insearch override (homemaker-py-7ua). experiments/run_and_capture_91f.py sidesteps this by capturing the true in-process fails list instead of rescoring from disk; experiments/diag_residual_91f.py tallies fail categories from those sidecars. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01R8agJBT2ZpmF3ErW7wi2wY
74 lines
2.7 KiB
Python
74 lines
2.7 KiB
Python
#!/usr/bin/env python3
|
|
"""homemaker-py-91f support script: run the §13.9 full-default-stack staged
|
|
search and capture the TRUE in-process fail list (not a post-hoc rescore).
|
|
|
|
Investigation finding (see bd issue filed alongside 91f): reloading a
|
|
dumped .dom and rescoring it with matching leaf_sharing/collapse_insearch
|
|
conf does NOT reliably reproduce driver.search_staged's own reported
|
|
n_fails once collapse_insearch's cell-relabelling is doing real work --
|
|
scoring `copy.deepcopy(r.best.root)` immediately in-process (before any
|
|
dom.dump/dom.load round trip) DOES reliably reproduce it (verified: exact
|
|
match across 5 repeats and against the live search's own log). So this
|
|
script never rescores from disk -- it captures the fails list right off
|
|
the in-memory search result, and only dumps the .dom for reference.
|
|
|
|
Usage:
|
|
python3 experiments/run_and_capture_91f.py <programme> <seed> <outdir>
|
|
"""
|
|
from __future__ import annotations
|
|
|
|
import copy
|
|
import json
|
|
import sys
|
|
import time
|
|
from pathlib import Path
|
|
|
|
sys.path.insert(0, str(Path(__file__).resolve().parents[1] / "src"))
|
|
from homemaker_layout import dom, driver, fitness # noqa: E402
|
|
|
|
ROOT = Path(__file__).resolve().parents[1]
|
|
OVERRIDES = {"leaf_sharing": True, "share_edge_cap": True, "collapse_insearch": True}
|
|
|
|
|
|
def main() -> int:
|
|
prog = sys.argv[1]
|
|
seed = int(sys.argv[2])
|
|
outdir = Path(sys.argv[3])
|
|
outdir.mkdir(parents=True, exist_ok=True)
|
|
|
|
pdir = ROOT / "examples" / prog
|
|
seed_root = dom.load(str(pdir / "init.dom"))
|
|
|
|
t0 = time.perf_counter()
|
|
r = driver.search_staged(
|
|
seed_root, pdir, budget=20000, pop_size=16, child_budget=80,
|
|
seed_budget=300, stage1_frac=0.4, base_p=0.15, p_crossover=0.2,
|
|
seed=seed, n_workers=1,
|
|
leaf_sharing=True, leaf_share_factor=3,
|
|
depth_balanced=True, interior_outside=True, outside_divisor=3,
|
|
)
|
|
elapsed = time.perf_counter() - t0
|
|
|
|
conf, cost = fitness.load_config(pdir, overrides=OVERRIDES)
|
|
fit = fitness.Fitness(conf, cost)
|
|
score, fails = fit.score_with_fails(copy.deepcopy(r.best.root))
|
|
|
|
match = (len(fails) == r.best.n_fails)
|
|
print(f"{prog} seed={seed}: elapsed={elapsed:.1f}s search_n_fails="
|
|
f"{r.best.n_fails} in_process_rescore_n_fails={len(fails)} "
|
|
f"match={match}", file=sys.stderr)
|
|
|
|
dom.dump(r.best.root, str(outdir / f"{prog}_s{seed}.dom"))
|
|
with open(outdir / f"{prog}_s{seed}.fails.json", "w") as fh:
|
|
json.dump({
|
|
"programme": prog, "seed": seed, "elapsed_s": elapsed,
|
|
"search_n_fails": r.best.n_fails, "search_fitness": r.best.fitness,
|
|
"rescore_n_fails": len(fails), "rescore_match": match,
|
|
"fails": fails,
|
|
}, fh, indent=2)
|
|
|
|
return 0 if match else 1
|
|
|
|
|
|
if __name__ == "__main__":
|
|
sys.exit(main())
|