Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
75 commits
Select commit Hold shift + click to select a range
3dbe8e1
feat(circuits): prove textbook Barrington bound
SamuelSchlesinger Jul 22, 2026
08920e4
feat(circuits): unfold circuit outputs to formulas
SamuelSchlesinger Jul 22, 2026
efd1465
feat(circuits): define depth classes and bridge NC1
SamuelSchlesinger Jul 22, 2026
9cf4c10
feat(circuits): add executable Barrington compiler
SamuelSchlesinger Jul 22, 2026
f111718
feat(circuits): encode width-five branching programs
SamuelSchlesinger Jul 22, 2026
8cf928e
feat(circuits): specify Barrington code generation
SamuelSchlesinger Jul 22, 2026
ec5bd6c
feat(classes): define uniform Barrington boundary
SamuelSchlesinger Jul 22, 2026
43fdd7b
feat(classes): bound uniform Barrington code size
SamuelSchlesinger Jul 22, 2026
ac14d31
feat(tm): suppress append-only output in finite control
SamuelSchlesinger Jul 22, 2026
406a87f
feat(tm): add binary output-position probe
SamuelSchlesinger Jul 22, 2026
377562e
feat(tm): prove marker-safe output probe runs
SamuelSchlesinger Jul 22, 2026
f3d35dc
feat(tm): bound output probe replay space
SamuelSchlesinger Jul 22, 2026
33973d3
feat(circuits): add streaming Barrington traversal
SamuelSchlesinger Jul 22, 2026
12ab096
feat(tm): canonicalize output probe capture
SamuelSchlesinger Jul 22, 2026
5f947bd
feat(tm): capture arbitrary transducer output bits
SamuelSchlesinger Jul 22, 2026
6a16919
feat(tm): add restartable output probes
SamuelSchlesinger Jul 22, 2026
9ea5f20
feat(circuits): add fixed-address Barrington slots
SamuelSchlesinger Jul 22, 2026
18e6cc0
feat(tm): bound complete output probe queries
SamuelSchlesinger Jul 22, 2026
991f86e
feat(circuits): query fixed Barrington slots directly
SamuelSchlesinger Jul 22, 2026
2ac0c30
feat(circuits): query Barrington slots from postfix tokens
SamuelSchlesinger Jul 22, 2026
19c34b7
feat(circuits): query and serialize Barrington bits
SamuelSchlesinger Jul 22, 2026
94ceb80
feat(circuits): query Barrington programs through probes
SamuelSchlesinger Jul 22, 2026
27ab637
feat(tm): blank bounded sparse work prefixes
SamuelSchlesinger Jul 22, 2026
2acdf53
feat(tm): reset restartable output probes
SamuelSchlesinger Jul 22, 2026
42c1fd9
feat(tm): clean output probe work frames
SamuelSchlesinger Jul 22, 2026
b664ee7
feat(tm): compose restartable output probes
SamuelSchlesinger Jul 22, 2026
cc6c89a
feat(barrington): add scan-based probe controller foundation
SamuelSchlesinger Jul 22, 2026
2efac6b
feat(barrington): latch probe bits for serialization
SamuelSchlesinger Jul 22, 2026
9210bcb
feat(tm): totalize output position probes
SamuelSchlesinger Jul 22, 2026
831682d
feat(tm): totalize restartable output probes
SamuelSchlesinger Jul 22, 2026
8c79e7d
feat(tm): add dynamically indexed output probes
SamuelSchlesinger Jul 22, 2026
a97b41c
feat(tm): dispatch dynamically indexed probes
SamuelSchlesinger Jul 22, 2026
8feb77f
feat(tm): reset output latches before dispatch
SamuelSchlesinger Jul 22, 2026
cb970d5
refactor(tm): expose bounded BinaryFor segments
SamuelSchlesinger Jul 22, 2026
61cb440
feat(tm): add bounded output probe scans
SamuelSchlesinger Jul 22, 2026
ed6979a
feat(tm): count ones through output probes
SamuelSchlesinger Jul 22, 2026
3dc2a44
feat(tm): certify output probe prefix counts
SamuelSchlesinger Jul 22, 2026
bf6f028
feat(tm): derive segment space from entry bounds
SamuelSchlesinger Jul 22, 2026
65593c3
feat(tm): derive count scans from source space
SamuelSchlesinger Jul 22, 2026
6ded0bd
feat(tm): add output-probe unary decoder
SamuelSchlesinger Jul 22, 2026
638e443
feat(tm): certify active unary probe steps
SamuelSchlesinger Jul 22, 2026
3cca33d
feat(tm): certify unary decoder body branches
SamuelSchlesinger Jul 22, 2026
fa687e5
feat(tm): unify unary decoder step semantics
SamuelSchlesinger Jul 22, 2026
56194d6
feat(tm): certify bounded unary decode segments
SamuelSchlesinger Jul 22, 2026
1de3d40
feat(tm): add fixed tag probe decoder
SamuelSchlesinger Jul 22, 2026
96b0dd4
feat(tm): certify fixed tag probe runs
SamuelSchlesinger Jul 22, 2026
2851149
feat(tm): dispatch decoded formula tags
SamuelSchlesinger Jul 22, 2026
991dca1
feat(tm): share formula token decoder layout
SamuelSchlesinger Jul 22, 2026
fb217bf
feat(tm): normalize formula token dispatch
SamuelSchlesinger Jul 22, 2026
7a56593
feat(tm): compose normalized token decoding
SamuelSchlesinger Jul 22, 2026
1fe3238
feat(tm): wire variable token decoding
SamuelSchlesinger Jul 22, 2026
5144c66
feat(tm): expose bounded loop Hoare contracts
SamuelSchlesinger Jul 22, 2026
4d28997
feat(tm): certify bounded decoder contracts
SamuelSchlesinger Jul 22, 2026
9c97331
feat(tm): certify variable token decoding
SamuelSchlesinger Jul 22, 2026
5a2ec2f
feat(bp): add instruction serializer machine
SamuelSchlesinger Jul 22, 2026
02e7a26
feat(bp): emit decoded leaf instructions
SamuelSchlesinger Jul 22, 2026
231959a
feat(bp): certify decoded leaf dispatch
SamuelSchlesinger Jul 22, 2026
1bb6468
feat(bp): expose recursive query boundary
SamuelSchlesinger Jul 22, 2026
75828b7
feat(bp): add stack-free slot cursor
SamuelSchlesinger Jul 22, 2026
b2939f3
feat(bp): reduce slot descent to two bits
SamuelSchlesinger Jul 22, 2026
624cd7d
feat(bp): dispatch recursive slot bits
SamuelSchlesinger Jul 22, 2026
5de220f
feat(bp): capture and position slot bits
SamuelSchlesinger Jul 22, 2026
3e5090b
feat(bp): certify slot address positioning
SamuelSchlesinger Jul 22, 2026
2cad194
feat(bp): compose initial slot dispatch
SamuelSchlesinger Jul 22, 2026
42716be
feat(bp): certify recursive slot descent
SamuelSchlesinger Jul 23, 2026
d229ce5
feat(formula): certify forward child split
SamuelSchlesinger Jul 23, 2026
d3e0d62
feat(tm): expose binary equality Hoare contracts
SamuelSchlesinger Jul 23, 2026
58ccac6
feat(tm): normalize binary equality cursors
SamuelSchlesinger Jul 23, 2026
e30d424
feat(bp): certify forward scan core
SamuelSchlesinger Jul 23, 2026
9169745
feat(bp): certify forward token updates
SamuelSchlesinger Jul 23, 2026
347eb51
feat(bp): connect token decoding to forward scan
SamuelSchlesinger Jul 23, 2026
de13b81
feat(bp): certify decoded forward scan steps
SamuelSchlesinger Jul 23, 2026
8868f32
feat(bp): transport forward scan frames
SamuelSchlesinger Jul 23, 2026
987c46f
feat(bp): bound decoded forward scans
SamuelSchlesinger Jul 23, 2026
389e200
feat(bp): expose forward scan prefix invariants
SamuelSchlesinger Jul 24, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
78 changes: 76 additions & 2 deletions Complexitylib/Circuits.lean
Original file line number Diff line number Diff line change
Expand Up @@ -7,15 +7,34 @@ import Complexitylib.Circuits.Basic
import Complexitylib.Circuits.BitString
import Complexitylib.Circuits.DecisionTree
import Complexitylib.Circuits.Formula
import Complexitylib.Circuits.FormulaEncoding
import Complexitylib.Circuits.FormulaEncoding.Navigation
import Complexitylib.Circuits.FormulaEncoding.ForwardNavigation
import Complexitylib.Circuits.FormulaEncoding.BitNavigation
import Complexitylib.Circuits.FormulaEncoding.ProbeNavigation
import Complexitylib.Circuits.CircuitFormula
import Complexitylib.Circuits.Restriction
import Complexitylib.Circuits.BranchingProgram
import Complexitylib.Circuits.Barrington
import Complexitylib.Circuits.BarringtonS5
import Complexitylib.Circuits.BarringtonBridge
import Complexitylib.Circuits.BarringtonRepr
import Complexitylib.Circuits.BarringtonLength
import Complexitylib.Circuits.BarringtonCompiler
import Complexitylib.Circuits.BarringtonStreaming
import Complexitylib.Circuits.BarringtonSlots
import Complexitylib.Circuits.BarringtonSlotQuery
import Complexitylib.Circuits.BarringtonTokenQuery
import Complexitylib.Circuits.BarringtonBitQuery
import Complexitylib.Circuits.BarringtonBitSerializer
import Complexitylib.Circuits.BarringtonProbeQuery
import Complexitylib.Circuits.BarringtonProbeSerializer
import Complexitylib.Circuits.BranchingProgramEncoding
import Complexitylib.Circuits.BranchingProgramEncoding.Machine
import Complexitylib.Circuits.BarringtonCodeGenerator
import Complexitylib.Circuits.BarringtonFamily
import Complexitylib.Circuits.BarringtonConverse
import Complexitylib.Circuits.CircuitFormula.Family
import Complexitylib.Circuits.MultilinearExtension
import Complexitylib.Circuits.NormalForm
import Complexitylib.Circuits.AndOrNot
Expand All @@ -28,6 +47,7 @@ import Complexitylib.Circuits.EssentialInput
import Complexitylib.Circuits.Shannon
import Complexitylib.Circuits.LowerBound
import Complexitylib.Circuits.Schnorr
import Complexitylib.Circuits.DepthClasses
import Complexitylib.Circuits.AC0
import Complexitylib.Circuits.Nondeterminism
import Complexitylib.Circuits.Hardwiring
Expand Down Expand Up @@ -84,7 +104,29 @@ convention.

* **Barrington's theorem** (`barrington_equivalence`):
Logarithmic-depth Boolean formula families are exactly polynomial-length
width-`5` permutation branching-program families.
width-`5` permutation branching-program families. The finite forward theorem
`barrington_representation_depth_four` gives the textbook length bound
`4 ^ depth`, and `barrington_quadratic_of_log_depth` specializes it to `n²`
at depth at most `log₂ n`.
`barringtonCompile_representation` supplies the same finite theorem through
an explicit executable compiler rather than an existential choice.
`BPCode.Program.decode?_encode` verifies the canonical serialized output
format needed by the remaining log-space uniformity proof.
`barringtonCompileCode_spec` then connects canonical formula bits to canonical
program bits, exact semantics, and a serialized output-size bound.
`barringtonCompileStream_instruction?` gives the corresponding exact
random-access instruction view without constructing the complete program,
while `barringtonCompileSlot?_eq_instruction?` follows one branch of the
fixed `4^D` address schedule and returns exactly its selected instruction,
while `barringtonCompileTokensSlot?_eq_instruction?` carries that query over
canonical postfix tokens using stack-free child-span recovery, and
`barringtonCompileBitsSlot?_eq_instruction?` performs the same query directly
over canonical encoded formula bits. `barringtonCompileProbeSlot?_eq_instruction?`
further replaces the complete bit list by a position-indexed source oracle,
with explicit finite decoding fuel. `barringtonCompileBitsCode_eq` then proves
the fixed-address two-pass serializer emits the exact canonical code.
`BoolFunFamily.onTotalAssignments_mem_Width5BP` applies the theorem to the
total-assignment view of an actual typed `NC1` circuit family.

## Module structure

Expand All @@ -94,10 +136,40 @@ Public modules (definitions a reviewer should read):
`CompleteBasis`, `sizeComplexity`, `wireDepth`, `depth`
* `Complexitylib.Circuits.BitString` — canonical bridges between `BitString n`
and `List Bool`
* `Complexitylib.Circuits.CircuitFormula` — exact selected-output unfolding from
fan-in-two circuit DAGs to Boolean formulas, with a factor-two depth bound
* `Complexitylib.Circuits.FormulaEncoding` — canonical iterative postfix formula
codec with exact round trips and code length
* `Complexitylib.Circuits.FormulaEncoding.ProbeNavigation` — exact token,
subtree, and child-span navigation through a position-indexed bit oracle
* `Complexitylib.Circuits.CircuitFormula.Family` — family-level unfolding and
the typed-`NC1` bridge to width-`5` branching programs
* `Complexitylib.Circuits.Family` — circuit families, list semantics, pointwise
size/depth bounds, and the polynomial-size characterization
* `Complexitylib.Circuits.BarringtonConverse` — balanced branching-program
evaluation and the nonuniform Barrington equivalence
* `Complexitylib.Circuits.BarringtonCompiler` — executable finite `S₅` search
and formula-to-program compilation with the `4 ^ depth` bound
* `Complexitylib.Circuits.BarringtonStreaming` — random-access compilation by
instruction index without materializing the complete recursive program
* `Complexitylib.Circuits.BarringtonSlots` — exact placement of compiled
instructions in a depth-bounded fixed-address schedule
* `Complexitylib.Circuits.BarringtonSlotQuery` — structural first/last occupied
addresses and exact direct lookup in that fixed schedule
* `Complexitylib.Circuits.BarringtonTokenQuery` — the same exact fixed-slot
query over canonical postfix token streams, without reconstructing a formula
* `Complexitylib.Circuits.BarringtonBitQuery` — the fixed-slot query directly
over canonical encoded formula bits, with bit-level child-span recovery
* `Complexitylib.Circuits.BarringtonBitSerializer` — exact two-pass canonical
serialization by scanning the fixed encoded-bit address schedule
* `Complexitylib.Circuits.BarringtonProbeQuery` — exact fixed-address queries
through restartable position-indexed formula-code probes
* `Complexitylib.Circuits.BranchingProgramEncoding` — canonical seven-bit
permutation ranks, instruction/program codecs, and exact size bounds
* `Complexitylib.Circuits.BranchingProgramEncoding.Machine` — framed,
one-way machine emission of canonical instruction codes from binary registers
* `Complexitylib.Circuits.BarringtonCodeGenerator` — the total bitstring-level
formula-code-to-program-code reference for promised log-depth `FL` generation
* `Complexitylib.Circuits.Encoding` — canonical proof-free encoding, validation,
and iterative evaluation of fan-in-two AND/OR circuits
* `Complexitylib.Circuits.Encoding.Family` — tagged encoding and evaluation at
Expand All @@ -116,7 +188,9 @@ Public modules (definitions a reviewer should read):
(`two_pow_le_complexity_of_xorBool`)
* `Complexitylib.Circuits.XOR` — `Schnorr.xorBool` (N-input parity)
* `Complexitylib.Circuits.EssentialInput` — `IsEssentialInput`, `essentialInputs`
* `Complexitylib.Circuits.AC0` — `AC0`
* `Complexitylib.Circuits.DepthClasses` — `DEPTH`, the nonuniform `NC` and `AC`
hierarchies, and the aliases `NC0`, `NC1`, and `AC0`
* `Complexitylib.Circuits.AC0` — compatibility import for `AC0`
* `Complexitylib.Circuits.Nondeterminism.Defs` — `existsQuantify`, `forallQuantify`
* `Complexitylib.Circuits.Hardwiring` — exact-size prefix hardwiring
* `Complexitylib.Circuits.Unrolling` — bounded machine-configuration layouts,
Expand Down
11 changes: 6 additions & 5 deletions Complexitylib/Circuits/AC0.lean
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,14 @@ Released under Apache 2.0 license as described in the file LICENSE.
Authors: Samuel Schlesinger
-/
import Complexitylib.Circuits.AC0.Defs
import Complexitylib.Circuits.DepthClasses

