169 budget_h: float, share: list, grid_v: int = 2000,
170 grid_vbin: int = 20) -> list:
171 """The run_ensemble invocation(s) for this stage.
173 THE SHARD INDEX IS NOT THE REGISTRY INDEX. run_ensemble assigns a row with
174 `assign_machine(row_id, of) == row_id % of`, so with `--of 1` only
175 `--machine 0` is ever given any rows. Passing this host registry index
176 (2 for the workstation) with `--of 1` silently assigns it ZERO rows and the
177 run exits having done nothing. Shard index is therefore always the
178 position within the participating set, while the registry index is used
179 only to name the output file so two machines cannot collide.
181 design_rel =
"design/%s_calib.csv" % stage
183 def one(shard: int, of: int, reg_index: int, workers: int) -> list:
185 "python run_ensemble.py \\",
186 " --design %s \\" % design_rel,
187 " --conditions conditions_S8.json \\",
188 " --spec parameters_S4.json \\",
189 " --out results/%s_calib_machine%d.jsonl \\" % (stage, reg_index),
190 " --machine %d --of %d \\" % (shard, of),
191 " --equations bin_moment --i-discrete 100 --i-bin 36 \\",
192 " --v-discrete 5 --v-bin %d --allow-mixed \\" % grid_vbin,
193 " --I 80000 --V %d --dose 15.0 --lnl 1 --rtol 1e-5 \\" % grid_v,
194 " --solver-mode full_system \\",
195 " --timeout-s %d --workers %d --omp-threads 1"
196 % (int(budget_h * 3600), workers),
200 return one(0, 1, machine[
"index"], slots)
203 for shard, reg_index
in enumerate(share):
204 m = next(x
for x
in reg[
"machines"]
if x[
"index"] == reg_index)
205 lines.append(
"# shard %d/%d -- run this ON %s"
206 % (shard, len(share), m[
"name"]))
207 lines.extend(one(shard, len(share), reg_index, m.get(
"slots", 1)))
227def pick_levers(led: dict, worst: list, n_wanted: int = 3) -> tuple:
228 """Choose levers for the worst residual, honouring the ledger verdicts."""
230 for name, L
in led[
"levers"].items():
231 for c
in L[
"columns"]:
237 rank = {
"live": 3,
"inconclusive": 2,
"dead": 1}
238 if cur
is None or rank[L[
"verdict"]] > rank[cur]:
239 verdict[c] = L[
"verdict"]
240 never = set(led.get(
"untested_columns")
or [])
241 unwired = set(((led.get(
"policy")
or {}).get(
"unwired_parameters")
or {}))
249 if v ==
"inconclusive":
255 params = (led.get(
"best")
or {}).get(
"params")
or {}
256 ratios = led.get(
"residuals")
or {}
257 chosen, why, skipped = [], [], []
258 for obs, miss
in worst:
259 for col
in LEVER_MAP.get(obs, []):
260 if col
in chosen
or priority(col) == 99:
262 if col
not in PRIOR_BOX:
265 base = float(params.get(col))
266 except (TypeError, ValueError):
267 base = sum(PRIOR_BOX[col][:2]) / 2.0
270 if span < MIN_USABLE_SPAN:
271 skipped.append((col, obs, span))
274 why.append((col, obs, miss, priority(col)))
275 if len(chosen) >= n_wanted:
276 return chosen, why, skipped
277 return chosen, why, skipped
281 """The prior box for `col`, clipped to the region measured as affordable.
283 THE CLIFF LOCATION IS UNKNOWN. S14 shows E_b_i2 = 0.60 never reaches dose
284 and 0.75 always does; the boundary is somewhere in between and nothing
285 measures where. Placing a design point inside that unresolved interval is
286 a coin flip that costs a full row budget when it loses, so the box is
287 clipped to the nearest value KNOWN to complete -- not to just above the
290 lo, hi, kind = PRIOR_BOX[col]
291 vlo, vhi = VALIDITY_BOX.get(col, (
None,
None))
296 rec = (led.get(
"affordability")
or {}).get(col)
299 bad = rec.get(
"unaffordable_numeric")
or []
300 good = rec.get(
"affordable_numeric")
or []
301 below = [u
for u
in bad
if u < base]
302 above = [u
for u
in bad
if u > base]
304 safe = [g
for g
in good
if g > max(below)]
305 lo = max(lo, min(safe)
if safe
else max(below))
307 safe = [g
for g
in good
if g < min(above)]
308 hi = min(hi, max(safe)
if safe
else min(above))
329def levels_for(col: str, base: float, n: int, prefer: int = 0,
331 """n levels for `col`, spanning the prior box.
333 `prefer` is the corrective direction: -1 sweeps from the box floor up to
334 the base, +1 from the base up to the ceiling, 0 spans the whole box. The
335 base is always one of the endpoints when prefer != 0, so the stage stays
336 anchored to the point already known to be grid-clean.
338 lo, hi, kind = box
or PRIOR_BOX[col]
339 base = min(max(base, lo), hi)
345 lo, hi, _ = box
or PRIOR_BOX[col]
346 if kind ==
"log" and lo > 0:
347 a, b = math.log10(lo), math.log10(hi)
348 vals = [10 ** (a + (b - a) * i / (n - 1))
for i
in range(n)]
350 vals = [lo + (hi - lo) * i / (n - 1)
for i
in range(n)]
351 if col
in INTEGER_LEVERS:
355 vals = sorted({int(round(v))
for v
in vals})
370 """--box i_mobile=5:32 -> {"i_mobile": (5.0, 32.0)}."""
372 for part
in (spec
or "").split(
","):
376 col, _, rng = part.partition(
"=")
377 lo, _, hi = rng.partition(
":")
379 if col
not in PRIOR_BOX:
380 raise SystemExit(
"--box %s: unknown lever (not in PRIOR_BOX)" % col)
382 out[col] = (float(lo), float(hi))
384 raise SystemExit(
"--box %s: expected lever=lo:hi" % part)
385 if out[col][0] >= out[col][1]:
386 raise SystemExit(
"--box %s: lo must be < hi" % part)
391 row_base: int, why: list =
None, box_override: dict =
None) -> tuple:
394 raise SystemExit(
"ledger has no valid best row -- nothing safe to pin to")
395 params = dict(best[
"params"])
396 target_obs = {c: o
for c, o, _, _
in (why
or [])}
397 ratios = led.get(
"residuals")
or {}
400 for col, n
in zip(levers, n_levels):
402 base = float(params.get(col))
403 except (TypeError, ValueError):
404 base = sum(PRIOR_BOX[col][:2]) / 2.0
405 obs = target_obs.get(col)
406 lo, hi, kind =
box_for(col, led, base)
407 ov = (box_override
or {}).get(col)
413 lo, hi = max(lo, ov[0]), min(hi, ov[1])
416 "--box %s=%g:%g leaves nothing after intersecting the "
417 "admissible span (%g, %g) for that lever."
418 % (col, ov[0], ov[1], *
box_for(col, led, base)[:2]))
425 combos = [c + [v]
for c
in combos
for v
in g]
427 header = [
"row_id",
"condition",
"cond_row_id",
"matrix",
"base_idx",
428 "param_j",
"theta_id"] + [k
for k
in params
if k
not in BOOKKEEPING]
429 rows, labels = [], {}
430 for i, combo
in enumerate(combos):
432 rec = {
"row_id": rid,
"condition": best.get(
"condition")
or "S330",
433 "cond_row_id": rid,
"matrix":
"S",
"base_idx": i,
434 "param_j": -1,
"theta_id": i}
438 for col, v
in zip(levers, combo):
439 if col
in INTEGER_COLS:
441 rec[col] = repr(v)
if isinstance(v, float)
else v
442 tag.append(
"%s%.3g" % (col.replace(
"_",
""), v))
444 labels[str(rid)] =
"%s%02d_%s" % (stage, i,
"_".join(tag))
445 return header, rows, labels
499 ap = argparse.ArgumentParser(description=
"Propose the next calibration stage.")
500 ap.add_argument(
"--machine", type=int, default=
None)
501 ap.add_argument(
"--stage", default=
None)
502 ap.add_argument(
"--levers", default=
None,
503 help=
"comma-separated override, e.g. eta,f_cl_i,E_b_i2")
504 ap.add_argument(
"--for", dest=
"for_obs", default=
None,
505 help=
"observable an explicit --levers override is aimed at, "
506 "e.g. --for N_void; without it the sweep is symmetric "
507 "because the corrective direction is unknown")
508 ap.add_argument(
"--levels", default=
None,
509 help=
"comma-separated level count per lever, e.g. 3,2,2")
510 ap.add_argument(
"--row-base", type=int, default=
None)
511 ap.add_argument(
"--box", default=
None,
512 help=
"narrow a lever's box for this stage only, e.g. "
513 "--box gamma_s=1.5:1.8. Use to target a region a "
514 "sibling stage does not cover, instead of duplicating "
515 "it. Clamps into PRIOR_BOX; never widens past it.")
516 ap.add_argument(
"--grid-v", type=int, default=2000,
517 help=
"max vacancy cluster size (--V). Raise for cavity "
518 "stages: at V=2000 every setting that grows realistic "
519 "cavities hits the ceiling and returns GRID+NOCONV.")
520 ap.add_argument(
"--grid-vbin", type=int, default=20,
521 help=
"vacancy bin count. Scale with --grid-v to hold the "
522 "bin ratio: r = (V/v_discrete)^(1/v_bin), which is "
523 "1.349 at the V=2000/v_bin=20 default.")
524 ap.add_argument(
"--budget-h", type=float, default=
None,
525 help=
"row budget in hours; overrides machines.json")
526 ap.add_argument(
"--share", default=
None,
527 help=
"split this design across registry machine indices, "
528 "e.g. --share 0,2 for MacBook Pro + workstation")
529 ap.add_argument(
"--write", action=
"store_true",
530 help=
"write the design files and update the ledger/guide")
531 a = ap.parse_args(argv)
535 for item
in a.box.split(
","):
536 col, rng = item.split(
"=")
537 lo, hi = (float(x)
for x
in rng.split(
":"))
539 if col
not in PRIOR_BOX:
540 raise SystemExit(
"--box names unknown lever %r" % col)
541 plo, phi, kind = PRIOR_BOX[col]
544 PRIOR_BOX[col] = (max(lo, plo), min(hi, phi), kind)
545 print(
"box override: %s -> %.4g .. %.4g"
546 % (col, PRIOR_BOX[col][0], PRIOR_BOX[col][1]))
547 machine, reg =
detect(a.machine)
551 levers = [s.strip()
for s
in a.levers.split(
",")
if s.strip()]
555 unwired = ((led.get(
"policy")
or {}).get(
"unwired_parameters")
or {})
556 bad = [c
for c
in levers
if c
in unwired]
559 print(
"REFUSING --levers %s: the physics never reads it." % c)
560 print(
" %s" % unwired[c])
562 tgt = a.for_obs
or "operator override"
563 why = [(c, tgt, 0.0, -1)
for c
in levers]
568 raise SystemExit(
"no admissible levers -- every candidate is dead in "
569 "the ledger. Widen LEVER_MAP or PRIOR_BOX.")
571 slots = machine.get(
"slots", 1)
573 n_levels = [int(x)
for x
in a.levels.split(
",")]
576 n_levels = [2] * len(levers)
577 while math.prod(n_levels) * 3 // 2 <= slots
and max(n_levels) < 4:
578 n_levels[n_levels.index(min(n_levels))] += 1
579 n_rows = math.prod(n_levels)
585 nums = [int(s[1:].split(
"_")[0])
for s
in led[
"stages"]
586 if s.startswith(
"S")
and s[1:].split(
"_")[0].isdigit()]
587 stage =
"S%d" % ((max(nums)
if nums
else 14) + 1)
588 row_base = a.row_base
if a.row_base
is not None else 4000 + \
589 (int(stage[1:]) - 10) * 100
591 header, rows, labels =
build_design(led, levers, n_levels, stage, row_base,
593 share = [int(x)
for x
in a.share.split(
",")]
if a.share
else []
595 math.ceil(n_rows / len(share))
if share
else n_rows)
598 budget_h, budget_src = a.budget_h,
"--budget-h"
599 elif machine.get(
"timeout_s"):
600 budget_h, budget_src = machine[
"timeout_s"] / 3600.0,
"machines.json (this machine)"
601 elif reg.get(
"timeout_s"):
602 budget_h, budget_src = reg[
"timeout_s"] / 3600.0,
"machines.json (global default)"
604 budget_h, budget_src = 20.0,
"built-in fallback"
605 over = (cost.get(
"known")
and budget_h
and cost[
"max_row_h"] > budget_h)
608 print(
"machine : %d %s (%d slots)" % (machine[
"index"], machine[
"name"], slots))
609 print(
"pinned to : %s (%s, %d/6 in range)"
610 % (b[
"label"]
or b[
"row_id"], b[
"stage"], b[
"n_in_range"]))
611 print(
"worst residuals:")
612 for k, m
in worst[:4]:
613 print(
" %-7s %8.4gx off (log10 = %.2f)" % (k, led[
"residuals"][k], m))
614 for k, m
in deferred:
615 print(
" %-7s %8.4gx off (log10 = %.2f) DEFERRED by policy"
616 % (k, led[
"residuals"][k], m))
617 print(
"levers chosen :")
618 tagname = {-1:
"operator override", 0:
"never varied",
619 1:
"inconclusive", 2:
"live"}
620 for col, obs, miss, pr
in why:
621 lv = next((n
for c, n
in zip(levers, n_levels)
if c == col),
"?")
622 print(
" %-12s %-2s levels for %-7s [%s]"
623 % (col, lv, obs, tagname.get(pr,
"?")))
624 for col, obs, span
in skipped:
625 print(
" %-12s SKIPPED for %-7s -- only %.0f%% of its box is "
626 "affordable in the corrective direction" % (col, obs, span * 100))
627 print(
"design : %s, %d rows (%s)"
628 % (stage, n_rows,
" x ".join(str(n)
for n
in n_levels)))
629 if cost.get(
"known"):
630 print(
"est. cost : %.1f h wall (%d wave(s) x %.1f h worst row, %s)"
631 % (cost[
"est_wall_h"], cost[
"waves"], cost[
"max_row_h"], cost[
"source"]))
633 print(
"sharded across : %s"
634 %
", ".join(
"%d=%s" % (i, next(m[
"name"]
for m
in reg[
"machines"]
635 if m[
"index"] == i))
for i
in share))
636 print(
"row budget : %.1f h (from %s)%s"
637 % (budget_h, budget_src,
" *** EXCEEDED ***" if over
else ""))
641 print(
"REFUSING to recommend as-is: the worst measured row (%.1f h) exceeds "
642 "the row budget (%.1f h)." % (cost[
"max_row_h"], budget_h))
643 print(
"Either pass --budget-h, raise timeout_s for machine %d in "
644 "machines.json, or cut the design with --levels."
648 design_rel =
"design/%s_calib.csv" % stage
649 labels_rel =
"design/%s_labels.json" % stage
651 a.grid_v, a.grid_vbin)
654 print(
"DRY RUN -- nothing written. Re-run with --write to emit:")
655 print(
" %s (%d rows)" % (design_rel, n_rows))
656 print(
" %s" % labels_rel)
659 print(
"\n".join(cmd))
662 dpath = HERE / design_rel
663 with dpath.open(
"w", newline=
"", encoding=
"utf-8")
as fh:
664 w = csv.DictWriter(fh, fieldnames=header)
668 (HERE / labels_rel).write_text(json.dumps(labels, indent=1), encoding=
"utf-8")
672 "machine": machine[
"index"],
"machine_name": machine[
"name"],
673 "levers": levers,
"n_levels": n_levels,
"n_rows": n_rows,
674 "design": design_rel,
"labels": labels_rel,
675 "pinned_to": {
"stage": b[
"stage"],
"row_id": b[
"row_id"],
676 "label": b[
"label"]},
677 "rationale": (
"worst residuals are %s; sweeping %s, which the ledger "
678 "has not retired" % (
679 ", ".join(
"%s (%.3gx)" % (k, led[
"residuals"][k])
680 for k, _
in worst[:3]),
682 "cost_estimate": cost,
689 led.setdefault(
"next_by_machine", {})[str(machine[
"index"])] = claim
691 LEDGER.write_text(json.dumps(led, indent=2), encoding=
"utf-8")
693 sys.path.insert(0, str(HERE))
698 print(
"wrote %s (%d rows), %s" % (design_rel, n_rows, labels_rel))
699 print(
"updated calibration_ledger.json[next] and CALIBRATION_GUIDE.md")
701 print(
"Review the design, then run:")
702 print(
"\n".join(cmd))
list build_commands(str stage, dict machine, dict reg, int slots, float budget_h, list share, int grid_v=2000, int grid_vbin=20)
tuple build_design(dict led, list levers, list n_levels, str stage, int row_base, list why=None, dict box_override=None)