SPB Git

spb/wp34_uqo

Public
6.5 KB · 96 lines python
1"""Hypothesis registry: parses hypotheses/H*.md (YAML front matter), validates required fields, optionally executes the2linked verification commands, and emits research_log/discovery_log.jsonl + paper/tables/hypotheses.tex.34Front matter schema (all required):5  id, title, axis (A|B|C|D), kind (algebraic|algorithmic|sha256|methodology|formal), statement, motivation, assumptions,6  expected_contribution, related_work (list of bib keys), possible_counterexamples, verification_strategy,7  computational_budget, status (planned|running|evaluated), classification (new_verified|known_reproduced|conditional|8  empirical_observation|rejected|unresolved|pending), evidence (list of result files), verdict (one sentence).9"""10import argparse, datetime, json, pathlib, re, subprocess, sys11import yaml12ROOT = pathlib.Path(__file__).resolve().parents[2]13REQ = ["id", "title", "axis", "kind", "statement", "motivation", "assumptions", "expected_contribution", "related_work",14       "possible_counterexamples", "verification_strategy", "computational_budget", "status", "classification", "evidence", "verdict"]15CLASSES = {"new_verified", "known_reproduced", "conditional", "empirical_observation", "rejected", "unresolved", "pending"}16LABEL = {"new_verified": "New verified result", "known_reproduced": "Known result reproduced", "conditional": "Conditional result",17         "empirical_observation": "Empirical observation", "rejected": "Rejected conjecture", "unresolved": "Unresolved direction", "pending": "Pending"}181920def load():21    hyps = []22    for f in sorted((ROOT / "hypotheses").glob("H*.md")):23        txt = f.read_text()24        m = re.match(r"^---\n(.*?)\n---\n(.*)$", txt, re.S)25        if not m:26            raise SystemExit(f"{f}: missing front matter")27        meta = yaml.safe_load(m.group(1)); meta["body"] = m.group(2).strip(); meta["file"] = f.name28        missing = [k for k in REQ if k not in meta]29        if missing:30            raise SystemExit(f"{f}: missing fields {missing}")31        if meta["classification"] not in CLASSES:32            raise SystemExit(f"{f}: bad classification {meta['classification']}")33        for ev in meta["evidence"]:34            if not (ROOT / ev).exists():35                print(f"WARNING {f.name}: evidence file missing: {ev}")36        hyps.append(meta)37    return hyps383940def tex_escape(s: str) -> str:41    s = s.replace("π̄", r"$\bar\pi$").replace("\u0304", "").replace("^", r"\^{}").replace("~", r"\textasciitilde{}")42    for a, b in [("&", r"\&"), ("%", r"\%"), ("_", r"\_"), ("#", r"\#"), ("√", r"$\surd$"), ("≈", r"$\approx$"), ("≤", r"$\le$"), ("≥", r"$\ge$"),43                 ("→", r"$\to$"), ("⟹", r"$\Rightarrow$"), ("×", r"$\times$"), ("²", r"$^2$"), ("³", r"$^3$"), ("Ω", r"$\Omega$"), ("φ", r"$\varphi$"), ("λ", r"$\lambda$"),44                 ("β", r"$\beta$"), ("Σ", r"$\Sigma$"), ("σ", r"$\sigma$"), ("δ", r"$\delta$"), ("π", r"$\pi$"), ("ω", r"$\omega$"), ("χ", r"$\chi$"), ("α", r"$\alpha$"),45                 ("−", "--"), ("–", "--"), ("—", "---"), ("·", r"$\cdot$"), ("∈", r"$\in$"), ("⊕", r"$\oplus$"), ("≡", r"$\equiv$"), ("∞", r"$\infty$"), ("ℓ", r"$\ell$"),46                 ("ε", r"$\varepsilon$"), ("≠", r"$\ne$"), ("∘", r"$\circ$"), ("‖", r"$\|$"), ("⁻¹", r"$^{-1}$"), ("⁻⁴", r"$^{-4}$"), ("⁻⁵", r"$^{-5}$"), ("⁴", r"$^4$"), ("⁵", r"$^5$"),47                 ("₀", r"$_0$"), ("₁", r"$_1$"), ("₂", r"$_2$"), ("±", r"$\pm$"), ("…", r"\ldots{}"), ("µ", r"$\mu$"), ("•", r"$\cdot$"), ("≫", r"$\gg$"), ("≪", r"$\ll$"), ("′", "'"), ("ô", "\\^o"), ("Ø", "O")]:48        s = s.replace(a, b)49    greek = {"θ": "theta", "γ": "gamma", "μ": "mu", "ν": "nu", "ρ": "rho", "τ": "tau", "κ": "kappa", "η": "eta", "ζ": "zeta", "ξ": "xi", "ψ": "psi", "Δ": "Delta", "Γ": "Gamma", "Θ": "Theta", "Λ": "Lambda", "Π": "Pi", "Φ": "Phi", "Ψ": "Psi"}50    for a, b in greek.items():51        s = s.replace(a, "$\\" + b + "$")52    bad = sorted({c for c in s if ord(c) > 127 and c not in "éèàçêôûîïüöäñÉÈ"})53    if bad:54        print("WARNING tex_escape: unmapped characters", bad)55    return s565758def main():59    ap = argparse.ArgumentParser(); ap.add_argument("--run", action="store_true", help="execute verification commands in front matter `commands`")60    a = ap.parse_args()61    hyps = load()62    counts = {}63    for h in hyps:64        counts[h["kind"]] = counts.get(h["kind"], 0) + 165    log = ROOT / "research_log/discovery_log.jsonl"66    with log.open("w") as fh:67        for h in hyps:68            if a.run and h.get("commands"):69                for cmd in h["commands"]:70                    print(f"[{h['id']}] $ {cmd}")71                    subprocess.run(cmd, shell=True, check=True, cwd=ROOT)72            fh.write(json.dumps({"id": h["id"], "title": h["title"], "axis": h["axis"], "kind": h["kind"], "status": h["status"],73                                 "classification": h["classification"], "verdict": h["verdict"], "evidence": h["evidence"],74                                 "logged_utc": datetime.datetime.now(datetime.timezone.utc).isoformat(timespec="seconds")}) + "\n")75    # LaTeX table (longtable) for the paper76    rows = []77    for h in hyps:78        rows.append(f"{h['id']} & {h['axis']} & {tex_escape(h['title'])} & {LABEL[h['classification']]} & {tex_escape(h['verdict'])} \\\\")79    tex = ["% generated by experiments/automated_discovery/registry.py — do not edit",80           r"\begin{longtable}{@{}p{0.8cm}p{0.5cm}p{4.2cm}p{2.6cm}p{6.4cm}@{}}",81           r"\caption{Hypothesis portfolio and evaluation outcome. Classification vocabulary follows the mandate (new verified result; known result independently reproduced; conditional result; empirical observation; rejected conjecture; unresolved direction).}\label{tab:hypotheses}\\",82           r"\toprule ID & Axis & Hypothesis & Classification & Verdict \\ \midrule \endfirsthead",83           r"\toprule ID & Axis & Hypothesis & Classification & Verdict \\ \midrule \endhead",84           r"\bottomrule \endfoot"] + rows + [r"\end{longtable}"]85    (ROOT / "paper/tables").mkdir(exist_ok=True, parents=True)86    (ROOT / "paper/tables/hypotheses.tex").write_text("\n".join(tex) + "\n")87    summary = {"n_hypotheses": len(hyps), "by_kind": counts,88               "by_classification": {c: sum(1 for h in hyps if h["classification"] == c) for c in CLASSES}}89    (ROOT / "results/automated_discovery").mkdir(exist_ok=True, parents=True)90    (ROOT / "results/automated_discovery/hypothesis_summary.json").write_text(json.dumps(summary, indent=1))91    print(json.dumps(summary, indent=1))929394if __name__ == "__main__":95    main()96
Files · main
Menu

Theme