(2) The proposed method is again the scheduled projection (2806/3220/6026), its budget multiplier DECLARED as the one free constant: the canonical total is the same for every multiplier 1.25-4, the wide-bracket one is not. The earned projection is the constant-free variant (3568/3020/6588). What the old tables hid: problem by problem the proposed rule beats Chandrupatla on the canonical set 87/24/42, exact sign test p = 9e-5, while trailing him by 0.7% in total; on the wide-bracket set he is genuinely stronger (26 to 9, p = 0.006). Gap decomposition recomputed with the library: 244 (was 262), 160 of it on the flat families (two thirds), fun1 58 (a quarter, not a third as the abstract said). Also corrected on the way: the 'subsumed by Chandrupatla' pin claimed he is better on the worst single problem - true only with the looser tolerance (84 against the credit rule's 83 once fixed); §8.3 still called zero slack degenerate, which Table 1a refutes; §5.2's Brent figure is our pure-Python implementation and now says so. verify_article.py 286/286, 802 tests pass twice. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
37 lines
1.5 KiB
Python
37 lines
1.5 KiB
Python
"""Which rows of sweep_full.json changed when the baselines moved to the library?
|
|
|
|
Only 'chandrupatla' and 'brent' may change: every configuration of ours and every
|
|
other baseline is deterministic and untouched by the switch, so any other difference
|
|
is a regression, not a consequence.
|
|
|
|
python -u diff_sweeps.py OLD.json NEW.json
|
|
"""
|
|
from __future__ import annotations
|
|
|
|
import json
|
|
import sys
|
|
|
|
|
|
def main(old_path, new_path):
|
|
old = {r["label"]: r for r in json.load(open(old_path, encoding="utf8"))}
|
|
new = {r["label"]: r for r in json.load(open(new_path, encoding="utf8"))}
|
|
print(f"rows: old {len(old)}, new {len(new)}; only in old: {sorted(set(old) - set(new))}"
|
|
f"; only in new: {sorted(set(new) - set(old))}")
|
|
changed = []
|
|
for lbl in sorted(set(old) & set(new)):
|
|
for s in ("APS", "CHA"):
|
|
if old[lbl][s]["per"] != new[lbl][s]["per"]:
|
|
changed.append((lbl, s, old[lbl][s]["total"], new[lbl][s]["total"],
|
|
old[lbl][s]["solved"], new[lbl][s]["solved"],
|
|
old[lbl][s]["over"], new[lbl][s]["over"]))
|
|
for c in changed:
|
|
print(f" CHANGED {c[0]:<14} {c[1]}: total {c[2]} -> {c[3]}, solved {c[4]} -> {c[5]}, "
|
|
f"over2x {c[6]} -> {c[7]}")
|
|
unexpected = [c for c in changed if c[0] not in ("chandrupatla", "brent")]
|
|
print(f"unexpected changes: {len(unexpected)}")
|
|
return changed, unexpected
|
|
|
|
|
|
if __name__ == "__main__":
|
|
main(sys.argv[1], sys.argv[2])
|