Proposition 5.5Matching the opponent's nimber difference restores nim-sum zero
Checked theoremLean checks a formal statement corresponding to this claim.
1 Paper text
Proposition 5.5(Local restoration principle) Suppose the opponent moves from a position Q with nim(Q)=0 to a position Q′ (so it is now our turn). Let Δ(Q,Q′)=nim(Q)⊕nim(Q′) denote the nimber difference caused by the opponent’s move. If we respond with a move Q′→R such that Δ(Q′,R)=Δ(Q,Q′), then nim(R)=0.
Generated from paper_jmlr.tex, lines 520–529.
2 Explain this
The idea. A NIM position with nim-sum zero is "balanced": whoever must move from it loses against correct
play. Any move changes one heap, say from xi to xi′, and this unbalances the position by exactly
δ=xi⊕xi′. If the reply changes some heap by the same XOR difference δ, the two changes
cancel and the balance returns.
A small example. In Figure 2, Q=(3,5,6) has nim-sum 3⊕5⊕6=0. The opponent
plays 5→4, so δ=5⊕4=1. The reply 3→2 also has 3⊕2=1, and R=(2,4,6) has nim-sum
2⊕4⊕6=0 again.
Why it matters. The reply never needs the nim-sum of the whole board. It needs only the two most recent
frames: δ is read off the one heap that changed, and a cancelling heap is found by a local bit test.
That is why a shallow two-frame network can play this response although no shallow single-frame network can
evaluate the nim-sum (Theorem 5.2).
Caveats.
The promise matters. If nim(Q)=0, matching the difference only reproduces the old value,
nim(R)=nim(Q) (see the initialisation boundary).
Restoration is conditional: it keeps a won position won once a zero-nim-sum position has been established.
It does not find the first winning move from an arbitrary position.
The previous frame must be the board the opponent moved from, that is, the player's own post-move board.
Two-frame restoration, step by step
Exact construction traceEvery 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.
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.
Heap
Q 421
Q′ 421
XOR
Heap
0
3 011
3 011
000
same
1
5 101
4 100
001
changed
2
6 110
6 110
000
same
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′).
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.
Heap
Q′ 421
Q′ ⊕ δ
Test
0
3 011
2 010
passes: 2 < 3
1
4 100
5 101
fails: 5 > 4
2
6 110
7 111
fails: 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.
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.
Heap
passes
nonzero
fallback value
flag si
0
1
1
3 − 1 = 2
1
1
0
1
4 − 1 = 3
0
2
0
1
6 − 1 = 5
0
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 i
i in binary
si
first fi
0
00
1
1
1
01
0
0
2
10
0
0
Index bits (OR of the fi in each 1-column): 00
Output the move
validity1|index (2 bits)00|value (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.
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
Objects. A board is a list of natural numbers; nimSum folds XOR over it.
The proposition. Writing q,q′,r for the nim-sums of Q,Q′,R, the paper's proof is the identity
r=q′⊕Δ(Q′,R)=q′⊕(q⊕q′)=q under the hypothesis Δ(Q′,R)=Δ(Q,Q′). Lean
states it in exactly this form, conditional_restoration: if q=0 and
q⊕q′=q′⊕r then r=0. No legality assumption is needed for this step.
one_heap_difference checks the sentence before it: when one heap changes from a to b, the
two nim-sums differ by a⊕b.
The predecessor Q has nim-sum zero and Q→Q′ is the opponent's move.
Prose-to-formal notes
The proposition is the algebra in conditional_restoration, stated for the three nim-sums q=nim(Q), q′=nim(Q′), r=nim(R). Legality of the reply is not needed for this step; the shallow selector in the next sentence is a separate record.
Module NimCore
(lean/NimCore.lean, lines 37–39) · file SHA-256 b07db6c505210d5a…Axioms reported by the fresh build: propext, Quot.sound
Statement as elaborated and printed by Lean 4.26.0
∀ (pre post : List ℕ) (a b : ℕ),
NimAudit.nimSum (pre ++ a :: post) ^^^ NimAudit.nimSum (pre ++ b :: post) = a ^^^ b
Exact source text, lines 37–39
37theorem one_heap_difference (pre post : List Nat) (a b : Nat) :38 nimSum (pre ++ a :: post) ^^^ nimSum (pre ++ b :: post) = a ^^^ b := by39 simp [nimSum_append, nimSum, Nat.xor_comm, xor_left_comm]
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).