/-!
# The class AC⁰

Surface module for `Complexity.AC0`: Boolean-function families computable by
constant-depth, polynomial-size circuit families of unbounded fan-in AND/OR
gates with free negation on wires. The definition lives in
`Complexitylib.Circuits.AC0.Defs`; separation results against AC⁰ are a
roadmap item and will surface here.
Compatibility surface for `Complexity.AC0`: Boolean-function families computed
by constant-depth, polynomial-size circuit families of unbounded fan-in AND/OR
gates with free negation on wires. The definition and basic API now live in
`Complexitylib.Circuits.DepthClasses`; separation results against AC⁰ remain
a roadmap item.
-/
35 changes: 6 additions & 29 deletions Complexitylib/Circuits/AC0/Defs.lean
Original file line number Diff line number Diff line change
Expand Up @@ -3,35 +3,12 @@ Copyright (c) 2025 Samuel Schlesinger. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
Authors: Samuel Schlesinger
-/
import Complexitylib.Circuits.AndOrNot.Defs
import Complexitylib.Circuits.DepthClasses.Defs

/-! # AC0 — Core Definitions
/-!
# AC0 -- compatibility import

This module defines the AC0 circuit complexity class.

## Main definitions

* `AC0` — the class of families in AC0 (constant depth, polynomial size,
unbounded fan-in AND/OR)
`Complexity.AC0` now lives with the complete `DEPTH`/`NC`/`AC` hierarchy in
`Complexitylib.Circuits.DepthClasses.Defs`. This module preserves the original
import path.
-/

