A research program to empirically prove the exact circuit complexity of
concrete Boolean functions
See paper/main.pdf for a detailed writeup.
A circuit is a DAG of fan-in 2 AND gates, where each wire (gate input or circuit output) carries an optional negation bit that flips the signal at zero cost. NOT is not a gate — it is simply an annotation on a wire. Circuit size is the number of AND gates.
This is equivalent to counting
Constants cost one gate. There are no free constant wires. The cheapest
constant is
For each input size
Size<n>/Defs<m>.lean— Generated by a trusted Python program. Boolean functions encoded as(Fin n → Bool) → Bool.Size<n>/Proofs<m>.lean— Written by AI. Upper bounds (witness circuits) and lower bounds (ruling out smaller circuits). The only files AI touches.Size<n>/Statements<m>.lean— Generated by the same trusted program. Imports Defs and Proofs, states the complexity theorems.
We trust only the generator (which we review) and Lean's type checker. The AI is untrusted — incorrect proofs are rejected at type-checking time.
All proofs must be explicit. No native_decide or other opaque decision
procedures.
Three operations on circuits preserve size and are therefore free:
-
Input permutation (
$S_n$ ): relabel input wires.Circuits.CircuitComplexity_perm -
Input negation (
$\mathbb{Z}_2^n$ ): flip negation bits on input wires.Circuits.CircuitComplexity_negInput -
Output negation (
$\mathbb{Z}_2$ ): flip the output negation bit.Circuits.CircuitComplexity_neg
These generate the NPN equivalence group
of order
| Functions | Representatives | Reduction | ||
|---|---|---|---|---|
| 1 | ||||
| 2 | ||||
| 3 | ||||
| 4 | ||||
| 5 |
Function f_idx has truth table encoded by idx: bit idx gives
$f(\text{input}j)$, where $\text{input}j$ interprets $(x_0, \ldots, x{n-1})$
in little-endian binary as $x_0 \cdot 2^0 + x_1 \cdot 2^1 + \cdots + x{n-1} \cdot 2^{n-1}$.
For example, with 0110) maps inputs
Each Size<n>/Proofs<m>.lean file must export, for every representative
function index idx in its batch:
-
f_{idx}_size : Nat— the circuit complexity$k$ -
f_{idx}_upper : HasCircuitOfSize f_{idx} k— a witness circuit -
f_{idx}_lower : ∀ j, j < k → ¬HasCircuitOfSize f_{idx} j— optimality
The Statements file combines these into a CircuitComplexity theorem.
The trusted generator lives at gen/generate.py:
python3 gen/generate.py 1 2 3 # generate for n = 1, 2, 3
python3 gen/generate.py --batch-size 8 3 # custom batch size
The default batch size is 16 functions per file.
Lean 4 (v4.28.0) with no external dependencies — no Mathlib or other libraries. This keeps the trusted base minimal.
The patterns/ directory documents proof techniques and observations as they
emerge:
patterns/upper-bounds.md— witness circuit constructionpatterns/lower-bounds.md— lower bound proof structurepatterns/observations.md— results tables and structural observations
The initial target is
The goal is to gain knowledge on proving circuit lower bounds for concrete circuits, in the hope that the techniques and insights transfer to general purpose circuit lower bounds.