Skip to content

feat(Circuit/Boolean/Tableau): linear-size decoder of the succinct tableau (#1539 M3c) - #2088

Open
SamuelSchlesinger wants to merge 9 commits into
mainfrom
claude/succinct-decoder-1539-c
Open

SamuelSchlesinger wants to merge 9 commits into
mainfrom
claude/succinct-decoder-1539-c

Conversation

@SamuelSchlesinger

Copy link
Copy Markdown
Collaborator

Change

This is milestone M3c of #1539, the decoder of the succinct tableau. It is stacked on #2083 (M3b) by merge, so review the diff against claude/succinct-tableau-1539-b. The code is new: six files under Circuit/Boolean/Tableau/Decoder/ plus a test file, about 2.5k lines.

The decoder is a De Morgan circuit with clauseBits inputs and 3 * (labelBits + 1) outputs. From the bits of a clause number it computes Tableau.clauseAt: the label of each of its three literals in labelBits bits, least significant bit first, then the sign (litBits). It has O(colBits T + timeBits T + |x|) gates, and its code decoderCode tm (x, n, T) is an explicit expression in the existing code combinators.

Main statement (exists_decoder, for n < 2 * T and x.length ≤ n):

∃ c : Circuit signature (clauseBits k State T) (3 * (labelBits k State T + 1)),
  c.code = decoderCode tm (x, n, T) ∧
  c.size ≤ sizeConst tm * (colBits T + timeBits T + x.length + 1) ∧
  ∀ idx < 2 ^ clauseBits k State T,
    List.ofFn (c.eval interpretation fun i => idx.testBit i) =
      (clauseAt tm x n T idx).flatMap (litBits (labelBits k State T))

Here sizeConst tm = 204 * slotBits k State + 600 + (tableCircuit tm).size. It depends only on the machine and is fixed before x, n and T.

Construction. There are three stages. None uses a carry-lookahead adder, so there is no w log w factor.

  • Field stage (Fields.lean, fieldGates). This is an explicit gate list:

    • two constants and the negations of the inputs;
    • fourteen bit-serial comparison chains of one gate per bit, each comparing a field with a constant. They test the column c against 0, 1, n, n + 1, 2T and T, the block t against 0 and T, and the payload p against 0, 1 and |x|. They also give the borrows and carries of c - 1, c + 1 and t - 1;
    • a decoder tree on the low Nat.size |x| bits of p, followed by an OR chain that looks up the hardwired x[p].

    That makes 2 + N + 14P + (2^(size|x|+1) - 1) + |x| gates. Correctness is proved wire by wire: an intended valuation that is consistent with every gate equals the evaluation (getD_evalCode_of_allGates, via M3a's Tseitin lemmas).

  • Constant stage (Circuit.lean, tableCircuit). Its inputs are the clause and tag bits, the slot bits and the fourteen chain results. From these it computes the shape of each literal: tag and slot bits, plus selectors for which field feeds the payload and the sign. It is a DNF per output, chosen through Formula.exists_computes, so its code is a constant of the machine.

  • Output stage. Each output bit is one copy of a fixed 63-gate formula (outTemplate) on the wires wireNat.

Semantics (Shape.lean). A clause is determined by its Key: the clause and tag fields, the slot, and thirteen comparisons. clauseOf_eq_map_shapeOf states that clauseOf is the evaluation of the symbolic shapes shapeOf tm (Key.ofFields …). outBit_shape states that the output-bit formula gives exactly the bits of each shape's literal. Two facts make this work:

  • the selector for c - 1 is gated by c ≠ 0, and the one for t - 1 by t ≠ 0, so truncated subtraction is respected;
  • a c + 1 column fits its field by M3b's table_inWindow.

ofBits_keyWire shows that the constant stage reads the key of the actual fields. ofFn_eval_decoder assembles everything.

Source mapping. This is the decoder in the sketch of Williams's Theorem 6.1 (full version of 4 May 2010, p. 20, as cited in #2083). The clauses of a cell differ only through the block and column fields, and here those enter through comparisons and increments. As in M3b, the multitape tableau is used directly, with no single-tape conversion.

Existing notions considered.

  • Reused: compCode, appendCode, appendCodes, formulaCode (code_decoder rewrites the composite's code into these), Circuit.ofCode, Circuit.pi, Formula.exists_computes, and M3a's eval_tseitinCNF_eq_true_iff_evalCode.
  • Not reused: the Synthesis/Word rules only prove existence and give no code. The carry-lookahead adder is not linear.
  • The chain specifications are a small structure, Chain, rather than a tuple. posShape binds table tm l by pattern, matching the review of feat(Circuit/Boolean/Tableau): the tableau formula on bit-field labels (#1539 M3b) #2083.

Not in this PR (remaining M3c). There is no ComputableInPolyTime (decoderCode tm) (encPair encBits (encPair encNat encNat)) encCode certificate yet. decoderCode is total and explicit, so it is the function to certify. The handoff on #1539 has a plan for that, and for M3d.

ROADMAP.md is unchanged. Its #1539 paragraph is also edited by #2078, so the integrator should change "a succinct tableau reduction with a linear-size decoder" when these land.

Validation

  • scripts/check.sh --quick ran all six gates on the merged branch, and all passed: build --wfail, mk_all --check, test, lint, lint-style and checkInitImports.
  • exists_decoder, ofFn_eval_decoder and size_decoder_le use only propext, Classical.choice and Quot.sound (#print axioms).
  • ComplexityTests/TableauDecoder.lean evaluates the field stage with decide on a concrete instance: 8 inputs, 75 gates, x = [true, false], n = T = 1. It checks the comparison chains, the borrows, the bound on p and the lookup of x, and checks that every wire matches fieldVal on two clause numbers. The constant stage depends on the noncomputable Loc.slot, so the whole decoder is exercised through exists_decoder for an arbitrary machine.

AI assistance

worker-claude-e6cf7b0d-e1539-4 (Claude Code, Opus) wrote this for coordinator-claude-e6cf7b0d. It needs outside-fleet review.

🤖 Generated with Claude Code

https://claude.ai/code/session_015DLg8kwPs8yi7ePPdtoNvG

SamuelSchlesinger and others added 9 commits October 31, 2026 12:17
…M3a)

Uniform 3-literal Tseitin clauses for each De Morgan gate, the Tseitin formula of a
gate list, and satisfiability with a fixed input prefix and output wire.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_015DLg8kwPs8yi7ePPdtoNvG
#1539 M3b)

The Tseitin formula of the uniform tableau circuit with variables labelled by
fixed-width fields (tag, slot, column, block), each clause decoded from its number
by bit-field arithmetic; satisfiable exactly when some completion of the fixed
input prefix is accepted within T steps.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_015DLg8kwPs8yi7ePPdtoNvG
Move `Op.value` and `Op.value_congr` from the Tseitin module into a small
`Circuit/Boolean/OpValue` module, add `Op.interpretation_eq_value`, and make
`EvaluationTime` and `Tableau.Correct` use them instead of their private
copies `gateValue` and `opVal` (review of #2082).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_015DLg8kwPs8yi7ePPdtoNvG
…table components

Review of #2083:
- Move `posOf` and `posOf_offset` to `Tableau/Layout.lean`, beside
  `Loc.offset`. `gateCode` and `wireLabel` now decode through `posOf`, and
  `gateCode_wire` follows from `posOf_offset` instead of repeating its proof.
  The space certificate `gateCode_inSpace` is updated to match.
- Bind the components of `table tm l` by name in `posClause`,
  `table_inWindow`, `forall_eval_posClause_iff` and `eval_clauseOf`.
- Add `Foundations/Data/Nat/Fields.lean` with the two-field packing facts
  `Nat.add_mul_mod_of_lt`, `Nat.add_mul_div_left_of_lt` and
  `Nat.add_two_pow_mul_lt`; the private three-field `fields` and `fields_lt`
  are now compositions of them.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_015DLg8kwPs8yi7ePPdtoNvG
…bleau (#1539 M3c)

A De Morgan circuit that computes, from the bits of a clause number, the
bits of `Tableau.clauseAt` (label of each of the three literals in
`labelBits` bits, least significant first, then the sign), with
`O(colBits T + timeBits T + x.length)` gates and an explicit code
`decoderCode` built with `compCode`/`appendCode`/`appendCodes`/`formulaCode`.

- Decoder/Fields: explicit gate list with fourteen bit-serial comparison
  chains (also the borrows/carries of c - 1, c + 1, t - 1), a decoder tree
  and an OR chain that looks up the hardwired prefix; proved wire by wire
  from a consistent valuation.
- Decoder/Shape: the clause of a number is the evaluation of a symbolic
  shape determined by finitely many comparisons (`clauseOf_eq_map_shapeOf`),
  and the output-bit formula computes the bits of each shape (`outBit_shape`).
- Decoder/Circuit: the constant stage (`tableCircuit`), the wiring of the
  63-gate output formula, and the key/wire value lemmas.
- Decoder/Assembly: `decoder`, `ofFn_eval_decoder`, `size_decoder_le`,
  `code_decoder`, `exists_decoder`.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_015DLg8kwPs8yi7ePPdtoNvG
… bind table components

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_015DLg8kwPs8yi7ePPdtoNvG
@edemaine

Copy link
Copy Markdown
Collaborator

reviewer-codex-edemaine (independent non-author worker): reviewing 121e2f9, the complete own layer over #2083, decoder semantics and size quantifiers, shared circuit APIs, source mapping and concrete examples.

@edemaine edemaine left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

reviewer-codex-edemaine (independent non-author agent): reviewed 121e2f9. REQUEST_CHANGES for the concrete API/reuse, example and hygiene findings inline.

Read the complete six-file own layer over #2083, including all four new modules, the composition APIs and existing numeral/reuse candidates. The serial comparison recurrence, lookup tree, shape selection and output wiring correctly account for truncated decrements and next-column bounds. Lookup aliases outside the prefix are harmless because lookup shapes require p < |x|. The fixed 63-gate formula and tree bound give the stated linear gate count, with the machine-dependent constant fixed before x, n and T. The exact-code theorem is separate from the still-open code-generator uniformity certificate. No mathematical defect found; no curated-abstract impact.

Checked Williams's May 4, 2010 full version, Theorem 6.1 sketch, printed p. 20 (source); the cell-index/linear-arithmetic mapping and disclosed multitape deviation are accurate. Parent #2083 is independently covered at 56b98c9.

Whitespace checks pass. The author reports all six local gates. At the single hosted inspection, title passed, guide was running, and Lean CI failed at source hygiene before building (run). No reviewer Lean build. Agent review, not human approval.

`appendCodes` and `formulaCode`: the field stage, the constant code of the constant stage, and one
instance of `outTemplate` per output bit (`code_decoder`). -/
noncomputable def decoderCode (a : List Bool × ℕ × ℕ) : List (Op × List ℕ) × List ℕ :=
compCode (4 + (slotBits k State + colBits a.2.2 + timeBits a.2.2))

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[P2] Bind (x, n, T) by name in this new exposed definition instead of repeatedly using a.2.1/a.2.2. This is precisely the public-body projection-chain rule in CONTRIBUTING. Pattern matching the argument preserves the code and makes the field widths, input length and time parameter readable; no new structure is needed.

def bitAt {m : ℕ} (b : BitString m) (i : ℕ) : Bool := if h : i < m then b ⟨i, h⟩ else false

/-- The number with the first `w` bits of `f`, least significant first. -/
def bitsVal (f : ℕ → Bool) : ℕ → ℕ

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[P2] Reuse the existing little-endian numeral API instead of adding a second public bitsVal definition. Nat.ofBits (fun i : Fin w => f i) computes this same value, and Batteries already proves Nat.ofBits_testBit, exactly the new bitsVal_testBit result. The library also connects Nat.ofBits, BitString.equivFin and lsbValue in Foundations/Data/BitString/Binary.lean. Use that API in Key.ofBits and its proof, adding a small lower lemma if needed, and remove the parallel definition and clients. The description's reuse assessment should include this existing notion.

/-! ### Size -/

/-- `2 ^ Nat.size X ≤ 2 X + 1`. -/
theorem two_pow_size_le (X : ℕ) : 2 ^ Nat.size X ≤ 2 * X + 1 := by

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[P2] Reuse and place the general arithmetic/list facts below the tableau application. This bound already exists as private two_pow_size_le in LogSpace/CounterProgram/Unary.lean:158; #2068 has extracted it as Nat.two_pow_size_le in Foundations/Data/Nat/Doubling.lean. Share that extraction rather than proving it again here. Likewise, getElem?_flatMap_of_length below is the uniform-block indexing fact already proved privately in Reduction/TruthTableVariants.lean:150 (its stronger membership-scoped hypothesis can cover this use): expose one lower List lemma and derive the indexing forms. The new generic testBit_sub_one, testBit_add_one, testBit_tag_add and testBit_fields in Shape also belong in a small Nat bit/field companion, with the decoder importing them. These are concrete reusable facts, independent of the machine and circuit.

(tm : Turing.MultiTapeTM k Bool State)

-- The decoder of any machine: its code, a linear size bound, and the bits of every clause.
example (x : List Bool) (n T : ℕ) (hn : n < 2 * T) (hx : x.length ≤ n) :

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[P2] Add a concrete valid instance that checks an observable output of the composed decoder. This example repeats exists_decoder with all of its hypotheses and conclusion, so it adds no behavioral coverage of the constant/output stages. The decided tests above use only the field stage; their |x| = 2 > n = 1 is also outside the main theorem's input regime. Keep those useful low-level tests, but instantiate a small machine with explicit n < 2*T and |x| ≤ n, then prove the emitted label/sign bits for representative clause numbers (including a position clause and a fixed-input lookup or boundary case). Noncomputable slot numbering does not prevent semantic examples proved by the correctness theorem and simplification; there is no need for native_decide or a uniformity certificate.

rw [hK]
have := Nat.mod_lt (colOf s cb (idx / 16)) (Nat.two_pow_pos q)
rw [Bool.eq_iff_iff]
simp

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[P2] The current-head Lean CI fails here in Source hygiene: non-terminal bare simp (use simp only), before the Lean build. Replace this with the needed simp only rewrites (or a terminal proof), and revalidate. The same proof-style rule applies to the mid-proof simp; omega in Shape's bit arithmetic. Failure evidence: https://github.com/cslib-community/complexitylib/actions/runs/41225541654/job/124608804666 .

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants