Papers
Topics
Authors
Recent
Search
2000 character limit reached

Proof-State Snapshotting in Lean 4

Updated 4 July 2026
  • Proof-state snapshotting is a technique that captures an elaborated proof state at a 'sorry' position and reuses it across tactic-search branches.
  • It bundles the Environment, MetavarContext, and LocalContext into a Snapshot, enabling efficient sharing of large immutable data and cloning of smaller contexts.
  • Empirical results demonstrate speedups from 5.6× to 50× by significantly reducing the reconstruction overhead in automated theorem proving.

Proof-state snapshotting is a technique for automated theorem proving in Lean 4 that captures an already elaborated proof state at a sorry position and reuses it across multiple tactic-search branches instead of reconstructing that state independently for each branch. In the formulation reported by Shen and Shi, the relevant proof state at source position pp is the triple ProofState(p)(Environmentp, MetavarContextp, LocalContextp)\mathrm{ProofState}(p) \coloneqq (\mathrm{Environment}_p,\ \mathrm{MetavarContext}_p,\ \mathrm{LocalContext}_p), and Lean’s implementation bundles these components into a Snapshot object. The method was introduced to address the mismatch between portfolio-style tactic search and an execution model in which each branch re-runs import loading and theorem-body elaboration, an arrangement that makes branching disproportionately expensive in Lean 4 with Mathlib (Shen et al., 25 May 2026).

1. Definition and internal representation

In Lean 4 with Mathlib loaded, a proof state at position p is represented by three internal data structures: the Environment, the MetavarContext, and the LocalContext (Shen et al., 25 May 2026). The Environment contains the global environment of all loaded constants, declarations, notation, and type-class instances; the MetavarContext contains the current open metavariables and their assignment table; and the LocalContext contains the local hypotheses and bound variables visible at the relevant source position.

The paper states that these three components are bundled into a Snapshot object with the simplified type signature:

m,l\ell_m,\ell_l2

A snapshot at position pp is then written as snap_p : Snapshot = (env_p, mctx_p, lctx_p) (Shen et al., 25 May 2026). The Environment is described as approximately 2–4 GB once Mathlib is in core, whereas the MetavarContext is approximately KB per hole. This size asymmetry is central to the design: the large global environment is immutable and can be shared by reference, while the much smaller per-branch state can be cloned cheaply.

The same source also formalizes an implementation-level reference object: SnapshotRef{envRef:e, mctxRef:m, lctxRef:l}\mathrm{SnapshotRef} \hookrightarrow \{ \mathrm{envRef} : \ell_e,\ \mathrm{mctxRef} : \ell_m,\ \mathrm{lctxRef} : \ell_l \}, where e\ell_e points into the global read-only environment store and m,l\ell_m,\ell_l point into the proof’s mutable context store. This representation allows a JSON-RPC interface to return a stable snapshotId : String without transmitting the full proof state through JSON. A plausible implication is that the technique is best understood not as proof serialization, but as server-side retention and controlled reuse of elaborated state.

2. Baseline reconstruction and the source of overhead

The baseline targeted by proof-state snapshotting is the “Level 0” tactic-search workflow in which every branch rebuilds a fresh proof state (Shen et al., 25 May 2026). The paper decomposes that reconstruction into two dominant costs.

First, import loading deserializes all Mathlib .olean files into an empty Environment, with cost Tload60 sT_{\mathrm{load}} \approx 60\ \mathrm{s} per branch. Second, theorem-body elaboration re-type-checks the theorem header and all prior steps up to the first sorry, with cost Tbody[18 s,735 s]T_{\mathrm{body}} \in [18\ \mathrm{s}, 735\ \mathrm{s}] per branch, growing with proof complexity. Together these account for more than 99%99\% of per-branch wall time in a standard single-machine setting (Shen et al., 25 May 2026).

The paper gives concrete endpoint estimates. On the simplest benchmark, mathd_algebra_209, the minimum theorem-body elaboration cost is approximated as min(Tbody)78 s60 s18 s\min(T_{\mathrm{body}}) \approx 78\ \mathrm{s} - 60\ \mathrm{s} \approx 18\ \mathrm{s}. On the hardest cited case, mathd_numbertheory_328 with 28 branches, theorem-body elaboration is estimated as ProofState(p)(Environmentp, MetavarContextp, LocalContextp)\mathrm{ProofState}(p) \coloneqq (\mathrm{Environment}_p,\ \mathrm{MetavarContext}_p,\ \mathrm{LocalContext}_p)0. Since tactic execution itself is only a few ms to a few hundred ms, the fallback time is summarized as ProofState(p)(Environmentp, MetavarContextp, LocalContextp)\mathrm{ProofState}(p) \coloneqq (\mathrm{Environment}_p,\ \mathrm{MetavarContext}_p,\ \mathrm{LocalContext}_p)1 per branch (Shen et al., 25 May 2026).

The paper’s per-branch breakdown illustrates the imbalance:

Problem Branches Tactic CPU Native/branch Overhead%
mathd_numbertheory_3 21 44 ms 5.5 s 99.9 %
algebra_sqineq_at2malt1 14 50 ms 5.7 s 99.9 %

These figures support the paper’s central diagnosis: the limiting factor is not tactic evaluation but repeated reconstruction of a largely identical proof state. This suggests that improvements to branching throughput should target state reuse rather than tactic-level micro-optimization.

3. Snapshot capture, branching, and execution model

