Documentation

Complexitylib.Circuits.Internal.Simulation

Internal: Completeness of fan-in-2 AND/OR #

This module proves CompleteBasis Basis.andOr2 using the generic simulation lemma CompleteBasis.of_simulation. The proof compiles any circuit over Basis.unboundedAndOr into one over Basis.andOr2 by decomposing each unbounded fan-in gate into a chain of fan-in-2 gates.

Strategy #

Given a circuit c : Circuit Basis.unboundedAndOr N M G, we construct c' : Circuit Basis.andOr2 N M G' with c'.eval = c.eval.

Each original gate with fan-in k is replaced by a chain of chainLen k fan-in-2 gates:

The new circuit's internal gates consist of chains for all original internal gates followed by chains for all original output gates. The new output gates are trivial passthroughs reading the last wire of each output chain.

AndOrOp extensions #

Identity element for fold: true for AND, false for OR.

Equations
Instances For

    The binary operation corresponding to an AndOrOp.

    Equations
    Instances For
      theorem Complexity.AndOrOp.eval_eq_foldl (op : AndOrOp) (n : ) (v : BitString n) :
      op.eval n v = Fin.foldl n (fun (acc : Bool) (i : Fin n) => op.binOp acc (v i)) op.identity

      op.eval is the left fold of op.binOp over the inputs, starting from op.identity.

      op.identity is a left identity for op.binOp.

      theorem Complexity.AndOrOp.binOp_self (op : AndOrOp) (b : Bool) :
      op.binOp b b = b

      op.binOp is idempotent: op.binOp b b = b.

      theorem Complexity.AndOrOp.binOp_assoc (op : AndOrOp) (a b c : Bool) :
      op.binOp (op.binOp a b) c = op.binOp a (op.binOp b c)

      op.binOp is associative.

      theorem Complexity.AndOrOp.dual_const (op : AndOrOp) (b : Bool) :
      (op.dual.eval 2 fun (i : Fin 2) => (if i = 0 then false else true) ^^ b) = op.identity

      The dual-op trick for constants: OR(b, ¬b) = true, AND(b, ¬b) = false.

      theorem Complexity.AndOrOp.passthrough_eq (op : AndOrOp) (v : Bool) :
      (op.eval 2 fun (x : Fin 2) => v) = v

      A passthrough evaluates to the input value.

      eval on 0 inputs gives the identity.

      theorem Complexity.AndOrOp.eval_one (op : AndOrOp) (v : Fin 1Bool) :
      op.eval 1 v = op.binOp op.identity (v 0)

      eval on 1 input gives identity op input.

      Chain length and prefix sums #

      Number of fan-in-2 gates needed to simulate one gate with k inputs.

      Equations
      Instances For
        @[simp]

        A fan-in-0 gate is simulated by a single (constant) gate.

        @[simp]

        A fan-in-1 gate is simulated by a single (passthrough) gate.

        Every chain contains at least one gate.

        For fan-in k ≥ 2, the chain has exactly k - 1 gates.

        Prefix sum: prefixSum f n = f 0 + f 1 + ⋯ + f (n-1).

        Equations
        Instances For
          @[simp]

          The empty prefix sum is 0.

          theorem Complexity.CompileAndOr.prefixSum_succ (f : ) (n : ) :
          prefixSum f (n + 1) = prefixSum f n + f n

          Unfolding lemma: prefixSum f (n + 1) = prefixSum f n + f n.

          theorem Complexity.CompileAndOr.prefixSum_mono (f : ) {i j : } (h : i j) :

          prefixSum f is monotone in the length argument.

          Segment lookup #

          def Complexity.CompileAndOr.segLookup (n : ) (f : ) (idx : ) (h : idx < prefixSum f n) :

          Given a flat index into a segmented array, find the segment and position.

          Equations
          Instances For
            theorem Complexity.CompileAndOr.segLookup_fst_lt (n : ) (f : ) (idx : ) (h : idx < prefixSum f n) :
            (segLookup n f idx h).1 < n

            The segment index returned by segLookup is a valid segment number (< n).

            theorem Complexity.CompileAndOr.segLookup_snd_lt (n : ) (f : ) (idx : ) (h : idx < prefixSum f n) :
            (segLookup n f idx h).2 < f (segLookup n f idx h).1

            The position returned by segLookup lies within its segment's size.

            theorem Complexity.CompileAndOr.segLookup_sum (n : ) (f : ) (idx : ) (h : idx < prefixSum f n) :
            prefixSum f (segLookup n f idx h).1 + (segLookup n f idx h).2 = idx

            segLookup decomposes the flat index: segment offset plus position recovers idx.

            Wire layout definitions #

            Chain size function for internal gates (0-padded beyond G).

            Equations
            Instances For

              Chain size function for output gates (0-padded beyond M).

              Equations
              Instances For

                Total number of fan-in-2 gates in all chains simulating internal gates.

                Equations
                Instances For

                  Total number of fan-in-2 gates in all chains simulating output gates.

                  Equations
                  Instances For

                    Total internal gates in the compiled circuit.

                    Equations
                    Instances For

                      Offset of the chain for internal gate i.

                      Equations
                      Instances For
                        theorem Complexity.CompileAndOr.iChainF_eq {N M G : } [NeZero N] [NeZero M] (c : Circuit Basis.unboundedAndOr N M G) {i : } (hi : i < G) :

                        Within bounds, iChainF is the chain length of the corresponding internal gate.

                        theorem Complexity.CompileAndOr.oChainF_eq {N M G : } [NeZero N] [NeZero M] (c : Circuit Basis.unboundedAndOr N M G) {j : } (hj : j < M) :

                        Within bounds, oChainF is the chain length of the corresponding output gate.

                        theorem Complexity.CompileAndOr.iOffset_succ {N M G : } [NeZero N] [NeZero M] (c : Circuit Basis.unboundedAndOr N M G) {i : } (hi : i < G) :
                        iOffset c (i + 1) = iOffset c i + chainLen (c.gates i, hi).fanIn

                        The chain for internal gate i + 1 starts right after the chain for gate i.

                        The chain for internal gate i fits inside the internal-chain region.

                        theorem Complexity.CompileAndOr.oOffset_succ {N M G : } [NeZero N] [NeZero M] (c : Circuit Basis.unboundedAndOr N M G) {j : } (hj : j < M) :
                        oOffset c (j + 1) = oOffset c j + chainLen (c.outputs j, hj).fanIn

                        The chain for output gate j + 1 starts right after the chain for output gate j.

                        theorem Complexity.CompileAndOr.oOffset_chain_le_G' {N M G : } [NeZero N] [NeZero M] (c : Circuit Basis.unboundedAndOr N M G) {j : } (hj : j < M) :

                        The chain for output gate j fits inside the compiled circuit's gate count.

                        Wire remapping #

                        def Complexity.CompileAndOr.remapWire {N M G : } [NeZero N] [NeZero M] (c : Circuit Basis.unboundedAndOr N M G) (w : Fin (N + G)) :
                        Fin (N + G' c)

                        Map an old wire index to its new position. Input wires are unchanged; internal gate i maps to the last gate of its chain.

                        Equations
                        • One or more equations did not get rendered due to their size.
                        Instances For
                          theorem Complexity.CompileAndOr.remapWire_input {N M G : } [NeZero N] [NeZero M] (c : Circuit Basis.unboundedAndOr N M G) (w : Fin (N + G)) (hw : w < N) :
                          (remapWire c w) = w

                          remapWire fixes input wires (indices below N).

                          theorem Complexity.CompileAndOr.remapWire_gate {N M G : } [NeZero N] [NeZero M] (c : Circuit Basis.unboundedAndOr N M G) {i : } (hi : i < G) :
                          (remapWire c N + i, ) = N + iOffset c i + chainLen (c.gates i, hi).fanIn - 1

                          remapWire sends internal gate i to the last gate of its chain.

                          theorem Complexity.CompileAndOr.remapWire_lt_of_lt {N M G : } [NeZero N] [NeZero M] (c : Circuit Basis.unboundedAndOr N M G) (w : Fin (N + G)) {i : } (hi : i G) (hw : w < N + i) :
                          (remapWire c w) < N + iOffset c i

                          If w < N + i in the old circuit, remapWire w < N + iOffset i in the new.

                          theorem Complexity.CompileAndOr.remapWire_lt_oOffset {N M G : } [NeZero N] [NeZero M] (c : Circuit Basis.unboundedAndOr N M G) (w : Fin (N + G)) (j : ) :
                          (remapWire c w) < N + oOffset c j

                          remapWire maps to a wire that comes before any output chain.

                          Chain gate construction #

                          def Complexity.CompileAndOr.fin2 {α : Sort u_1} (a b : α) :
                          Fin 2α

                          Helper: construct a function Fin 2 → α from two values.

                          Equations
                          Instances For
                            theorem Complexity.CompileAndOr.fin2_zero {α : Sort u_1} (a b : α) :

                            fin2 a b at index 0 is a.

                            theorem Complexity.CompileAndOr.fin2_one {α : Sort u_1} (a b : α) :

                            fin2 a b at index 1 is b.

                            Operation for the chain gate: dual-op for constants, same op otherwise.

                            Equations
                            Instances For
                              def Complexity.CompileAndOr.mkChainInputs {W : } (hW : 0 < W) (k : ) (ri : Fin kFin W) (base j : ) (hj : j < chainLen k) (hbase : base + chainLen k W) :
                              Fin 2Fin W

                              Input wires for the j-th chain gate.

                              Equations
                              • One or more equations did not get rendered due to their size.
                              Instances For
                                def Complexity.CompileAndOr.mkChainNeg (k : ) (rn : Fin kBool) (j : ) (hj : j < chainLen k) :
                                Fin 2Bool

                                Negation flags for the j-th chain gate.

                                Equations
                                • One or more equations did not get rendered due to their size.
                                Instances For
                                  def Complexity.CompileAndOr.mkChainGate {W : } (hW : 0 < W) (op : AndOrOp) (k : ) (ri : Fin kFin W) (rn : Fin kBool) (base j : ) (hj : j < chainLen k) (hbase : base + chainLen k W) :

                                  Build the j-th fan-in-2 gate in a chain for an original gate. Components are split out so projections reduce without unfolding dite.

                                  Equations
                                  • One or more equations did not get rendered due to their size.
                                  Instances For

                                    Compiled circuit #

                                    def Complexity.CompileAndOr.compileGateInputs {N M G : } [NeZero N] [NeZero M] (c : Circuit Basis.unboundedAndOr N M G) (idx : Fin (G' c)) :
                                    Fin 2Fin (N + G' c)

                                    Input wires for the compiled gate at flat index idx.

                                    Equations
                                    • One or more equations did not get rendered due to their size.
                                    Instances For

                                      Operation for the compiled gate at flat index idx.

                                      Equations
                                      • One or more equations did not get rendered due to their size.
                                      Instances For
                                        def Complexity.CompileAndOr.compileGateNeg {N M G : } [NeZero N] [NeZero M] (c : Circuit Basis.unboundedAndOr N M G) (idx : Fin (G' c)) :
                                        Fin 2Bool

                                        Negation flags for the compiled gate at flat index idx.

                                        Equations
                                        • One or more equations did not get rendered due to their size.
                                        Instances For

                                          Gate function for the compiled circuit. Components are separated so projections reduce without going through dite.

                                          Equations
                                          • One or more equations did not get rendered due to their size.
                                          Instances For

                                            Output gates: passthroughs reading the last wire of each output chain.

                                            Equations
                                            • One or more equations did not get rendered due to their size.
                                            Instances For

                                              The compiled circuit over Basis.andOr2.

                                              Equations
                                              Instances For

                                                Eval equivalence #

                                                theorem Complexity.CompileAndOr.segLookup_of_prefixSum (n : ) (f : ) (i j : ) (hi : i < n) (hj : j < f i) (h : prefixSum f i + j < prefixSum f n) :
                                                segLookup n f (prefixSum f i + j) h = (i, j)

                                                segLookup inverts prefixSum: if idx = prefixSum f i + j and j < f i, then segLookup returns (i, j).

                                                theorem Complexity.CompileAndOr.wireValue_remapWire {N M G : } [NeZero N] [NeZero M] (c : Circuit Basis.unboundedAndOr N M G) (input : BitString N) (w : Fin (N + G)) :
                                                (compileFn c).wireValue input (remapWire c w) = c.wireValue input w

                                                Key lemma: remapWire values in the compiled circuit match the original.

                                                The compiled fan-in-2 circuit computes the same function as the original circuit.

                                                The gate-chain simulation has linear overhead in total fan-in and gate count. The additional M term in the final circuit size comes from its passthrough output gates.

                                                Fan-in-2 AND/OR is functionally complete.