NIM paper · interactive edition Interactive edition · paper, explanations and Lean proofs.

Figure 2Worked example: (3,5,6) → (3,4,6) → (2,4,6)

Checked theorem Lean checks a formal statement corresponding to this claim.

1 Paper text

Three boxes from left to right. Start (Q): heaps {3, 5, 6}, nim-sum = 0 (green). An arrow labelled "Opponent moves 5 to 4, delta = 5 XOR 4 = 1" leads to After Opponent (Q'): heaps {3, 4, 6}, nim-sum = 1 (red). A blue arrow labelled "Agent restores 3 to 2, matches delta = 1 (3 XOR 2 = 1)" leads to Restored (R): heaps {2, 4, 6}, nim-sum = 0 (green).
Figure 2: A worked restoration example (three heaps). Starting from a PP-position QQ (green), the opponent changes heap 2 (5→45\to 4), creating a nimber difference δ=1\delta=1. The agent instantly restores the PP-position by changing heap 1 (3→23\to 2), which imposes the matching difference 3⊕2=13\oplus 2 = 1.

Generated from paper_jmlr.tex, lines 544–604.

2 Explain this

The figure works one restoration by hand: Q=(3,5,6)Q=(3,5,6) has nim-sum 00; the opponent's move 5→45\to4 has difference δ=1\delta=1 and leaves nim-sum 11; the agent's move 3→23\to2 has the same difference 3⊕2=13\oplus2=1 and returns to nim-sum 00. Note that the agent changes a different heap from the one the opponent touched; what is mirrored is the XOR difference, not the heap.

Two-frame restoration, step by step

Exact construction trace Every value is computed from the construction’s definitions for the example shown.

This is the checked two-frame selector run on one example, gate group by gate group. It starts from the two frames of Figure 2 and ends with the binary output fields shown in Figure 7. Every value below is computed from the selector's definition for the boards shown. Choose another example to see several candidates at once, the fallback, or a terminal board. The two examples marked "outside the promise" do not start from a zero-nim-sum board after a legal move, so the guarantee does not apply to them.

Inside the promise. The earlier board has nim-sum 0 and the opponent decreased one heap, so the restoration theorem guarantees that the output restores nim-sum 0.

Earlier board Q (3, 5, 6)nim-sum 0
012
Current board Q′ (3, 4, 6)nim-sum 1; changed: heap 1
012
After the reply (2, 4, 6)nim-sum 0; reply in heap 0
012
  1. Compare the frames bit by bit

    Each heap is a 3-bit block. For every heap and every bit position, one two-input XOR compares Q with Q′, all in parallel.

    HeapQ Q′ XORHeap
    03 0113 011000same
    15 1014 100001changed
    26 1106 110000same
  2. Extract the difference δ

    Bit k of δ is the OR of column k of the XOR table: 001 = δ = 1.

    At most one heap changed, so at most one row is nonzero and the OR equals the XOR of the rows, which is nim(Q) ⊕ nim(Q′).

  3. Propose replacements and test them in parallel

    For every heap at once: replace Q′i by Q′i ⊕ δ and test whether that is a decrease. The decisive bit is the highest set bit of δ (weight 1): a heap passes exactly when it has that bit set.

    HeapQ′ Q′ ⊕ δTest
    03 0112 010passes: 2 < 3
    14 1005 101fails: 5 > 4
    26 1107 111fails: 7 > 6
    Show the bit comparisons

    The test x ⊕ δ < x is a fixed-depth circuit: an OR over the possible highest differing bit, requiring equality above it, a 1 in x and a 0 in the replacement at that bit.

    • Heap 0: 011 vs 010 — the highest differing bit has weight 1; the heap has 1 there, so the replacement is smaller.
    • Heap 1: 100 vs 101 — the highest differing bit has weight 1; the heap has 0 there, so the replacement is larger.
    • Heap 2: 110 vs 111 — the highest differing bit has weight 1; the heap has 0 there, so the replacement is larger.

    Candidates passing: 1.

  4. Choose between cancelling and the fallback

    cancelling move At least one replacement passes, so the flags are the passing tests and the fallback is masked off.

    Heappassesnonzerofallback valueflag si
    0113 − 1 = 21
    1014 − 1 = 30
    2016 − 1 = 50
  5. Encode the first flagged heap as a binary index

    For N = 3 heaps the construction uses r = ⌊log2 N⌋ + 1 = 2 index bits (the encoder itself needs only N ≤ 2r). The first flag is at heap 0, so the index bits are 00.

    Show the priority encoder

    fi = si ∧ ¬sj for all j < i keeps only the first flag; index bit k is the OR of fi over the heaps i whose binary index has a 1 at bit k. This is a fixed-depth circuit, not a search.

    Heap ii in binarysifirst fi
    00011
    10100
    21000

    Index bits (OR of the fi in each 1-column): 00

  6. Output the move

    validity1index (2 bits)00value (3 bits)010

    Decoded move: set heap 0 to 2. New board (2, 4, 6), nim-sum 0.

How this relates to the Lean proof. The selector is Family.restS (B, N): the local difference circuits LocalRestore.dC, the candidate tests of SelectCircuit.varSel and the priority encoder PriorityEncoder.encode, read on the two-frame input LocalRestore.tf. Family.rest_semantics proves that, on the promised domain, these formulas and the compiled network output a legal move that restores nim-sum 0. Outside the promise the circuit still computes the values shown, and no theorem says that the result restores 0.

What this does not show. The selector does not find a first winning move from an arbitrary board. Given a zero-nim-sum predecessor it maintains the invariant (Theorem 5.12(iii)). The boxes of Figure 7 group operations; the stages here group gates, not network layers.

Depicted in Lean: Family.rest_semantics, LocalRestore.restore_equiv, LocalRestore.localDelta_eq, LocalRestore.restC_eval, SelectCircuit.varSel_correct, AttainCircuit.cancel_iff_bit, PriorityEncoder.encode_correct, Family.rest_ac0, Family.rest_net. Explains the paper’s Figure 2, Figure 7.

Computed in your browser by a short re-implementation of the definitions above (tools/visuals/nimvis-core.js). It is not itself checked by Lean. At build time it agreed with Lean's own evaluation of those definitions on all 12,299 reference cases. Lean's evaluation fixes the output wires, the difference δ and the decoded move; the intermediate tables (flags, first-flag bits) are re-derived from the same definitions.

3 How this is formalised

Misc.restoration_figure checks every number in the figure: the three nim-sums, the legality of both moves, 5⊕4=15\oplus4=1, and that the restoration selector Game.restore applied to ((3,5,6),(3,4,6))((3,5,6),(3,4,6)) returns (2,4,6)(2,4,6).

Coverage record
Paper anchorfig:restoration-example (manuscript label)
Displayed asFigure 2
ClaimWorked example: (3,5,6) → (3,4,6) → (2,4,6)
Coverage categoryChecked theorem
Statement sourcepaper_jmlr.tex lines 544–604; SHA-256 of the normalised block source 1a6ca1c763d12d3e…
Lean declarations
Explanationsexplain/fig:restoration-example, formal/fig:restoration-example
Build evidencefresh isolated rebuild, audit report

4 Lean statement and source

Principal declarations

theorem Misc.restoration_figure

Module Misc (lean/phase6/Misc.lean, lines 826–832) · file SHA-256 07766c03566dbfca… Axioms reported by the fresh build: propext

FIGURE fig:restoration-example: from (3,5,6) (nim-sum 0) the opponent plays 5 → 4 (nim-sum 1, δ = 1); the restoration rule answers 3 → 2, restoring nim-sum 0.

Statement as elaborated and printed by Lean 4.26.0

NimAudit.nimSum [3, 5, 6] = 0 ∧
  NimAudit.Game.Move [3, 5, 6] [3, 4, 6] ∧
    NimAudit.nimSum [3, 4, 6] = 1 ∧
      5 ^^^ 4 = 1 ∧
        NimAudit.Game.restore [3, 5, 6] [3, 4, 6] = some [2, 4, 6] ∧
          NimAudit.Game.Move [3, 4, 6] [2, 4, 6] ∧ NimAudit.nimSum [2, 4, 6] = 0
Exact source text, lines 826–832
826/-- FIGURE fig:restoration-example: from (3,5,6) (nim-sum 0) the opponent plays 5 → 4827    (nim-sum 1, δ = 1); the restoration rule answers 3 → 2, restoring nim-sum 0. -/828theorem restoration_figure :829    nimSum [3, 5, 6] = 0 ∧ Move [3, 5, 6] [3, 4, 6] ∧ nimSum [3, 4, 6] = 1 ∧ (5 ^^^ 4 : Nat) = 1 ∧830    restore [3, 5, 6] [3, 4, 6] = some [2, 4, 6] ∧ Move [3, 4, 6] [2, 4, 6] ∧ nimSum [2, 4, 6] = 0 := by831  refine ⟨by decide, ⟨[3], 5, [6], 4, rfl, rfl, by decide⟩, by decide, by decide, by decide,832    ⟨[], 3, [4, 6], 2, rfl, rfl, by decide⟩, by decide⟩

Project declarations in the statement: Game.Move, Game.restore, nimSum

Project declarations used by the proof or definition body

Game.Move, Game.restore, nimSum

Definitions these statements use

def Game.Move

Module NimGame (lean/phase2/NimGame.lean, lines 24–26) · file SHA-256 23df6bb87ecfd344…

An ordinary legal Nim move: exactly one heap strictly decreases.

Statement as elaborated and printed by Lean 4.26.0

List ℕ → List ℕ → Prop
Exact source text, lines 24–26
24/-- An ordinary legal Nim move: exactly one heap strictly decreases. -/25def Move (p q : List Nat) : Prop :=26  ∃ pre x post y, p = pre ++ x :: post ∧ q = pre ++ y :: post ∧ y < x

Project declarations in the statement: none

Project declarations used by the proof or definition body

none

def Game.restore

Module NimGame (lean/phase2/NimGame.lean, lines 407–410) · file SHA-256 23df6bb87ecfd344…

Two-frame restoration selector (paper Prop. restore / Thm search-gap (iii)): from the predecessor Q and current board Q', cancel delta = nim(Q) XOR nim(Q').

