from __future__ import annotations
import argparse
import json
import math
import sys
from pathlib import Path
ROOT = Path(__file__).resolve().parents[3]
FREEZE_JSON = ROOT / "paper" / "cpc" / "freeze" / "ase_fair_campaign_1.json"
OUT = (
ROOT / "paper" / "cpc" / "src" / "figures" / "generated" / "fair_campaign_table.tex"
)
HEADER = (
"% Auto-generated by paper/cpc/scripts/gen_fair_table.py -- do not edit by hand.\n"
)
EXPECTED_LADDER = [10, 50, 100, 200, 500]
def _load(path: Path) -> dict:
return json.loads(path.read_text())
def _sci_tex(value: float) -> str:
if value == 0 or not math.isfinite(value):
return "$0$"
exp = int(math.floor(math.log10(abs(value))))
mant = value / (10**exp)
return f"${mant:.2f}\\times 10^{{{exp}}}$"
def _sec3(value: float) -> str:
return f"${value:.3f}$"
def validate(payload: dict) -> list[str]:
errors: list[str] = []
if payload.get("fair") is not True:
errors.append("freeze payload must set fair=true")
if payload.get("ladder") != EXPECTED_LADDER:
errors.append(f"ladder {payload.get('ladder')!r} != {EXPECTED_LADDER}")
if payload.get("all_competitive_selects_agree") is not True:
errors.append("all_competitive_selects_agree is not true")
for key in ("host", "date_utc", "commit"):
if not payload.get(key):
errors.append(f"freeze JSON missing {key}")
fixture = str(payload.get("fixture", ""))
if "tiny_cuh2.con" not in fixture:
errors.append(f"fixture is not tiny_cuh2.con: {fixture!r}")
for row in payload.get("select_parity", []):
for key in ("symbol_Cu_agree", "natoms_agree", "mass_agree", "volume_agree"):
if not row.get(key):
errors.append(f"n={row.get('n_frames')}: {key} is false")
by_n_rdb = {r["n_frames"]: r for r in payload.get("readcon_db", [])}
by_n_ase = {r["n_frames"]: r for r in payload.get("ase_db", [])}
for n in EXPECTED_LADDER:
if n not in by_n_rdb or n not in by_n_ase:
errors.append(f"missing store row for N={n}")
return errors
def gen_table(payload: dict) -> str:
by_n_rdb = {r["n_frames"]: r for r in payload["readcon_db"]}
by_n_ase = {r["n_frames"]: r for r in payload["ase_db"]}
par = {r["n_frames"]: r for r in payload["select_parity"]}
rows = []
for n in payload["ladder"]:
r, a, p = by_n_rdb[n], by_n_ase[n], par[n]
agree = (
p["symbol_Cu_agree"]
and p["natoms_agree"]
and p.get("mass_agree", True)
and p.get("volume_agree", True)
)
rows.append(
" {n} & {ri} & {ai} & {re} & {ae} & {rsc} & {asc} & {r8} & {a8} & {ag} \\\\".format(
n=n,
ri=_sci_tex(float(r["insert_frames_per_s"] or 0)),
ai=_sci_tex(float(a["insert_frames_per_s"] or 0)),
re=_sci_tex(float(r["extract_frames_per_s"] or 0)),
ae=_sci_tex(float(a["extract_frames_per_s"] or 0)),
rsc=_sci_tex(float(r["select_cu_mean_s"])),
asc=_sci_tex(float(a["select_cu_mean_s"])),
r8=_sec3(float(r["concurrent_8readers_extract_s"])),
a8=_sec3(float(a["concurrent_8readers_extract_s"])),
ag="yes" if agree else "NO",
)
)
body = "\n".join(rows)
host = payload["host"]
date_utc = payload["date_utc"]
commit = payload["commit"]
return rf"""\begin{{table}}[ht]
\centering
\caption{{Fair campaign-store comparison on a concatenated
\texttt{{tiny\_cuh2.con}} ladder
(\texttt{{paper/cpc/freeze/ase\_fair\_campaign\_1.json}},
{date_utc}, host \texttt{{{host}}}, tree \texttt{{{commit}}}).
The same CON frames enter both stores. Insert and extract are
frames per second; Cu select and eight-reader extract are wall
seconds. Hit counts agree on symbol, natoms, mass, and volume.
This table is companion appendix material. It is not a main-claim
parse timing and not the legacy Cu2 unequal-workload bench.}}
\label{{tab:fair-campaign}}
\scriptsize
\begin{{tabular}}{{@{{}}r *{{8}}{{r}} l@{{}}}}
\toprule
$N$ & rdb ins/s & ASE ins/s & rdb ext/s & ASE ext/s & rdb Cu (s) & ASE Cu (s) & rdb$_8$ (s) & ASE$_8$ (s) & hits \\
\midrule
{body}
\bottomrule
\end{{tabular}}
\end{{table}}
"""
def main() -> int:
ap = argparse.ArgumentParser()
ap.add_argument(
"--check",
action="store_true",
help="require generated tex to match the committed file",
)
args = ap.parse_args()
payload = _load(FREEZE_JSON)
errors = validate(payload)
if errors:
print("freeze payload rejected:", file=sys.stderr)
for err in errors:
print(f" {err}", file=sys.stderr)
return 1
text = HEADER + gen_table(payload)
if args.check:
if not OUT.is_file():
print(f"missing committed table: {OUT}", file=sys.stderr)
return 1
if OUT.read_text() != text:
print(f"generated table differs from {OUT}", file=sys.stderr)
return 1
print(f"ok freeze table matches {OUT.relative_to(ROOT)}")
return 0
OUT.parent.mkdir(parents=True, exist_ok=True)
OUT.write_text(text)
print(f"wrote {OUT.relative_to(ROOT)}")
return 0
if __name__ == "__main__":
raise SystemExit(main())