namespace Complexity

/-- A Boolean function family is in **AC0** if there exist constants `d`
(depth bound) and `c` (size exponent) such that for every input length
`N ≥ 1`, some unbounded-fan-in AND/OR circuit of depth at most `d` and
size at most `N ^ c` computes `f N`.

This captures the standard definition of AC0:
- **Constant depth**: the circuit depth does not grow with `N`.
- **Polynomial size**: the number of gates is bounded by a polynomial in `N`.
- **Unbounded fan-in**: AND and OR gates may have arbitrarily many inputs.
- **Free negation**: each gate input carries a negation flag (standard in
circuit complexity). -/
def AC0 : Set BoolFunFamily := fun f =>
∃ (d c : Nat), ∀ (N : Nat) [NeZero N],
∃ (G : Nat) (circuit : Circuit Basis.unboundedAndOr N 1 G),
circuit.depth ≤ d ∧ circuit.size ≤ N ^ c ∧
(fun x => (circuit.eval x) 0) = f N

end Complexity
114 changes: 110 additions & 4 deletions Complexitylib/Circuits/Barrington.lean
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ Authors: Samuel Schlesinger
-/
import Complexitylib.Circuits.BranchingProgram
import Mathlib.Algebra.Group.Commutator
import Mathlib.Data.List.ModifyLast

/-!
# Toward Barrington's theorem: the group-theoretic core
Expand All @@ -20,9 +21,12 @@ Boolean function `f` through the permutation `σ`, meaning it evaluates to `σ`
exactly when `f` holds and to `1` (the identity) otherwise. The closure lemmas
proved here are the moves in Barrington's inductive construction:

- **conjugation** changes the representing permutation (`Computes_conj`);
- **negation** flips the function while inverting the permutation
(`Computes_not`);
- **conjugation** changes the representing permutation, either by wrapping the
program (`Computes_conj`) or pointwise with no length overhead
(`Computes_conjugate`);
- **negation** flips the function while inverting the permutation, either by
appending a constant (`Computes_not`) or by folding that constant into the
final instruction (`Computes_not_compact`);
- the **commutator trick** (`Computes_and`) represents `f ∧ g` through the
commutator `⁅σ, τ⁆` — choosing `σ, τ` to be `5`-cycles in `S₅` whose
commutator is again a `5`-cycle is exactly what makes the `AND` gate work.
Expand All @@ -32,7 +36,12 @@ proved here are the moves in Barrington's inductive construction:
- `BPInstr.inverse`, `BP.inverse`, `BP.eval_inverse` — inverting a program
inverts the permutation it evaluates to.
- `BPInstr.const`, `BPInstr.eval_const` — constant instructions.
- `BP.Computes`, `BP.Computes_conj`, `BP.Computes_not`, `BP.Computes_and`.
- `BPInstr.conjugate`, `BP.conjugate`, `BP.eval_conjugate` — length-preserving
pointwise conjugation.
- `BPInstr.postMul`, `BP.postMul`, `BP.eval_postMul` — fold a final constant
into the last instruction, adding an instruction only to the empty program.
- `BP.Computes`, `BP.Computes_conj`, `BP.Computes_not`,
`BP.Computes_not_compact`, `BP.Computes_and`.
-/

open scoped commutatorElement
Expand Down Expand Up @@ -60,6 +69,83 @@ def BPInstr.const {w : ℕ} (c : Equiv.Perm (Fin w)) : BPInstr w :=
simp only [BPInstr.eval, BPInstr.const]
cases α 0 <;> rfl

/-- Conjugate both branches of an instruction by the same permutation. -/
def BPInstr.conjugate {w : ℕ} (τ : Equiv.Perm (Fin w))
(ins : BPInstr w) : BPInstr w :=
{ ins with
perm0 := τ * ins.perm0 * τ⁻¹
perm1 := τ * ins.perm1 * τ⁻¹ }

/-- Pointwise instruction conjugation realizes group conjugation. -/
@[simp] theorem BPInstr.eval_conjugate {w : ℕ} (α : ℕ → Bool)
(τ : Equiv.Perm (Fin w)) (ins : BPInstr w) :
BPInstr.eval α (BPInstr.conjugate τ ins) =
τ * BPInstr.eval α ins * τ⁻¹ := by
simp only [BPInstr.eval, BPInstr.conjugate]
cases α ins.var <;> rfl

/-- Right-multiply both branches of an instruction by a fixed permutation. -/
def BPInstr.postMul {w : ℕ} (ins : BPInstr w)
(c : Equiv.Perm (Fin w)) : BPInstr w :=
{ ins with perm0 := ins.perm0 * c, perm1 := ins.perm1 * c }

/-- Right-multiplication commutes with selecting an instruction branch. -/
@[simp] theorem BPInstr.eval_postMul {w : ℕ} (α : ℕ → Bool)
(ins : BPInstr w) (c : Equiv.Perm (Fin w)) :
BPInstr.eval α (BPInstr.postMul ins c) = BPInstr.eval α ins * c := by
simp only [BPInstr.eval, BPInstr.postMul]
cases α ins.var <;> rfl

/-- Conjugate every instruction of a branching program. Unlike wrapping with
constant instructions, this operation preserves length exactly. -/
def BP.conjugate {w : ℕ} (τ : Equiv.Perm (Fin w)) (p : BP w) : BP w :=
p.map (BPInstr.conjugate τ)

/-- Pointwise conjugation conjugates the value of the whole program. -/
theorem BP.eval_conjugate {w : ℕ} (α : ℕ → Bool)
(τ : Equiv.Perm (Fin w)) (p : BP w) :
BP.eval α (BP.conjugate τ p) = τ * BP.eval α p * τ⁻¹ := by
induction p with
| nil => simp [BP.conjugate, BP.eval]
| cons ins p ih =>
rw [show BP.conjugate τ (ins :: p) =
BPInstr.conjugate τ ins :: BP.conjugate τ p from rfl]
rw [BP.eval_cons, BPInstr.eval_conjugate, ih, BP.eval_cons]
simp only [mul_assoc, inv_mul_cancel_left]

/-- Pointwise conjugation preserves program length exactly. -/
@[simp] theorem BP.length_conjugate {w : ℕ}
(τ : Equiv.Perm (Fin w)) (p : BP w) :
(BP.conjugate τ p).length = p.length := by
simp [BP.conjugate]