Statement as elaborated and printed by Lean 4.26.0

List ℕ → List ℕ → Option (List ℕ)
Exact source text, lines 407–410
407/-- Two-frame restoration selector (paper Prop. restore / Thm search-gap (iii)):408    from the predecessor Q and current board Q', cancel delta = nim(Q) XOR nim(Q'). -/409def restore (Q Q' : List Nat) : Option (List Nat) :=410  cancelFirst (nimSum Q ^^^ nimSum Q') Q'

Project declarations in the statement: none

Project declarations used by the proof or definition body

Game.cancelFirst, nimSum

def nimSum

Module NimCore (lean/NimCore.lean, lines 7–9) · file SHA-256 b07db6c505210d5a…

Statement as elaborated and printed by Lean 4.26.0

List ℕ → ℕ
Exact source text, lines 7–9
7def nimSum : List Nat → Nat8  | [] => 09  | h :: t => h ^^^ nimSum t

Project declarations in the statement: none

Project declarations used by the proof or definition body

none

Full modules

ModuleFileLinesImports
Misclean/phase6/Misc.lean912Bypass
NimCorelean/NimCore.lean139Std
NimGamelean/phase2/NimGame.lean634NimRollout

Build evidence: fresh isolated rebuild of all 38 bundled modules with Lean (version 4.26.0, started 2026-10-10T15:21:56Z, finished 2026-10-10T15:27:00Z: 38/38 modules compiled, 1588 axiom reports, no errors. See Build for the commands and the independent audit of 2026-10-10 (dated evidence).