Mathlib-Sexpr-GNN / README.md
jajostrains's picture
Upload README.md with huggingface_hub
700c48c verified
|
Raw History Blame Contribute Delete
5.29 kB
---
license: apache-2.0
library_name: pytorch
tags:
- lean-4
- mathlib
- theorem-proving
- tactic-prediction
- gnn
- graph-neural-network
datasets:
- jajostrains/Mathlib-Normalized-Sexpr
language:
- en
---
# Mathlib-Sexpr-GNN — GNN tactic and argument prediction for Lean 4
Graph neural networks that predict **which tactic to apply** to a Lean 4 proof
goal, and **which arguments** (local hypotheses or library lemmas) to give it.
Trained on 250,814 tactic steps from Mathlib, represented as S-expression
goal-state DAGs from [jajostrains/Mathlib-Normalized-Sexpr](https://huggingface.co/datasets/jajostrains/Mathlib-Normalized-Sexpr).
Two bundles are published here, each a self-contained directory verified by
content hashes (weights, node vocabulary, tactic vocabulary):
| Directory | Model | What it predicts |
|---|---|---|
| `tactic-baseline-gat/` | GATv2 encoder + classifier | tactic family only (e.g. `rw`, `apply`, `simp`) |
| `pointer-gat-gru/` | GATv2 encoder + GRU pointer decoder + stop head, with a premise scorer | tactic family **and** its ordered argument sequence, plus a premise scorer for library-lemma retrieval |
## How the models work
- **Goal representation.** Each proof state (goal + local context) is parsed
into a directed acyclic graph: expression nodes, hypothesis nodes with
binder annotations, and a State root. A GATv2 encoder (4 layers, 8 heads,
hidden 128, state+mean-attention readout) produces node embeddings.
- **Tactic head.** A classifier over the state embedding predicts one of 228
tactic families.
- **Argument decoder (pointer bundle).** A GRU recurrent decoder runs up to 3
decode steps. At each step it scores every premise-selectable DAG node
(pointer attention over node embeddings), picks one, and feeds it back into
the recurrence. A **stop head** decides when the argument sequence ends —
the count is learned, not taken from a static arity table. Already-selected
nodes are masked so no argument repeats.
- **Premise scorer.** A dot-product scorer over a unified candidate pool
(local DAG nodes + FAISS-retrieved library lemmas), for tactics that cite
Mathlib lemmas (`exact`, `apply`, `rw`).
## Metrics
Validation split (4,260 tactic steps), pointer bundle:
| Metric | Value |
|---|---|
| Tactic top-1 / top-5 | 0.320 / 0.711 |
| Argument top-1 / top-5 (position-level) | 0.433 / 0.779 |
| Exact argument-sequence match | 0.037 |
| Stop-decision accuracy | 0.789 |
| Premise scorer top-1 / top-5 / MRR | 0.481 / 0.806 / 0.618 |
Test split: tactic top-1 0.315, premise top-1 0.468, premise MRR 0.600.
Baseline bundle: validation tactic top-1 0.327 / top-5 0.701; test top-1 0.311.
Caveat on the argument metrics: they are computed over the positions a
DAG-pointer can physically select — local-context targets within the 3-step
decode budget. Library-lemma citations are the premise scorer's task and are
excluded from the pointer's accuracy; longer argument lists (the corpus
median exceeds 3 for `rw`-family chains) are truncated at the budget and
reported separately.
## Usage
Each bundle directory holds `bundle.json` (manifest with hashes and
metadata), `model.safetensors`, `config.json`, and the scorer (pointer
bundle only). The shared `vocab/` directory at the repo root holds the
canonical node and tactic vocabularies both bundles were trained against;
the manifests hash-bind the weights to them.
Loading with the project's API:
```python
from maths_ai.gnn_inference.atp_lean_gnn.bundle import load_pointer_bundle
loaded = load_pointer_bundle("pointer-gat-gru", device="cpu")
# loaded.model — TacticWithArgsClassifier (GATv2 + GRU pointer decoder)
# loaded.scorer — PremiseScorer (dot mode)
```
Bundle invariants enforced on load: weight and vocabulary hashes are
re-verified against `bundle.json`; a `pointer_gru` bundle cannot be loaded
as a legacy pointer or vice versa; a vocabulary of the same size but
different content is rejected (IDs are position-assigned, so a renumbered
vocabulary would silently mislabel every prediction otherwise).
## Training data and provenance
- 250,814 train / 4,260 val / 4,506 test tactic steps from the LeanDojo
Mathlib 4 benchmark split (row selection, splits, and row indices inherited
unchanged from the upstream benchmark).
- Goal states elaborated with a pinned Pantograph REPL against Mathlib at the
benchmark's commit; S-expressions and per-position argument traces extracted
per row.
- Trained from a baseline-initialized checkpoint (tactic head warm-started
from `tactic-baseline-gat`'s encoder), 30 epochs, bfloat16 AMP.
## Limitations
- Argument sequences are capped at 3 steps; longer `rw` chains are truncated.
- The premise scorer's FAISS index (318,953 Mathlib declarations) is **not**
published with this model — it is not yet hash-bound to the encoder that
produced its vectors, so serving it risks confidently wrong retrieval. It
will follow once that binding is enforced at load time.
- Closed-loop proof search (running the model against Lean) is not yet
evaluated; these are per-state prediction metrics.
## License
Apache-2.0, inherited from Mathlib. The dataset carries the LeanDojo MIT
notice for the benchmark's row selection and split structure; see the
dataset card for details.