To eliminate repeated reconstruction, the paper extends the Lean 4 Language Server with three JSON-RPC methods registered on server startup (Shen et al., 25 May 2026). These endpoints are:

  1. $/lean/dspSnapshotPing</code>, which checks for snapshot support and replies <code>{ &quot;ok&quot;: true }</code> if the patched server is running.</li> <li><code>$/lean/dspSnapshotCapture, which takes a file uri and a position corresponding to a sorry, blocks until the internal elaborator reaches that position, records a handle to the corresponding Snapshot, and returns a stable snapshotId : String.
  2. /lean/dspSnapshotBranch</code>,whichtakesa<code>snapshotId</code>andanarrayoftacticconfigurations,fetchestherecordedsnapshot,andspawnsa<ahref="https://www.emergentmind.com/topics/additiveparallelcorrection"title=""rel="nofollow"dataturbo="false"class="assistantlink"xdataxtooltip.raw="">parallel</a>taskforeachtactic.</li></ol><p>Foreachbranch,thesystemclonesonlythe<code>MetavarContext</code>,substitutesthetacticinplaceof<code>sorry</code>,runsthetactic,andreturnsarecordoftheform<code>ok:Bool,error:OptionString,cpuSeconds:Float</code>(<ahref="/papers/2605.25556"title=""rel="nofollow"dataturbo="false"class="assistantlink"xdataxtooltip.raw="">Shenetal.,25May2026</a>).The<code>Environment</code>issharedbyreferencebecauseitisimmutableandmuchlargerthanthemutableproofstatecomponents.Thepaperthereforecharacterizestheforkingcostas/lean/dspSnapshotBranch</code>, which takes a <code>snapshotId</code> and an array of tactic configurations, fetches the recorded snapshot, and spawns a <a href="https://www.emergentmind.com/topics/additive-parallel-correction" title="" rel="nofollow" data-turbo="false" class="assistant-link" x-data x-tooltip.raw="">parallel</a> task for each tactic.</li> </ol> <p>For each branch, the system clones only the <code>MetavarContext</code>, substitutes the tactic in place of <code>sorry</code>, runs the tactic, and returns a record of the form <code>{ ok: Bool, error: Option String, cpuSeconds: Float }</code> (<a href="/papers/2605.25556" title="" rel="nofollow" data-turbo="false" class="assistant-link" x-data x-tooltip.raw="">Shen et al., 25 May 2026</a>). The <code>Environment</code> is shared by reference because it is immutable and much larger than the mutable proof-state components. The paper therefore characterizes the forking cost as \mathrm{ProofState}(p) \coloneqq (\mathrm{Environment}_p,\ \mathrm{MetavarContext}_p,\ \mathrm{LocalContext}_p)$2 and “effectively free even for hundreds of branches.”

    The server-side procedure is given in LaTeX-style pseudocode:

    $\mathrm{ProofState}(p) \coloneqq (\mathrm{Environment}_p,\ \mathrm{MetavarContext}_p,\ \mathrm{LocalContext}_p)$3

    Each branch runs in parallel on a worker thread using Lean’s work-stealing scheduler, and wall time is described as dominated by the slowest single branch plus approximately 10 ms for task dispatch (Shen et al., 25 May 2026). In effect, snapshotting changes the unit of reuse from files and imports to the fully elaborated proof state at the hole boundary.

    4. Experimental protocol and benchmark design

    The evaluation was performed on a MacBook Pro with Apple M-series, 8 GB RAM, and macOS, using Lean 4.25.1 patched via elan (Shen et al., 25 May 2026). The data set comprised 48 miniF2F-v2 problems: 45 hand-crafted “Prove-phase” sketches with 1–5 sorry holes each, and 3 full end-to-end Draft-Sketch-Prove runs on selected theorems.

    For each problem, the paper compares two paths. The native snapshot path uses the sequence dspSnapshotPing $\mathrm{ProofState}(p) \coloneqq (\mathrm{Environment}_p,\ \mathrm{MetavarContext}_p,\ \mathrm{LocalContext}_p)$4 dspSnapshotCapture $\mathrm{ProofState}(p) \coloneqq (\mathrm{Environment}_p,\ \mathrm{MetavarContext}_p,\ \mathrm{LocalContext}_p)$5 dspSnapshotBranch. The fallback path performs a full lake build per branch with no snapshots (Shen et al., 25 May 2026). Fallback concurrency is bounded by RAM: with 8 GB, the experiments used approximately $\mathrm{ProofState}(p) \coloneqq (\mathrm{Environment}_p,\ \mathrm{MetavarContext}_p,\ \mathrm{LocalContext}_p)$6 parallel lake builds for the hand-crafted benchmarks and $\mathrm{ProofState}(p) \coloneqq (\mathrm{Environment}_p,\ \mathrm{MetavarContext}_p,\ \mathrm{LocalContext}_p)7forthefull<ahref="https://www.emergentmind.com/topics/dynamicspeculativeplanningdsp"title=""rel="nofollow"dataturbo="false"class="assistantlink"xdataxtooltip.raw="">DSP</a>runs.</p><p>Bothpathsusethesametacticportfolioofseventactics<code>aesop</code>,<code>normnum</code>,<code>omega</code>,<code>ring</code>,<code>linarith</code>,<code>decide</code>,and<code>simp</code>onthesameproofsketches,sothemeasurementisolatesinfrastructureoverheadratherthantacticquality(<ahref="/papers/2605.25556"title=""rel="nofollow"dataturbo="false"class="assistantlink"xdataxtooltip.raw="">Shenetal.,25May2026</a>).Thepaperdenotesthenumberofholesby7 for the full <a href="https://www.emergentmind.com/topics/dynamic-speculative-planning-dsp" title="" rel="nofollow" data-turbo="false" class="assistant-link" x-data x-tooltip.raw="">DSP</a> runs.</p> <p>Both paths use the same tactic portfolio of seven tactics—<code>aesop</code>, <code>norm_num</code>, <code>omega</code>, <code>ring</code>, <code>linarith</code>, <code>decide</code>, and <code>simp</code>—on the same proof sketches, so the measurement isolates infrastructure overhead rather than tactic quality (<a href="/papers/2605.25556" title="" rel="nofollow" data-turbo="false" class="assistant-link" x-data x-tooltip.raw="">Shen et al., 25 May 2026</a>). The paper denotes the number of holes by \mathrm{ProofState}(p) \coloneqq (\mathrm{Environment}_p,\ \mathrm{MetavarContext}_p,\ \mathrm{LocalContext}_p)$8 and sets the number of branches to $\mathrm{ProofState}(p) \coloneqq (\mathrm{Environment}_p,\ \mathrm{MetavarContext}_p,\ \mathrm{LocalContext}_p)$9.

    This design matters methodologically because it separates speed from proving power. The system does not compare different search heuristics or different theorem-proving capabilities; it measures the cost of trying the same set of tactics under two different execution models.

    5. Empirical results and scaling behavior

    Across 48 miniF2F-v2 problems—45 Prove-phase benchmarks and 3 full end-to-end runs—the reported wall-time speedup over the standard fallback ranges from $p$0 to $p$1, with average $p$2 and median $p$3 (Shen et al., 25 May 2026). The paper emphasizes that speedup increases with the number of proof branches.

    The main wall-time results are summarized as follows:

    Setting Native Fallback Speedup
    mathd_numbertheory_345 132.8 s 2,641.4 s 19.9×
    mathd_numbertheory_3 116.2 s 1,572.4 s 13.5×
    mathd_algebra_478 119.9 s 1,579.6 s 13.2×
    Holes 1 (5 probs), B=7 196 s 1,537 s 7.9× (6.3–9.6×)
    Holes 2 (19 probs), B=14 136 s 1,291 s 9.4× (5.6–19.9×)
    Holes 3 (11 probs), B=21 131 s 1,811 s 13.8× (6.5–20.2×)
    Holes 4 (7 probs), B=28 125 s 3,478 s 24.6× (13.1–50.0×)
    Holes 5 (3 probs), B=35 141 s 4,436 s 29.8× (20.1–45.2×)
    Average (all 45) 140 s 1,995 s 14.0×

    The paper states that speedup grows monotonically with hole count pp4 and therefore with branch count pp5 (Shen et al., 25 May 2026). Section 4.4 gives the scaling law: pp6 and pp7, where pp8 tactics and pp9. On the reported hardware, SnapshotRef{envRef:e, mctxRef:m, lctxRef:l}\mathrm{SnapshotRef} \hookrightarrow \{ \mathrm{envRef} : \ell_e,\ \mathrm{mctxRef} : \ell_m,\ \mathrm{lctxRef} : \ell_l \}0 once per theorem, SnapshotRef{envRef:e, mctxRef:m, lctxRef:l}\mathrm{SnapshotRef} \hookrightarrow \{ \mathrm{envRef} : \ell_e,\ \mathrm{mctxRef} : \ell_m,\ \mathrm{lctxRef} : \ell_l \}1 per branch for simple theorems to approximately SnapshotRef{envRef:e, mctxRef:m, lctxRef:l}\mathrm{SnapshotRef} \hookrightarrow \{ \mathrm{envRef} : \ell_e,\ \mathrm{mctxRef} : \ell_m,\ \mathrm{lctxRef} : \ell_l \}2 per branch for harder ones, and SnapshotRef{envRef:e, mctxRef:m, lctxRef:l}\mathrm{SnapshotRef} \hookrightarrow \{ \mathrm{envRef} : \ell_e,\ \mathrm{mctxRef} : \ell_m,\ \mathrm{lctxRef} : \ell_l \}3 (Shen et al., 25 May 2026).

    Projected runtimes extend the trend beyond the measured regime. For example, the paper reports projected values of approximately SnapshotRef{envRef:e, mctxRef:m, lctxRef:l}\mathrm{SnapshotRef} \hookrightarrow \{ \mathrm{envRef} : \ell_e,\ \mathrm{mctxRef} : \ell_m,\ \mathrm{lctxRef} : \ell_l \}4 speedup at SnapshotRef{envRef:e, mctxRef:m, lctxRef:l}\mathrm{SnapshotRef} \hookrightarrow \{ \mathrm{envRef} : \ell_e,\ \mathrm{mctxRef} : \ell_m,\ \mathrm{lctxRef} : \ell_l \}5, approximately SnapshotRef{envRef:e, mctxRef:m, lctxRef:l}\mathrm{SnapshotRef} \hookrightarrow \{ \mathrm{envRef} : \ell_e,\ \mathrm{mctxRef} : \ell_m,\ \mathrm{lctxRef} : \ell_l \}6 at SnapshotRef{envRef:e, mctxRef:m, lctxRef:l}\mathrm{SnapshotRef} \hookrightarrow \{ \mathrm{envRef} : \ell_e,\ \mathrm{mctxRef} : \ell_m,\ \mathrm{lctxRef} : \ell_l \}7, and approximately SnapshotRef{envRef:e, mctxRef:m, lctxRef:l}\mathrm{SnapshotRef} \hookrightarrow \{ \mathrm{envRef} : \ell_e,\ \mathrm{mctxRef} : \ell_m,\ \mathrm{lctxRef} : \ell_l \}8 at SnapshotRef{envRef:e, mctxRef:m, lctxRef:l}\mathrm{SnapshotRef} \hookrightarrow \{ \mathrm{envRef} : \ell_e,\ \mathrm{mctxRef} : \ell_m,\ \mathrm{lctxRef} : \ell_l \}9 (Shen et al., 25 May 2026). At “classical DSP scale,” described as 100 draft candidates yielding, for example, e\ell_e0 holes e\ell_e1 e\ell_e2 tactics e\ell_e3 branches, the paper estimates that fallback would take approximately 29 h on a single M-series laptop, whereas snapshots would reduce this to approximately 3.5 h. This suggests that the method is primarily a scaling intervention for portfolio search rather than a marginal constant-factor optimization.

    6. Relation to import-level caching, limitations, and scope

    The paper distinguishes proof-state snapshotting from import-level caching and presents the two as orthogonal techniques (Shen et al., 25 May 2026). Import-level caching, designated “Level 1” and exemplified by Kimina Lean Server, eliminates only e\ell_e4 and not e\ell_e5. Its best per-branch speedup is given as e\ell_e6 depending on e\ell_e7. Snapshotting, designated “Level 2,” eliminates both e\ell_e8 and e\ell_e9 per branch, although it still pays m,l\ell_m,\ell_l0 once per LSP server start.

    The projected composition of the two levels is summarized in the paper as follows:

    Approach Wall time vs Level 0
    Level 0 (per-branch lake) 2,641 s
    Level 1 (import cached, W=2) ~330 s
    Level 2 (snapshot) 133 s 20×
    Level 1+2 (persistent + snapshot) ~17 s >100×

    Several limitations are stated explicitly (Shen et al., 25 May 2026). Accuracy is unchanged: snapshotting does not modify which goals are provable, only how fast tactics are tried. A patched binary is required, so deployment depends on trusting and installing a custom Lean 4 build via elan; without it, the system transparently falls back to lake builds. The current implementation restarts the LSP per theorem, so m,l\ell_m,\ell_l1 is still paid once per theorem; a persistent-server variant would remove that one-time cost. Finally, all tests were conducted on an Apple M-series laptop, and the paper notes that other hardware and deeper proofs may shift the exact crossover points.

    These caveats delimit the technique’s scope. Proof-state snapshotting is not presented as a new proving method, a new tactic portfolio, or a change to proof semantics. It is an execution-model modification for Lean 4 tactic search in which elaborated state is kept live and reused rather than repeatedly reconstructed. Within that scope, the reported results indicate that the dominant bottleneck in portfolio-based search on partially specified proofs can be moved from proof-state reconstruction to tactic execution itself (Shen et al., 25 May 2026).

    Definition Search Book Streamline Icon: https://streamlinehq.com
    References (1)

Topic to Video (Beta)

No one has generated a video about this topic yet.

Whiteboard

No one has generated a whiteboard explanation for this topic yet.

Follow Topic

Get notified by email when new papers are published related to Proof-State Snapshotting.