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

Proposition 5.13A constant-depth recurrent update computes the nim-sum after N row updates and reports consecutive differences

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

1 Paper text

Proposition 5.13 (Sequential nim-sum accumulation) There is a recurrent Boolean update of constant depth and size O(B)O(B), implementable with fixed-scale quantised threshold gates, that computes the nim-sum of an NN-heap position after NN row updates. With O(B)O(B) state bits, it can also retain the previous completed nim-sum and report the XOR difference between consecutive completed positions.

Generated from paper_jmlr.tex, lines 836–839.

2 Explain this

The update. Keep a BB-bit accumulator ss. For each row xx: s←s⊕xs\leftarrow s\oplus x. After NN rows, ss is the nim-sum of the position. Each update XORs two BB-bit numbers bit by bit, a constant-depth operation.

Remembering the previous position. Keep a second register qq and a validity bit vv. At a separator: output ss (and q⊕sq\oplus s if v=1v=1), then set q←sq\leftarrow s, s←0s\leftarrow0, v←1v\leftarrow1. So the machine also reports the difference between consecutive positions' nim-sums.

Example. For 3,5,6,SEP,3,4,6,SEP3,5,6,\mathtt{SEP},3,4,6,\mathtt{SEP}: ss goes 3,6,03, 6, 0; at the first SEP it outputs 00; then ss goes 3,7,13,7,1; at the second SEP it outputs 11 and the difference 0⊕1=10\oplus1=1.

Why it matters. The update is shallow; the computation as a whole takes NN updates. The bypass works by letting the number of updates grow, which the simulation theorem forbids for fixed-latency models.

Row-wise recurrence: registers, separators and replay

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

The board arrives as a stream of rows, one heap per token, with separators (SEP) between positions and a reset at the start of a game. Step through the replay controller: in scan mode it XORs each row into the accumulator; the first separator outputs the summary, stores it and switches to replay mode; during replay the same rows arrive again and each is tested against the stored summary, keeping the first cancelling candidate and a fallback; the second separator outputs the move. The board-storage variant instead writes the rows into memory and chooses the move at its single separator. In the replay controller a separator clears the accumulator and keeps the summary of the position just completed, with its validity bit; an extra separator is read as an empty position, whose summary is 0. Only a reset returns every register, validity included, to its initial value. The board-storage separator clears its accumulator and pointer and keeps the stored board. The third protocol shows the summary mechanism of Proposition 5.13 alone: it reports summaries and differences but chooses no move.

The current NIM board already determines optimal play. The memory shown here makes that answer computationally accessible by retaining partial results across rows; an earlier game position is needed only for the optional comparison of consecutive positions.

  1. row 3scan
  2. row 4scan
  3. row 6scan
  4. SEPsummary
  5. row 2scan
  6. row 4scan
  7. row 1scan
  8. SEPsummary

8 / 8 SEP: separator: output the summary (and, if one is stored, the difference from it); keep the summary as the previous one; clear the accumulator

Registers after this update

accumulator s
0 000
previous summary q
7 111
validity v
1

Outputs so far

  • after token 4: summary σ = 1 (no previous summary)
  • after token 8: summary σ = 7, difference from the previous summary 6

Counting the work

  • Each position of 3 heaps takes N + 1 = 4 updates: its rows and a separator. The state is (s, q, v): 2B + 1 = 7 bits.
  • The summary alone does not choose a move: that needs the rows again (replay) or a stored board.
  • Each output bit of one update is a formula of depth ≤ 4. The number of sequential updates grows with N. That no shallow family computes the complete board-to-move map is a separate statement, conditional on the named classical input that parity is not in AC0.
All 8 updates as a table
#TokenRegisters afterOutput
1row 3s 3, q 0, v 0
2row 4s 7, q 0, v 0
3row 6s 1, q 0, v 0
4SEPs 0, q 1, v 1σ = 1
5row 2s 2, q 1, v 1
6row 4s 6, q 1, v 1
7row 1s 7, q 1, v 1
8SEPs 0, q 7, v 1σ = 7, diff 6

Game: (3, 4, 6) —your move (δ = 1)→ (2, 4, 6) —opponent (δ = 7)→ (2, 4, 1)

Only the boards at your decision times

Position fedsummary σdifference
(3, 4, 6)1—
(2, 4, 1)76

The difference 6 = 1 ⊕ 7 spans two moves: yours and the opponent’s.

Including your own post-move board

Position fedsummary σdifference
(3, 4, 6)1—
(2, 4, 6)01
(2, 4, 1)77

Now the last difference is 7, the opponent’s move alone, because your post-move board (2, 4, 6) is the preceding frame.

Computed with the summary mechanism (s, q, v).

How this relates to the Lean proof. Each update is one step of Controller.cstep (replay) or BoardStore.bsStep (board storage) on the token streams Controller.dtoks and BoardStore.btoks. The whole-game theorems WholeGame.replay_wins and BoardStore.bits_store_wins prove that, from every board with nonzero nim-sum, iterating these updates wins against every legal opponent. The summary mechanism is Recurrent.step. The comparison of decision-time boards with the post-move board is Bypass.diff_with_postMove and Bypass.diff_decision_only.

What this does not show. Each single update is shallow; the number of updates per decision (2N+22N+2, or N+1N+1 with board storage) grows with the board. That no shallow family computes the complete board-to-move map is a separate statement, conditional on the named classical input that parity is not in AC0\mathrm{AC}^0. The edge cases (an extra separator, a reset) lie outside the protocol streams that the theorems quantify over; the update rule is simply applied. The recurrent strategies are proved in their own stateful game semantics; connecting them to the later history model of weak mastery is a separate adapter that has not been built (coverage record). No recurrent network was trained.