/-- Fold a final constant multiplication into the last instruction. The empty
program has no last instruction, so it becomes a singleton constant program. -/
def BP.postMul {w : ℕ} (p : BP w) (c : Equiv.Perm (Fin w)) : BP w :=
if p = [] then [BPInstr.const c]
else p.modifyLast fun ins => BPInstr.postMul ins c

/-- Folding a final constant into the last instruction right-multiplies the
program value. -/
theorem BP.eval_postMul {w : ℕ} (α : ℕ → Bool) (p : BP w)
(c : Equiv.Perm (Fin w)) :
BP.eval α (BP.postMul p c) = BP.eval α p * c := by
induction p using List.reverseRecOn with
| nil => simp [BP.postMul, BP.eval_singleton]
| append_singleton p ins ih =>
simp [BP.postMul, List.modifyLast_concat, BP.eval_append,
BP.eval_singleton, mul_assoc]

/-- Folding a final constant uses the original length, except that an empty
program needs one instruction. -/
theorem BP.length_postMul {w : ℕ} (p : BP w)
(c : Equiv.Perm (Fin w)) :
(BP.postMul p c).length = max 1 p.length := by
induction p using List.reverseRecOn with
| nil => simp [BP.postMul]
| append_singleton p ins ih =>
simp [BP.postMul, List.modifyLast_concat]

/-- Invert a branching program: reverse the instruction list and invert each
instruction. -/
def BP.inverse {w : ℕ} (p : BP w) : BP w := (p.map BPInstr.inverse).reverse
Expand Down Expand Up @@ -91,6 +177,16 @@ theorem BP.Computes_conj {w : ℕ} {σ : Equiv.Perm (Fin w)} {p : BP w}
simp only [BP.eval_append, BP.eval_singleton, BPInstr.eval_const, h α]
rcases Bool.eq_false_or_eq_true (f α) with hf | hf <;> simp [hf]

/-- **Length-preserving conjugation.** Conjugating every instruction changes
the representing permutation without adding constant instructions. -/
theorem BP.Computes_conjugate {w : ℕ} {σ : Equiv.Perm (Fin w)} {p : BP w}
{f : (ℕ → Bool) → Bool} (h : BP.Computes σ p f)
(τ : Equiv.Perm (Fin w)) :
BP.Computes (τ * σ * τ⁻¹) (BP.conjugate τ p) f := by
intro α
rw [BP.eval_conjugate, h α]
rcases Bool.eq_false_or_eq_true (f α) with hf | hf <;> simp [hf]

/-- **Negation.** Appending a constant `σ⁻¹` to a program that represents `f`
through `σ` yields a program representing `¬f` through `σ⁻¹`. -/
theorem BP.Computes_not {w : ℕ} {σ : Equiv.Perm (Fin w)} {p : BP w}
Expand All @@ -100,6 +196,16 @@ theorem BP.Computes_not {w : ℕ} {σ : Equiv.Perm (Fin w)} {p : BP w}
simp only [BP.eval_append, BP.eval_singleton, BPInstr.eval_const, h α]
rcases Bool.eq_false_or_eq_true (f α) with hf | hf <;> simp [hf]

/-- **Compact negation.** Multiplying the final selected permutation by `σ⁻¹`
represents `¬f` through `σ⁻¹`. The multiplication is folded into the last
instruction, so the length becomes only `max 1 p.length`. -/
theorem BP.Computes_not_compact {w : ℕ} {σ : Equiv.Perm (Fin w)} {p : BP w}
{f : (ℕ → Bool) → Bool} (h : BP.Computes σ p f) :
BP.Computes σ⁻¹ (BP.postMul p σ⁻¹) (fun α => !f α) := by
intro α
rw [BP.eval_postMul, h α]
rcases Bool.eq_false_or_eq_true (f α) with hf | hf <;> simp [hf]

/-- **The commutator trick** (Barrington's `AND` gate). If `p` represents `f`
through `σ` and `q` represents `g` through `τ`, then the commutator program
`p q p⁻¹ q⁻¹` represents `f ∧ g` through the commutator `⁅σ, τ⁆`.
Expand Down
Loading