satp-policy-v2

A 0.2B ByT5 policy that reads a Lean 4 goal state and emits a per-problem aesop configuration โ€” search budget, rule-set options, and extra tactic and lemma rules. This repository is a self-contained inference bundle: checkpoint plus a standalone infer.py (no training-repo dependencies), forward-equivalent to the training policy.

Results

miniF2F (ChristianZ97/minif2f-satp), greedy decode, statements submitted raw (Lean default maxHeartbeats 200000), Lean 4 v4.26.0:

split solved
test 37.7% (92/244)
validation 37.3% (91/244)
ablation (test) solved
satp 37.7% (92/244)
w/ default search budget 37.7% (92/244)
distilled static configuration 31.6% (77/244)
w/o additional lemma 31.1% (76/244)
w/o additional tactic 30.7% (75/244)
aesop 10.7% (26/244)

Every number above โ€” both splits and all ablation rows โ€” is verified per problem by two independent backends (the Kimina server, and one lake env lean per proof), with #print axioms as the arbiter: a counted proof compiles, contains no sorry, and depends on no axioms beyond propext, Classical.choice, Quot.sound. Policy rows are additionally checked through both input paths (dataset goal_state, and live goal states via the satp tactic) with identical solved sets.

The 92 solved test proofs are published in two forms โ€” the policy-emitted configuration verbatim, and a distilled minimal tactic script โ€” at LeanSATP proofs/minif2f_test_v2; every file compiles on stock Mathlib v4.26 with import Mathlib alone.

Checkpoint

run e0f230ns (wandb satp-v2), epoch 7 / step 1700, seed 1827
verifier Kimina-Lean Server, Lean 4 v4.26.0
architecture ByT5(kaiyuy/leandojo-lean4-retriever-byt5-small)+LoRA(r16,ฮฑ32,q/k/v/o) mean-pool โ†’ shared MLP โ†’ 69-head joint action (28 tactic ร—10-way + 32 lemma ร—181-way + 4 config_level + 5 config_binary) + dense premise retrieval

Distilled static configuration

One constant config for every problem (lemma off); per-head mode over the 244 val decodes, -- % = mode agreement (joint 10-way: off | typeร—priority).

  aesop (config := {
    -- maxRuleApplications 200 = default     -- 50%
    maxRuleApplicationDepth := 10            -- 50%
    maxNormIterations := 520                 -- 36%
    maxGoals := 1024                         -- 24%
  }) (rule_sets := [-builtin])               -- enableBuiltin=F 59%
    (add norm 100 (by ring))                 -- 86%
    (add norm 100 (by field_simp))           -- 82%
    (add norm 100 (by norm_num))             -- 93%
    (add norm 100 (by norm_cast))            -- 82%
    (add norm 0 (by linarith))               -- 64%
    (add norm 0 (by nlinarith))              -- 89%
    (add norm 0 (by omega))                  -- 82%
    (add norm 100 (by abel))                 -- 85%
    (add norm 100 (by zify))                 -- 64%
    (add norm 0 (by bound))                  -- 55%
    (add norm 100 (by interval_cases))       -- 65%
    (add norm 100 (by ext))                  -- 55%
    (add norm 100 (by split))                -- 60%
    (add norm 100 (by exfalso))              -- 84%
    (add norm 100 (by ring_nf at *))         -- 58%
    (add norm 100 (by field_simp [*] at *))  -- 45%
    (add norm 100 (by norm_num [*] at *))    -- 72%
    (add norm 100 (by norm_cast at *))       -- 82%
    (add norm 100 (by rfl))                  -- 86%
    (add norm 100 (by push_cast))            -- 93%
    (add norm 100 (by assumption_mod_cast))  -- 72%
    (add safe 0 (by ring_nf))                -- 32%
    (add safe 0 (by simp_all))               -- 43%

off: positivity 87%, push_neg 85%, gcongr 65%, simp 58%, decide 36%. binary modes: enableSimp T 94%, useSimpAll T 71%, enableUnfold T 63%, useDefaultSimpSet T 86%, enableBuiltin F 59%. Priorities are integers, smaller = higher (0 first, 100 last); unsafe = success %.

Files

best_checkpoint.pt            # 1.12 GB โ€” infer.py reads model_state_dict only
infer.py                      # load โ†’ retrieve โ†’ greedy-decode โ†’ Kimina verify
reproduce.py                  # test-split repro, kimina | lake verifier (imports infer.py)
cache/premise_embeddings.npy  # 1.0 GB โ€” 180,957 ร— 1472 premise embeddings
cache/mathlib4_premises.txt   # 38 MB โ€” premise names, index-aligned

Premise corpus = LeanDojo Benchmark-4 v10; embeddings come from the frozen retriever โ†’ verifier-version independent. ByT5 base auto-downloads on first run.

Run

pip install torch transformers numpy requests huggingface_hub datasets
hf download ChristianZ97/satp-policy-v2 --local-dir satp-policy-v2
cd satp-policy-v2
KIMINA_URL=http://localhost:8000 python infer.py
var default meaning
KIMINA_URL http://localhost:8000 Kimina /verify endpoint
SATP_SPLIT validation or test
SATP_LIMIT 0 >0 โ†’ first N problems only
SATP_CKPT ./best_checkpoint.pt checkpoint path
SATP_CACHE ./cache premise files dir
SATP_HEARTBEATS0 unset 1 โ†’ remove the heartbeat cap (diagnostic; reported numbers use the default)
SATP_LEAN_TIMEOUT 300 server-side Lean timeout (s); HTTP timeout = +60

Verification is sequential (one POST per problem, retried with backoff). Header-less statements get the training header prepended.

Reproduce

reproduce.py re-runs the miniF2F test split end-to-end over the same greedy decode and compares against 92/244, with either verifier:

KIMINA_URL=http://localhost:8000 python reproduce.py kimina
SATP_LAKE_DIR=/path/to/lean-v4.26-project python reproduce.py lake   # no server

lake runs one lake env lean per problem (300 s timeout) inside any Lean v4.26 project with Mathlib built; writes reproduce_<backend>.jsonl ({name, success, tactic, code} per problem). Reference: kimina 92/244 exact (twice, bit-identical โ€” greedy decode is deterministic); all 92 replay 92/92 under lake env lean.

Lean-only path

LeanSATP runs the same policy as a Lean tactic: take a dataset row's formal_statement, add import LeanSATP, and close the proof with satp (satp? also prints the emitted configuration). Lean handles the rest โ€” elaboration, live goal state โ†’ policy, aesop execution. Same 92/244 solved set.

Downloads last month

-

Downloads are not tracked for this model. How to track
Video Preview
loading