Depicted in Lean: Controller.cstep, Controller.dtoks, Recurrent.replayStep, Recurrent.step, Recurrent.sep_resets, ControllerBits.bstep_reset, BoardStore.bsStep, BoardStore.btoks, Controller.crun_decision, Controller.stream_fits, WholeGame.replay_wins, BoardStore.bits_store_wins, Bypass.diff_with_postMove, Bypass.diff_decision_only, Recurrent.circuit_resources, BoardStore.bsForms_res, BoardStore.bsOuts_res, BoardStore.bs_net.

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 566 reference cases. The comparison compares every register and output after every token.

3 How this is formalised

  • Recurrent.fold_invariant: from any state with empty accumulator, for any finite sequence of positions, the tt-th output is (σ(Pt),Δ)(\sigma(P_t), \Delta) with Δ=σ(Pt−1)⊕σ(Pt)\Delta=\sigma(P_{t-1})\oplus\sigma(P_t) for t≥2t\ge2 (and determined by the starting state for t=1t=1).
  • Recurrent.stream_reports_delta: from the initial state the first output has no difference and the second reports nim⁡(Q)⊕nim⁡(Q′)\operatorname{nim}(Q)\oplus\operatorname{nim}(Q').
  • Recurrent.circuit_update and Recurrent.circuit_step_correct: 2B+12B+1 state bits suffice and explicit per-bit circuits compute the update.
  • Recurrent.circuit_resources: depth at most 44, total size at most 28B+828B+8.
  • Recurrent.xorNet_correct: a fixed-scale threshold realisation of one XOR bit update.
Coverage record
Paper anchorprop:streaming-nimsum (manuscript label)
Displayed asProposition 5.13
ClaimA constant-depth recurrent update computes the nim-sum after N row updates and reports consecutive differences
Coverage categoryChecked theorem
Statement sourcepaper_jmlr.tex lines 836–839; SHA-256 of the normalised block source bacb9fc36383f788…
Lean declarations
Assumptions and domain

Rows are BB-bit numbers in a fixed heap order; state (s,q,v)(s,q,v) of 2B+12B+1 bits; a reset between games restores (0,0,0)(0,0,0).

Prose-to-formal notes

Lean checks the per-update circuit (depth at most 4, size at most 28B+828B+8) and a fixed-scale XOR realisation. The summary mechanism stores summaries, not the history.

Audited correspondence rowsprop:streaming-nimsum
Explanationsexplain/prop:streaming-nimsum, formal/prop:streaming-nimsum
Build evidencefresh isolated rebuild, audit report

4 Lean statement and source

Principal declarations

theorem Recurrent.fold_invariant

Module NimRecurrent (lean/phase3/NimRecurrent.lean, lines 95–109) · file SHA-256 1f2994aefc75e7f5… Axioms reported by the fresh build: propext, Quot.sound

FOLD INVARIANT. From any state with empty accumulator, for ANY finite sequence of positions (empty positions allowed): the t-th output is (sigma(P_t), Delta) where Delta = prev XOR sigma(P_1) if the starting state is valid (none otherwise) for t = 1 and sigma(P_{t-1}) XOR sigma(P_t) for t ≥ 2; the final state retains the last summary with valid = true and acc = 0.

Statement as elaborated and printed by Lean 4.26.0

∀ (s : NimAudit.Recurrent.State),
  s.acc = 0 →
    ∀ (Ps : List (List ℕ)),
      NimAudit.Recurrent.run s (NimAudit.Recurrent.serialize Ps) =
        (NimAudit.Recurrent.expectedState s Ps, NimAudit.Recurrent.expectedOuts s.valid s.prev Ps)
Exact source text, lines 95–109
95/-- FOLD INVARIANT.  From any state with empty accumulator, for ANY finite sequence96    of positions (empty positions allowed): the t-th output is97    (sigma(P_t), Delta) where Delta = prev XOR sigma(P_1) if the starting state is98    valid (none otherwise) for t = 1 and sigma(P_{t-1}) XOR sigma(P_t) for t ≥ 2;99    the final state retains the last summary with valid = true and acc = 0. -/100theorem fold_invariant (s : State) (hs : s.acc = 0) (Ps : List (List Nat)) :101    run s (serialize Ps) = (expectedState s Ps, expectedOuts s.valid s.prev Ps) := by102  induction Ps generalizing s with103  | nil => simp [serialize, run, expectedState, expectedOuts]104  | cons P Ps ih =>105    have e : serialize (P :: Ps) = (P.map Token.row ++ [Token.sep]) ++ serialize Ps := by106      simp [serialize]107    rw [e, run_append, run_position, hs, Nat.zero_xor]108    rw [ih ⟨0, nimSum P, true⟩ rfl]109    simp [expectedState, expectedOuts]

Project declarations in the statement: Recurrent.Out, Recurrent.State, Recurrent.State.acc, Recurrent.State.prev, Recurrent.State.valid, Recurrent.expectedOuts, Recurrent.expectedState, Recurrent.run, Recurrent.serialize

Project declarations used by the proof or definition body

Recurrent.Out, Recurrent.Out.mk, Recurrent.State, Recurrent.State.acc, Recurrent.State.mk, Recurrent.State.prev, Recurrent.State.valid, Recurrent.Token, Recurrent.Token.row, Recurrent.Token.sep, Recurrent.expectedOuts, Recurrent.expectedState, Recurrent.run, Recurrent.run_append, Recurrent.run_position, Recurrent.serialize, nimSum

theorem Recurrent.stream_reports_delta

Module NimRecurrent (lean/phase3/NimRecurrent.lean, lines 173–177) · file SHA-256 1f2994aefc75e7f5… Axioms reported by the fresh build: propext

Statement as elaborated and printed by Lean 4.26.0

∀ (Q Q' : List ℕ) (Ps : List (List ℕ)),
  NimAudit.Recurrent.expectedOuts false 0 (Q :: Q' :: Ps) =
    { summary := NimAudit.nimSum Q, diff := none } ::
      { summary := NimAudit.nimSum Q', diff := some (NimAudit.nimSum Q ^^^ NimAudit.nimSum Q') } ::
        NimAudit.Recurrent.expectedOuts true (NimAudit.nimSum Q') Ps
Exact source text, lines 173–177
173theorem stream_reports_delta (Q Q' : List Nat) (Ps : List (List Nat)) :174    expectedOuts false 0 (Q :: Q' :: Ps) =175      ⟨nimSum Q, none⟩ :: ⟨nimSum Q', some (nimSum Q ^^^ nimSum Q')⟩ ::176        expectedOuts true (nimSum Q') Ps := by177  simp [expectedOuts]

Project declarations in the statement: Recurrent.Out, Recurrent.Out.mk, Recurrent.expectedOuts, nimSum

Project declarations used by the proof or definition body

Recurrent.Out, Recurrent.Out.mk, Recurrent.expectedOuts, nimSum

theorem Recurrent.circuit_update

Module NimRecurrent (lean/phase3/NimRecurrent.lean, lines 422–441) · file SHA-256 1f2994aefc75e7f5… Axioms reported by the fresh build: propext, Classical.choice, Quot.sound

PER-UPDATE CIRCUIT CORRECTNESS (k < B): the circuits compute the new state bits and, at a separator, the output bits.

Statement as elaborated and printed by Lean 4.26.0

∀ {B k : ℕ},
  k < B →
    ∀ (s : NimAudit.Recurrent.State) (t : NimAudit.Recurrent.Token),
      NimAudit.AC0.Circ.eval (NimAudit.Recurrent.encode B s t) (NimAudit.Recurrent.accC B k) =
          (NimAudit.Recurrent.step s t).1.acc.testBit k ∧
        NimAudit.AC0.Circ.eval (NimAudit.Recurrent.encode B s t) (NimAudit.Recurrent.prevC B k) =
            (NimAudit.Recurrent.step s t).1.prev.testBit k ∧
          NimAudit.AC0.Circ.eval (NimAudit.Recurrent.encode B s t) (NimAudit.Recurrent.validC B) =
              (NimAudit.Recurrent.step s t).1.valid ∧
            (t = NimAudit.Recurrent.Token.sep →
              NimAudit.AC0.Circ.eval (NimAudit.Recurrent.encode B s t) (NimAudit.AC0.Circ.input k) =
                  s.acc.testBit k ∧
                NimAudit.AC0.Circ.eval (NimAudit.Recurrent.encode B s t)
                      (NimAudit.Recurrent.diffC B k) =
                    (s.prev ^^^ s.acc).testBit k ∧
                  NimAudit.AC0.Circ.eval (NimAudit.Recurrent.encode B s t)
                      (NimAudit.Recurrent.diffValidC B) =
                    s.valid)
Exact source text, lines 422–441
422/-- PER-UPDATE CIRCUIT CORRECTNESS (k < B): the circuits compute the new state bits423    and, at a separator, the output bits. -/424theorem circuit_update {B k : Nat} (hk : k < B) (s : State) (t : Token) :425    eval (encode B s t) (accC B k) = (step s t).1.acc.testBit k ∧426    eval (encode B s t) (prevC B k) = (step s t).1.prev.testBit k ∧427    eval (encode B s t) (validC B) = (step s t).1.valid ∧428    (t = Token.sep → eval (encode B s t) (input k) = s.acc.testBit k ∧429      eval (encode B s t) (diffC B k) = (s.prev ^^^ s.acc).testBit k ∧430      eval (encode B s t) (diffValidC B) = s.valid) := by431  cases t with432  | row x =>433    simp only [accC, prevC, validC, eval_and, eval_or, eval_not, eval_input, eval_xorC,434      List.all_cons, List.all_nil, List.any_cons, List.any_nil, enc_acc hk, enc_prev hk,435      enc_valid, enc_tag, enc_x hk, step, Nat.testBit_xor]436    refine ⟨by simp, by simp, by simp, fun h => by cases h⟩437  | sep =>438    simp only [accC, prevC, validC, diffC, diffValidC, eval_and, eval_or, eval_not, eval_input,439      eval_xorC, List.all_cons, List.all_nil, List.any_cons, List.any_nil, enc_acc hk,440      enc_prev hk, enc_valid, enc_tag, step, Nat.testBit_xor, Nat.zero_testBit]441    refine ⟨by simp, by simp, by simp, fun _ => ⟨by simp, by simp, by simp⟩⟩

Project declarations in the statement: AC0.Circ.eval, AC0.Circ.input, Recurrent.Out, Recurrent.State, Recurrent.State.acc, Recurrent.State.prev, Recurrent.State.valid, Recurrent.Token, Recurrent.Token.sep, Recurrent.accC, Recurrent.diffC, Recurrent.diffValidC, Recurrent.encode, Recurrent.prevC, Recurrent.step, Recurrent.validC

Project declarations used by the proof or definition body

AC0.Circ, AC0.Circ.and, AC0.Circ.eval, AC0.Circ.eval_and, AC0.Circ.eval_input, AC0.Circ.eval_not, AC0.Circ.eval_or, AC0.Circ.input, AC0.Circ.not, AC0.Circ.or, Recurrent.Out, Recurrent.State, Recurrent.State.acc, Recurrent.State.prev, Recurrent.State.valid, Recurrent.Token, Recurrent.Token.casesOn, Recurrent.Token.row, Recurrent.Token.sep, Recurrent.accC, Recurrent.diffC, Recurrent.diffValidC, Recurrent.enc_acc, Recurrent.enc_prev, Recurrent.enc_tag, Recurrent.enc_valid, Recurrent.enc_x, Recurrent.encode, Recurrent.eval_xorC, Recurrent.prevC, Recurrent.step, Recurrent.validC, Recurrent.xorC

theorem Recurrent.circuit_step_correct

Module NimRecurrent (lean/phase3/NimRecurrent.lean, lines 458–489) · file SHA-256 1f2994aefc75e7f5… Axioms reported by the fresh build: propext, Classical.choice, Quot.sound

STATE-BIT THEOREM: 2B+1 bits suffice, and the per-update circuit maps the bit encoding of a B-bit state to the bit encoding of its successor.

Statement as elaborated and printed by Lean 4.26.0

∀ {B : ℕ} {s : NimAudit.Recurrent.State} {t : NimAudit.Recurrent.Token},
  NimAudit.Recurrent.StateWidth B s →
    NimAudit.Recurrent.TokenWidth B t →
      (NimAudit.Recurrent.stateOfBits B fun j =>
          if j < B then
            NimAudit.AC0.Circ.eval (NimAudit.Recurrent.encode B s t) (NimAudit.Recurrent.accC B j)
          else
            if j < 2 * B then
              NimAudit.AC0.Circ.eval (NimAudit.Recurrent.encode B s t)
                (NimAudit.Recurrent.prevC B (j - B))
            else
              NimAudit.AC0.Circ.eval (NimAudit.Recurrent.encode B s t)
                (NimAudit.Recurrent.validC B)) =
        (NimAudit.Recurrent.step s t).1
Exact source text, lines 458–489
458/-- STATE-BIT THEOREM: 2B+1 bits suffice, and the per-update circuit maps the bit459    encoding of a B-bit state to the bit encoding of its successor. -/460theorem circuit_step_correct {B : Nat} {s : State} {t : Token} (hs : StateWidth B s)461    (ht : TokenWidth B t) :462    stateOfBits B (fun j =>463        if j < B then eval (encode B s t) (accC B j)464        else if j < 2 * B then eval (encode B s t) (prevC B (j - B))465        else eval (encode B s t) (validC B)) = (step s t).1 := by466  have hw := step_width hs ht467  unfold stateOfBits468  have h1 : ofBits B (fun k => if k < B then eval (encode B s t) (accC B k)469      else if k < 2 * B then eval (encode B s t) (prevC B (k - B))470      else eval (encode B s t) (validC B)) = (step s t).1.acc := by471    apply ofBits_testBit_eq hw.1472    intro k hk473    simp only [hk, if_true]474    exact (circuit_update hk s t).1475  have h2 : ofBits B (fun k => if B + k < B then eval (encode B s t) (accC B (B + k))476      else if B + k < 2 * B then eval (encode B s t) (prevC B (B + k - B))477      else eval (encode B s t) (validC B)) = (step s t).1.prev := by478    apply ofBits_testBit_eq hw.2479    intro k hk480    simp only [show ¬ B + k < B by omega, show B + k < 2 * B by omega, if_true, if_false,481      show B + k - B = k by omega]482    exact (circuit_update hk s t).2.1483  have h3 : (if 2 * B < B then eval (encode B s t) (accC B (2 * B))484      else if 2 * B < 2 * B then eval (encode B s t) (prevC B (2 * B - B))485      else eval (encode B s t) (validC B)) = (step s t).1.valid := by486    simp only [show ¬ 2 * B < B by omega, Nat.lt_irrefl, if_false]487    cases t <;> simp [validC, enc_valid, enc_tag, step]488  simp only []489  rw [h1, h2, h3]

Project declarations in the statement: AC0.Circ.eval, Recurrent.Out, Recurrent.State, Recurrent.StateWidth, Recurrent.Token, Recurrent.TokenWidth, Recurrent.accC, Recurrent.encode, Recurrent.prevC, Recurrent.stateOfBits, Recurrent.step, Recurrent.validC

Project declarations used by the proof or definition body

AC0.Circ, AC0.Circ.eval, AC0.Circ.eval_input, AC0.Circ.eval_not, AC0.Circ.eval_or, AC0.Circ.input, AC0.Circ.not, AC0.Circ.or, Game.ofBits, Recurrent.Out, Recurrent.State, Recurrent.State.acc, Recurrent.State.mk, Recurrent.State.prev, Recurrent.State.valid, Recurrent.StateWidth, Recurrent.Token, Recurrent.Token.casesOn, Recurrent.Token.row, Recurrent.Token.sep, Recurrent.TokenWidth, Recurrent.accC, Recurrent.circuit_update, Recurrent.diffC, Recurrent.diffValidC, Recurrent.enc_tag, Recurrent.enc_valid, Recurrent.encode, Recurrent.ofBits_testBit_eq, Recurrent.prevC, Recurrent.stateOfBits, Recurrent.step, Recurrent.step_width, Recurrent.validC

theorem Recurrent.circuit_resources

Module NimRecurrent (lean/phase3/NimRecurrent.lean, lines 491–498) · file SHA-256 1f2994aefc75e7f5… Axioms reported by the fresh build: propext, Quot.sound

Per-update circuit resources: depth ≤ 4, total size ≤ 28 B + 8 for all state and output bits (constant depth, O(B) size).

Statement as elaborated and printed by Lean 4.26.0

∀ (B k : ℕ),
  (NimAudit.Recurrent.accC B k).depth ≤ 4 ∧
    (NimAudit.Recurrent.prevC B k).depth ≤ 4 ∧
      (NimAudit.Recurrent.validC B).depth ≤ 4 ∧
        (NimAudit.Recurrent.diffC B k).depth ≤ 4 ∧
          (NimAudit.Recurrent.diffValidC B).depth ≤ 4 ∧
            (NimAudit.Recurrent.accC B k).size + (NimAudit.Recurrent.prevC B k).size +
                  (NimAudit.Recurrent.diffC B k).size ≤
                28 ∧
              (NimAudit.Recurrent.validC B).size + (NimAudit.Recurrent.diffValidC B).size ≤ 8
Exact source text, lines 491–498
491/-- Per-update circuit resources: depth ≤ 4, total size ≤ 28 B + 8 for all492    state and output bits (constant depth, O(B) size). -/493theorem circuit_resources (B k : Nat) :494    depth (accC B k) ≤ 4 ∧ depth (prevC B k) ≤ 4 ∧ depth (validC B) ≤ 4 ∧495    depth (diffC B k) ≤ 4 ∧ depth (diffValidC B) ≤ 4 ∧496    size (accC B k) + size (prevC B k) + size (diffC B k) ≤ 28 ∧497    size (validC B) + size (diffValidC B) ≤ 8 := by498  simp [accC, prevC, validC, diffC, diffValidC, xorC, listMax]

Project declarations in the statement: AC0.Circ.depth, AC0.Circ.size, Recurrent.accC, Recurrent.diffC, Recurrent.diffValidC, Recurrent.prevC, Recurrent.validC

Project declarations used by the proof or definition body

AC0.Circ, AC0.Circ.and, AC0.Circ.depth, AC0.Circ.depth_and, AC0.Circ.depth_input, AC0.Circ.depth_not, AC0.Circ.depth_or, AC0.Circ.input, AC0.Circ.listMax, AC0.Circ.not, AC0.Circ.or, AC0.Circ.size, AC0.Circ.size_and, AC0.Circ.size_input, AC0.Circ.size_not, AC0.Circ.size_or

theorem Recurrent.xorNet_correct

Module NimRecurrent (lean/phase3/NimRecurrent.lean, lines 511–513) · file SHA-256 1f2994aefc75e7f5… Axioms reported by the fresh build: none

Statement as elaborated and printed by Lean 4.26.0

∀ (a b : Bool),
  NimAudit.AC0.evalNet NimAudit.Recurrent.xorNet
      (fun j => if j = 0 then a else if j = 1 then b else false) 0 =
    (a ^^ b)
Exact source text, lines 511–513
511theorem xorNet_correct (a b : Bool) :512    evalNet xorNet (fun j => if j = 0 then a else if j = 1 then b else false) 0 = xor a b := by513  cases a <;> cases b <;> decide

Project declarations in the statement: AC0.evalNet, Recurrent.xorNet

Project declarations used by the proof or definition body

AC0.evalNet, Recurrent.xorNet

Definitions these statements use

inductive Recurrent.Out

Module NimRecurrent (lean/phase3/NimRecurrent.lean, lines 41–43) · file SHA-256 1f2994aefc75e7f5…

Statement as elaborated and printed by Lean 4.26.0

Type
Exact source text, lines 41–43
41structure Out where42  summary : Nat43  diff : Option Nat

Project declarations in the statement: none

Project declarations used by the proof or definition body

none

inductive Recurrent.State

Module NimRecurrent (lean/phase3/NimRecurrent.lean, lines 36–39) · file SHA-256 1f2994aefc75e7f5…

Statement as elaborated and printed by Lean 4.26.0

Type
Exact source text, lines 36–39
36structure State where37  acc : Nat38  prev : Nat39  valid : Bool

Project declarations in the statement: none

Project declarations used by the proof or definition body

none

def Recurrent.State.acc

Module NimRecurrent (lean/phase3/NimRecurrent.lean, lines 37–37) · file SHA-256 1f2994aefc75e7f5…

Statement as elaborated and printed by Lean 4.26.0

NimAudit.Recurrent.State → ℕ
Exact source text, lines 37–37
37  acc : Nat

Project declarations in the statement: Recurrent.State

Project declarations used by the proof or definition body

Recurrent.State

def Recurrent.State.prev

Module NimRecurrent (lean/phase3/NimRecurrent.lean, lines 38–38) · file SHA-256 1f2994aefc75e7f5…

Statement as elaborated and printed by Lean 4.26.0

NimAudit.Recurrent.State → ℕ
Exact source text, lines 38–38
38  prev : Nat

Project declarations in the statement: Recurrent.State

Project declarations used by the proof or definition body

Recurrent.State

def Recurrent.State.valid

Module NimRecurrent (lean/phase3/NimRecurrent.lean, lines 39–39) · file SHA-256 1f2994aefc75e7f5…

Statement as elaborated and printed by Lean 4.26.0

NimAudit.Recurrent.State → Bool
Exact source text, lines 39–39
39  valid : Bool

Project declarations in the statement: Recurrent.State

Project declarations used by the proof or definition body

Recurrent.State

def Recurrent.expectedOuts

Module NimRecurrent (lean/phase3/NimRecurrent.lean, lines 84–88) · file SHA-256 1f2994aefc75e7f5…

Expected outputs for a sequence of positions from a state with empty accumulator.

Statement as elaborated and printed by Lean 4.26.0

Bool → ℕ → List (List ℕ) → List NimAudit.Recurrent.Out
Exact source text, lines 84–88
84/-- Expected outputs for a sequence of positions from a state with empty accumulator. -/85def expectedOuts : Bool → Nat → List (List Nat) → List Out86  | _, _, [] => []87  | v, q, P :: Ps =>88    ⟨nimSum P, if v then some (q ^^^ nimSum P) else none⟩ :: expectedOuts true (nimSum P) Ps

Project declarations in the statement: Recurrent.Out

Project declarations used by the proof or definition body

Recurrent.Out, Recurrent.Out.mk, nimSum

def Recurrent.expectedState

Module NimRecurrent (lean/phase3/NimRecurrent.lean, lines 90–93) · file SHA-256 1f2994aefc75e7f5…

Expected final state.

Statement as elaborated and printed by Lean 4.26.0

NimAudit.Recurrent.State → List (List ℕ) → NimAudit.Recurrent.State
Exact source text, lines 90–93
90/-- Expected final state. -/91def expectedState : State → List (List Nat) → State92  | s, [] => s93  | _, P :: Ps => expectedState ⟨0, nimSum P, true⟩ Ps

Project declarations in the statement: Recurrent.State

Project declarations used by the proof or definition body

Recurrent.State, Recurrent.State.mk, nimSum

def Recurrent.run

Module NimRecurrent (lean/phase3/NimRecurrent.lean, lines 52–55) · file SHA-256 1f2994aefc75e7f5…

Run the recurrence over a token list, collecting outputs.

Statement as elaborated and printed by Lean 4.26.0

NimAudit.Recurrent.State →
  List NimAudit.Recurrent.Token → NimAudit.Recurrent.State × List NimAudit.Recurrent.Out
Exact source text, lines 52–55
52/-- Run the recurrence over a token list, collecting outputs. -/53def run : State → List Token → State × List Out54  | s, [] => (s, [])55  | s, t :: ts => ((run (step s t).1 ts).1, (step s t).2.toList ++ (run (step s t).1 ts).2)

Project declarations in the statement: Recurrent.Out, Recurrent.State, Recurrent.Token

Project declarations used by the proof or definition body

Recurrent.Out, Recurrent.State, Recurrent.Token, Recurrent.step

def Recurrent.serialize

Module NimRecurrent (lean/phase3/NimRecurrent.lean, lines 57–59) · file SHA-256 1f2994aefc75e7f5…

Serialise positions: rows then SEP, position after position.

Statement as elaborated and printed by Lean 4.26.0

List (List ℕ) → List NimAudit.Recurrent.Token
Exact source text, lines 57–59
57/-- Serialise positions: rows then SEP, position after position. -/58def serialize (Ps : List (List Nat)) : List Token :=59  Ps.flatMap (fun P => P.map Token.row ++ [Token.sep])

Project declarations in the statement: Recurrent.Token

Project declarations used by the proof or definition body

Recurrent.Token, Recurrent.Token.row, Recurrent.Token.sep

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

def AC0.Circ.eval

Module Circuit (lean/phase3/Circuit.lean, lines 44–49) · file SHA-256 af97cc0eec7d8464…

Statement as elaborated and printed by Lean 4.26.0

(ℕ → Bool) → NimAudit.AC0.Circ → Bool
Exact source text, lines 44–49
44def eval (x : Nat → Bool) : Circ → Bool45  | input i => x i46  | const b => b47  | not c => !(eval x c)48  | and cs => cs.attach.all (fun ⟨c, _⟩ => eval x c)49  | or cs => cs.attach.any (fun ⟨c, _⟩ => eval x c)

Project declarations in the statement: AC0.Circ

Project declarations used by the proof or definition body

AC0.Circ, AC0.Circ.and, AC0.Circ.casesOn, AC0.Circ.const, AC0.Circ.input, AC0.Circ.not, AC0.Circ.or, AC0.Circ.rec, AC0.Circ.rec_1

inductive Recurrent.Token

Module NimRecurrent (lean/phase3/NimRecurrent.lean, lines 32–34) · file SHA-256 1f2994aefc75e7f5…

Statement as elaborated and printed by Lean 4.26.0

Type
Exact source text, lines 32–34
32inductive Token where33  | row (x : Nat)34  | sep

Project declarations in the statement: none

Project declarations used by the proof or definition body

none

def Recurrent.accC

Module NimRecurrent (lean/phase3/NimRecurrent.lean, lines 388–388) · file SHA-256 1f2994aefc75e7f5…

Statement as elaborated and printed by Lean 4.26.0

ℕ → ℕ → NimAudit.AC0.Circ
Exact source text, lines 388–388
388def accC (B k : Nat) : Circ := and [input (2 * B + 1), xorC (input k) (input (2 * B + 2 + k))]

Project declarations in the statement: AC0.Circ

Project declarations used by the proof or definition body

AC0.Circ, AC0.Circ.and, AC0.Circ.input, Recurrent.xorC

def Recurrent.diffC

Module NimRecurrent (lean/phase3/NimRecurrent.lean, lines 392–392) · file SHA-256 1f2994aefc75e7f5…

Statement as elaborated and printed by Lean 4.26.0

ℕ → ℕ → NimAudit.AC0.Circ
Exact source text, lines 392–392
392def diffC (B k : Nat) : Circ := xorC (input (B + k)) (input k)

Project declarations in the statement: AC0.Circ

Project declarations used by the proof or definition body

AC0.Circ.input, Recurrent.xorC

def Recurrent.diffValidC

Module NimRecurrent (lean/phase3/NimRecurrent.lean, lines 393–393) · file SHA-256 1f2994aefc75e7f5…

Statement as elaborated and printed by Lean 4.26.0

ℕ → NimAudit.AC0.Circ
Exact source text, lines 393–393
393def diffValidC (B : Nat) : Circ := and [input (2 * B), not (input (2 * B + 1))]

Project declarations in the statement: AC0.Circ

Project declarations used by the proof or definition body

AC0.Circ, AC0.Circ.and, AC0.Circ.input, AC0.Circ.not

def Recurrent.encode

Module NimRecurrent (lean/phase3/NimRecurrent.lean, lines 377–385) · file SHA-256 1f2994aefc75e7f5…

Input layout of one update: acc bits 0..B-1, prev bits B..2B-1, valid 2B, tag 2B+1 (true = row), row bits 2B+2..3B+1.

Statement as elaborated and printed by Lean 4.26.0

ℕ → NimAudit.Recurrent.State → NimAudit.Recurrent.Token → ℕ → Bool
Exact source text, lines 377–385
377/-- Input layout of one update: acc bits 0..B-1, prev bits B..2B-1, valid 2B,378    tag 2B+1 (true = row), row bits 2B+2..3B+1. -/379def encode (B : Nat) (s : State) (t : Token) : Nat → Bool := fun j =>380  if j < B then s.acc.testBit j381  else if j < 2 * B then s.prev.testBit (j - B)382  else if j = 2 * B then s.valid383  else if j = 2 * B + 1 then (match t with | .row _ => true | .sep => false)384  else if j < 3 * B + 2 then (match t with | .row x => x.testBit (j - (2 * B + 2)) | .sep => false)385  else false

Project declarations in the statement: Recurrent.State, Recurrent.Token

Project declarations used by the proof or definition body

Recurrent.State, Recurrent.State.acc, Recurrent.State.prev, Recurrent.State.valid, Recurrent.Token, Recurrent.Token.casesOn, Recurrent.Token.row, Recurrent.Token.sep

def Recurrent.prevC

Module NimRecurrent (lean/phase3/NimRecurrent.lean, lines 389–390) · file SHA-256 1f2994aefc75e7f5…

Statement as elaborated and printed by Lean 4.26.0

ℕ → ℕ → NimAudit.AC0.Circ
Exact source text, lines 389–390
389def prevC (B k : Nat) : Circ :=390  or [and [input (2 * B + 1), input (B + k)], and [not (input (2 * B + 1)), input k]]

Project declarations in the statement: AC0.Circ

Project declarations used by the proof or definition body

AC0.Circ, AC0.Circ.and, AC0.Circ.input, AC0.Circ.not, AC0.Circ.or

def Recurrent.step

Module NimRecurrent (lean/phase3/NimRecurrent.lean, lines 47–50) · file SHA-256 1f2994aefc75e7f5…

One recurrent update; SEP produces an output.

Statement as elaborated and printed by Lean 4.26.0

NimAudit.Recurrent.State →
  NimAudit.Recurrent.Token → NimAudit.Recurrent.State × Option NimAudit.Recurrent.Out
Exact source text, lines 47–50
47/-- One recurrent update; SEP produces an output. -/48def step (s : State) : Token → State × Option Out49  | .row x => (⟨s.acc ^^^ x, s.prev, s.valid⟩, none)50  | .sep => (⟨0, s.acc, true⟩, some ⟨s.acc, if s.valid then some (s.prev ^^^ s.acc) else none⟩)

Project declarations in the statement: Recurrent.Out, Recurrent.State, Recurrent.Token

Project declarations used by the proof or definition body

Recurrent.Out, Recurrent.Out.mk, Recurrent.State, Recurrent.State.acc, Recurrent.State.mk, Recurrent.State.prev, Recurrent.State.valid, Recurrent.Token, Recurrent.Token.casesOn, Recurrent.Token.row, Recurrent.Token.sep

def Recurrent.validC

Module NimRecurrent (lean/phase3/NimRecurrent.lean, lines 391–391) · file SHA-256 1f2994aefc75e7f5…

Statement as elaborated and printed by Lean 4.26.0

ℕ → NimAudit.AC0.Circ
Exact source text, lines 391–391
391def validC (B : Nat) : Circ := or [input (2 * B), not (input (2 * B + 1))]

Project declarations in the statement: AC0.Circ

Project declarations used by the proof or definition body

AC0.Circ, AC0.Circ.input, AC0.Circ.not, AC0.Circ.or

def Recurrent.StateWidth

Module NimRecurrent (lean/phase3/NimRecurrent.lean, lines 138–139) · file SHA-256 1f2994aefc75e7f5…

WIDTH PRESERVATION: B-bit rows keep acc and prev below 2^B.

Statement as elaborated and printed by Lean 4.26.0

ℕ → NimAudit.Recurrent.State → Prop
Exact source text, lines 138–139
138/-- WIDTH PRESERVATION: B-bit rows keep acc and prev below 2^B. -/139def StateWidth (B : Nat) (s : State) : Prop := s.acc < 2 ^ B ∧ s.prev < 2 ^ B

Project declarations in the statement: Recurrent.State

Project declarations used by the proof or definition body

Recurrent.State, Recurrent.State.acc, Recurrent.State.prev

def Recurrent.TokenWidth

Module NimRecurrent (lean/phase3/NimRecurrent.lean, lines 141–143) · file SHA-256 1f2994aefc75e7f5…

Statement as elaborated and printed by Lean 4.26.0

ℕ → NimAudit.Recurrent.Token → Prop
Exact source text, lines 141–143
141def TokenWidth (B : Nat) : Token → Prop142  | .row x => x < 2 ^ B143  | .sep => True

Project declarations in the statement: Recurrent.Token

Project declarations used by the proof or definition body

Recurrent.Token, Recurrent.Token.casesOn, Recurrent.Token.row, Recurrent.Token.sep

def Recurrent.stateOfBits

Module NimRecurrent (lean/phase3/NimRecurrent.lean, lines 443–445) · file SHA-256 1f2994aefc75e7f5…

The 2B+1 state bits determine the state (B-bit width).

Statement as elaborated and printed by Lean 4.26.0

ℕ → (ℕ → Bool) → NimAudit.Recurrent.State
Exact source text, lines 443–445
443/-- The 2B+1 state bits determine the state (B-bit width). -/444def stateOfBits (B : Nat) (bits : Nat → Bool) : State :=445  ⟨ofBits B (fun k => bits k), ofBits B (fun k => bits (B + k)), bits (2 * B)⟩

Project declarations in the statement: Recurrent.State

Project declarations used by the proof or definition body

Game.ofBits, Recurrent.State.mk

def AC0.Circ.depth

Module Circuit (lean/phase3/Circuit.lean, lines 61–66) · file SHA-256 af97cc0eec7d8464…

Statement as elaborated and printed by Lean 4.26.0

NimAudit.AC0.Circ → ℕ
Exact source text, lines 61–66
61def depth : Circ → Nat62  | input _ => 063  | const _ => 064  | not c => depth c + 165  | and cs => listMax (cs.attach.map (fun ⟨c, _⟩ => depth c)) + 166  | or cs => listMax (cs.attach.map (fun ⟨c, _⟩ => depth c)) + 1

Project declarations in the statement: AC0.Circ

Project declarations used by the proof or definition body

AC0.Circ, AC0.Circ.and, AC0.Circ.casesOn, AC0.Circ.const, AC0.Circ.input, AC0.Circ.listMax, AC0.Circ.not, AC0.Circ.or, AC0.Circ.rec, AC0.Circ.rec_1

def AC0.Circ.size

Module Circuit (lean/phase3/Circuit.lean, lines 51–56) · file SHA-256 af97cc0eec7d8464…

Statement as elaborated and printed by Lean 4.26.0

NimAudit.AC0.Circ → ℕ
Exact source text, lines 51–56
51def size : Circ → Nat52  | input _ => 153  | const _ => 154  | not c => size c + 155  | and cs => (cs.attach.map (fun ⟨c, _⟩ => size c)).sum + 156  | or cs => (cs.attach.map (fun ⟨c, _⟩ => size c)).sum + 1

Project declarations in the statement: AC0.Circ

Project declarations used by the proof or definition body

AC0.Circ, AC0.Circ.and, AC0.Circ.casesOn, AC0.Circ.const, AC0.Circ.input, AC0.Circ.not, AC0.Circ.or, AC0.Circ.rec, AC0.Circ.rec_1

def AC0.evalNet

Module Circuit (lean/phase3/Circuit.lean, lines 751–754) · file SHA-256 af97cc0eec7d8464…

A network: layers applied in order.

Statement as elaborated and printed by Lean 4.26.0

List NimAudit.AC0.Layer → (ℕ → Bool) → ℕ → Bool
Exact source text, lines 751–754
751/-- A network: layers applied in order. -/752def evalNet : List Layer → (Nat → Bool) → (Nat → Bool)753  | [], z => z754  | l :: ls, z => evalNet ls (evalLayer l z)

Project declarations in the statement: AC0.Layer

Project declarations used by the proof or definition body

AC0.Layer, AC0.evalLayer

def Recurrent.xorNet

Module NimRecurrent (lean/phase3/NimRecurrent.lean, lines 500–503) · file SHA-256 1f2994aefc75e7f5…

Fixed-scale threshold realisation of one XOR bit update (W = 2): a two-layer network of literal-threshold gates computes a XOR b.

Statement as elaborated and printed by Lean 4.26.0

List NimAudit.AC0.Layer
Exact source text, lines 500–503
500/-- Fixed-scale threshold realisation of one XOR bit update (W = 2): a two-layer501    network of literal-threshold gates computes a XOR b. -/502def xorNet : List Layer :=503  [[⟨[1, 1], [false, true], 2⟩, ⟨[1, 1], [true, false], 2⟩], [⟨[1, 1], [false, false], 1⟩]]

Project declarations in the statement: AC0.Layer

Project declarations used by the proof or definition body

AC0.Gate, AC0.Gate.mk, AC0.Layer

Full modules

ModuleFileLinesImports
Circuitlean/phase3/Circuit.lean1151NimProbability
NimCorelean/NimCore.lean139Std
NimRecurrentlean/phase3/NimRecurrent.lean555NimAttain, Circuit

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).