Download scripts/build_reference_set.py from NicolasT08/formal-mas: direct link, hf CLI and curl.
- Browser
- Download file 5.54 kB
-
https://huggingface.co/NicolasT08/formal-mas/resolve/main/scripts/build_reference_set.py
- Command line
-
hf download hf://NicolasT08/formal-mas/scripts/build_reference_set.py
-
curl -L -o build_reference_set.py https://huggingface.co/NicolasT08/formal-mas/resolve/main/scripts/build_reference_set.py
5.54 kB
| """Build the retrieval reference set Q (Phase 1.2) from the pinned Mathlib environment. | |
| 1. Run scripts/extract_proof_consts.lean with `lake env lean` (offline data building, | |
| CLAUDE.md §7) over the project-area modules → data/index/proof_consts.jsonl (~8 min). | |
| 2. Derive gold lemmas, select ~200 balanced queries and split them 2/3 dev, 1/3 test. | |
| Outputs (data/retrieval_eval/): q_dev.jsonl, q_test.jsonl, infra_constants.json, meta.json. | |
| Also writes data/index/corpus_eval.jsonl: the corpus without the Q theorems, from which the | |
| evaluation index is built (the queries must not retrieve themselves). | |
| Usage: | |
| python scripts/build_reference_set.py [--size 200] [--seed 2026] [--skip-extract] | |
| """ | |
| from __future__ import annotations | |
| import argparse | |
| import json | |
| import os | |
| import subprocess | |
| import sys | |
| from datetime import datetime, timezone | |
| from pathlib import Path | |
| ROOT = Path(__file__).resolve().parents[1] | |
| sys.path.insert(0, str(ROOT / "src")) | |
| from formal_mas.retrieval.corpus import AREA_PREFIXES, SourceIndex, load_jsonl # noqa: E402 | |
| from formal_mas.retrieval.reference_set import ( # noqa: E402 | |
| PROJECT_AREAS, | |
| build_candidates, | |
| infrastructure, | |
| select, | |
| split, | |
| summary, | |
| ) | |
| EXTRACT_SCRIPT = ROOT / "scripts" / "extract_proof_consts.lean" | |
| def run_extraction(lean_project: Path, out: Path) -> None: | |
| """Dump proof-term constants of the project-area modules. Raises if Lean fails.""" | |
| out.parent.mkdir(parents=True, exist_ok=True) | |
| prefixes = sorted({p for area in PROJECT_AREAS for p in AREA_PREFIXES[area]}) | |
| env = {**os.environ, "FORMAL_MAS_CONSTS_OUT": str(out.resolve()), | |
| "FORMAL_MAS_MODULE_PREFIXES": ",".join(prefixes)} | |
| proc = subprocess.run( | |
| ["lake", "env", "lean", str(EXTRACT_SCRIPT)], cwd=lean_project, env=env, | |
| capture_output=True, text=True, encoding="utf-8", errors="replace", | |
| ) | |
| if proc.returncode != 0: | |
| raise subprocess.CalledProcessError(proc.returncode, proc.args, proc.stdout, proc.stderr) | |
| def write_jsonl(rows, path: Path) -> None: | |
| path.parent.mkdir(parents=True, exist_ok=True) | |
| with path.open("w", encoding="utf-8", newline="\n") as f: | |
| for r in rows: | |
| f.write(json.dumps(r, ensure_ascii=False) + "\n") | |
| def main(argv: list[str] | None = None) -> None: | |
| parser = argparse.ArgumentParser(description=__doc__.splitlines()[0]) | |
| parser.add_argument("--lean-project", type=Path, default=ROOT / "lean_project") | |
| parser.add_argument("--index-dir", type=Path, default=ROOT / "data" / "index") | |
| parser.add_argument("--out", type=Path, default=ROOT / "data" / "retrieval_eval") | |
| parser.add_argument("--size", type=int, default=200) | |
| parser.add_argument("--seed", type=int, default=2026) | |
| parser.add_argument("--infra-pct", type=float, default=1.0) | |
| parser.add_argument("--skip-extract", action="store_true", help="reuse proof_consts.jsonl") | |
| args = parser.parse_args(argv) | |
| consts_path = args.index_dir / "proof_consts.jsonl" | |
| if not args.skip_extract: | |
| run_extraction(args.lean_project, consts_path) | |
| corpus_rows = load_jsonl(args.index_dir / "corpus.jsonl") | |
| corpus = {r["name"]: r for r in corpus_rows} | |
| entries = load_jsonl(consts_path) | |
| # Population for infrastructure frequencies: hand-written theorems of the project areas. | |
| population = [e for e in entries | |
| if e["name"] in corpus and corpus[e["name"]]["origin"] == "manual" | |
| and corpus[e["name"]]["area"] in PROJECT_AREAS] | |
| infra = infrastructure(population, corpus, args.infra_pct) | |
| sources = SourceIndex(args.lean_project / ".lake" / "packages" / "mathlib") | |
| candidates = build_candidates(population, corpus, set(infra), sources) | |
| items = split(select(candidates, args.size, args.seed), args.seed) | |
| for part in ("dev", "test"): | |
| write_jsonl([q.to_json() for q in items if q.split == part], args.out / f"q_{part}.jsonl") | |
| (args.out / "infra_constants.json").write_text(json.dumps({ | |
| "threshold_pct": args.infra_pct, | |
| "population": len(population), | |
| "constants": [{"name": c, "pct": round(p, 3)} for c, p in infra.items()], | |
| }, indent=2, ensure_ascii=False), encoding="utf-8") | |
| excluded = {q.name for q in items} | |
| write_jsonl((r for r in corpus_rows if r["name"] not in excluded), args.index_dir / "corpus_eval.jsonl") | |
| cand_by = {a: {"concrete": sum(1 for q in candidates if q.area == a and q.concrete), | |
| "abstract": sum(1 for q in candidates if q.area == a and not q.concrete)} | |
| for a in PROJECT_AREAS} | |
| stats = summary(items) | |
| meta = { | |
| "created_utc": datetime.now(timezone.utc).isoformat(timespec="seconds"), | |
| "mathlib_commit": json.loads((args.index_dir / "corpus_meta.json").read_text(encoding="utf-8")).get("mathlib_commit"), | |
| "seed": args.seed, | |
| "size": args.size, | |
| "gold_method": "c: proof-term constants in corpus, minus Mathlib.Tactic and infrastructure, " | |
| "whose last name component is written in the proof (gold_b = method b)", | |
| "gold_range": [1, 10], | |
| "infra_pct": args.infra_pct, | |
| "population": len(population), | |
| "candidates": cand_by, | |
| "corpus_eval_size": len(corpus_rows) - len(excluded), | |
| "q": stats, | |
| } | |
| (args.out / "meta.json").write_text(json.dumps(meta, indent=2, ensure_ascii=False), encoding="utf-8") | |
| print(json.dumps({"candidates": cand_by, **stats}, indent=2, ensure_ascii=False)) | |
| if __name__ == "__main__": | |
| main() | |