will702's picture
Upload folder using huggingface_hub
eab734a verified
Raw
History Blame Contribute Delete
3.76 kB
"""End-to-end orchestration: statement → IR → solve → TikZ → verify."""
from __future__ import annotations
import json
from pathlib import Path
from typing import Any
from statement_to_tikz.emit_tikz import emit_standalone_tex
from statement_to_tikz.formalize import formalize
from statement_to_tikz.ir import GeometryIR, SolveMode, SolvedScene
from statement_to_tikz.schematic import layout_schematic
from statement_to_tikz.solve import DEFAULT_TOL, solve_geometry
from statement_to_tikz.verify import check_ir_consistency, verify_scene
def solve_with_fallback(
ir: GeometryIR,
*,
tol: float = DEFAULT_TOL,
force_schematic: bool = False,
) -> SolvedScene:
ir = ir.model_copy(deep=True)
ir.ensure_labels()
if force_schematic:
return layout_schematic(ir)
exact = solve_geometry(ir, tol=tol)
if exact.mode == SolveMode.exact:
return exact
# Prefer schematic over failed; seed from failed attempt if available
base = exact.coordinates if exact.coordinates else None
schematic = layout_schematic(ir, base=base)
schematic.message = (
f"fallback after exact fail ({exact.message}); {schematic.message}"
)
return schematic
def run_pipeline(
statement: str | None = None,
*,
ir: GeometryIR | None = None,
out_dir: Path | str | None = None,
basename: str = "fig",
tol: float = DEFAULT_TOL,
compile_pdf: bool = True,
allow_offline_formalizer: bool = True,
force_schematic: bool = False,
formalizer_kwargs: dict[str, Any] | None = None,
) -> dict[str, Any]:
"""Run full or partial pipeline. Returns paths + report."""
if ir is None:
if not statement:
raise ValueError("provide statement or ir")
ir = formalize(
statement,
allow_offline=allow_offline_formalizer,
**(formalizer_kwargs or {}),
)
else:
ir = ir.model_copy(deep=True)
if statement and not ir.statement:
ir.statement = statement
ir.ensure_labels()
warnings = check_ir_consistency(ir)
scene = solve_with_fallback(ir, tol=tol, force_schematic=force_schematic)
tex = emit_standalone_tex(scene)
result: dict[str, Any] = {
"mode": scene.mode.value,
"max_residual": scene.max_residual,
"message": scene.message,
"warnings": warnings,
"ir": ir.model_dump(),
"coordinates": scene.coordinates,
"tex": tex,
}
if out_dir is not None:
out = Path(out_dir)
out.mkdir(parents=True, exist_ok=True)
tex_path = out / f"{basename}.tex"
ir_path = out / f"{basename}.ir.json"
report_path = out / f"{basename}.report.json"
tex_path.write_text(tex, encoding="utf-8")
ir_path.write_text(ir.model_dump_json(indent=2), encoding="utf-8")
report = verify_scene(scene, tex_path, tol=tol, compile=compile_pdf)
report["warnings"] = warnings
report["mode"] = scene.mode.value
report["message"] = scene.message
report["coordinates"] = scene.coordinates
report_path.write_text(json.dumps(report, indent=2), encoding="utf-8")
result["paths"] = {
"tex": str(tex_path),
"ir": str(ir_path),
"report": str(report_path),
"pdf": (report.get("compile") or {}).get("pdf"),
}
result["report"] = report
else:
result["report"] = verify_scene(scene, None, tol=tol, compile=False)
return result
def load_ir(path: Path | str) -> GeometryIR:
data = json.loads(Path(path).read_text(encoding="utf-8"))
data.pop("expected_mode", None)
ir = GeometryIR.model_validate(data)
ir.ensure_labels()
return ir