Documentation

Complexitylib.Algebraic.LowerBound.Nechiporuk.Sharing.Internal

Internals of programs with shared gates over the full binary basis #

Proof internals for Complexitylib.Algebraic.LowerBound.Nechiporuk.Sharing:

The variable leaves of a binary formula number at most its binary gates plus one.

@[simp]
theorem Algebraic.Binary.Formula.eval_mapIndex {N M : ℕ} (φ : Fin N → Fin M) (F : Formula N) (x : Fin M → Bool) :
(mapIndex φ F).eval x = F.eval (x ∘ φ)

Evaluating a reindexed formula is evaluating the original on the reindexed assignment.

@[simp]
theorem Algebraic.Binary.Formula.gates_mapIndex {N M : ℕ} (φ : Fin N → Fin M) (F : Formula N) :

Reindexing variables does not change the number of gates.

theorem Algebraic.Binary.Formula.leavesIn_mapIndex {N M : ℕ} (φ : Fin N → Fin M) (Y : Finset (Fin M)) (F : Formula N) :
leavesIn Y (mapIndex φ F) = leavesIn {i : Fin N | φ i ∈ Y} F

The leaves of a reindexed formula in Y are the leaves of the original in the preimage of Y.

theorem Algebraic.Binary.Formula.eval_subst {N M : ℕ} (σ : Fin N → Formula M) (F : Formula N) (x : Fin M → Bool) :
(subst σ F).eval x = F.eval fun (i : Fin N) => (σ i).eval x

Evaluating a substituted formula evaluates the original on the values of the substitutes.

@[simp]
theorem Algebraic.Binary.Formula.occ_mapIndex_castLE {N M : ℕ} (v : ℕ) (h : N ≤ M) (F : Formula N) :
occ v (mapIndex (Fin.castLE h) F) = occ v F

Embedding the variables with Fin.castLE preserves occurrence counts.

theorem Algebraic.Binary.Formula.occ_eq_zero_of_ge {N v : ℕ} (hv : N ≤ v) (F : Formula N) :
occ v F = 0

A variable index at least N never occurs in a formula on N variables.

The input leaves are among all variable leaves.

The input leaves of a binary formula number at most its binary gates plus one.

A formula on N variables has no leaves on variables from m ≥ N on.

@[simp]

Embedding the variables with Fin.castLE preserves shared-leaf counts.

The shared leaves from m on split into the occurrences of m and the shared leaves from m + 1 on.

theorem Algebraic.Binary.Formula.sum_inputLeavesIn_le_inputLeaves {N m n : ℕ} (Y : Fin m → Finset (Fin n)) (disjoint : Pairwise fun (i j : Fin m) => Disjoint (Y i) (Y j)) (F : Formula N) :
∑ i : Fin m, inputLeavesIn (Y i) F ≤ F.inputLeaves n

Over pairwise disjoint blocks of Fin n, inputLeavesIn sums to at most inputLeaves n.

Extend a block Y ⊆ Fin n to Fin N by including all shared variables i ≥ n.

Equations
Instances For

    Extending a block of Fin n to Fin n itself does not change it.

    The leaves in the extended block are the input leaves in Y plus all shared leaves.

    theorem Algebraic.Binary.Formula.leavesIn_eq_inputLeavesIn_add_sum_occ {N n : ℕ} (Y₀ : Finset (Fin n)) (Y : Finset (Fin N)) (hY : ∀ (i : Fin N) (hi : ↑i < n), i ∈ Y ↔ ⟨↑i, hi⟩ ∈ Y₀) (F : Formula N) :
    leavesIn Y F = inputLeavesIn Y₀ F + ∑ i ∈ Y, if n ≤ ↑i then occ (↑i) F else 0

    Decompose F.leavesIn Y into input leaves in Y₀ and occurrences of shared variables in Y when Y agrees with Y₀ below n.

    def Algebraic.Binary.Formula.liftBlock {N d : ℕ} (b : Bool) (W : Finset (Fin (N + d))) :
    Finset (Fin (N + 1 + d))

    Insert membership b at variable N, shifting variables ≥ N up by one.

    Equations
    Instances For
      theorem Algebraic.Binary.Formula.leavesIn_liftBlock_true {N : ℕ} (d : ℕ) (W : Finset (Fin (N + d))) (F : Formula (N + 1 + d)) :

      Including variable N in a lifted block adds exactly the occurrences of N.

      def Algebraic.Binary.Formula.substVarMap {N : ℕ} (φ : Formula N) (d : ℕ) (i : Fin (N + 1 + d)) :
      Formula (N + d)

      The substitution map replacing variable N by φ, keeping variables below N, and shifting variables above N down by one.

      Equations
      • One or more equations did not get rendered due to their size.
      Instances For
        theorem Algebraic.Binary.Formula.gates_subst_substVarMap {N : ℕ} (φ : Formula N) (d : ℕ) (F : Formula (N + 1 + d)) :
        (subst (φ.substVarMap d) F).gates = F.gates + occ N F * φ.gates

        Substituting φ for variable N adds φ.gates once per occurrence of N.

        theorem Algebraic.Binary.Formula.occ_subst_substVarMap {N : ℕ} (φ : Formula N) (d : ℕ) {w : ℕ} (hw : w < N) (F : Formula (N + 1 + d)) :
        occ w (subst (φ.substVarMap d) F) = occ w F + occ N F * occ w φ

        Substituting φ for variable N adds the occurrences of w < N in φ once per occurrence of N.

        theorem Algebraic.Binary.Formula.occ_subst_substVarMap_ge {N : ℕ} (φ : Formula N) (d : ℕ) {w : ℕ} (hw : N ≤ w) (F : Formula (N + 1 + d)) :
        occ w (subst (φ.substVarMap d) F) = occ (w + 1) F

        Substituting for variable N shifts the occurrences of variables above N down by one.

        theorem Algebraic.Binary.Formula.leavesIn_subst_substVarMap {N : ℕ} (φ : Formula N) (d : ℕ) (W : Finset (Fin (N + d))) (F : Formula (N + 1 + d)) :
        leavesIn W (subst (φ.substVarMap d) F) = leavesIn (liftBlock false W) F + occ N F * leavesIn {j : Fin N | Fin.castLE ⋯ j ∈ W} φ

        The leaves of a substituted formula in W are the leaves of the original outside variable N plus the leaves of φ once per occurrence of N.

        theorem Algebraic.Binary.Formula.leavesIn_subst_substVarMap_eq_zero_iff {N : ℕ} (φ : Formula N) (d : ℕ) (W : Finset (Fin (N + d))) (F : Formula (N + 1 + d)) :
        leavesIn W (subst (φ.substVarMap d) F) = 0 ↔ leavesIn (liftBlock (decide (leavesIn {j : Fin N | Fin.castLE ⋯ j ∈ W} φ ≠ 0)) W) F = 0

        A substituted formula has no leaves in W iff the original has none in the block lifted by whether φ has leaves in W.

        Substituting a formula on N variables for variable N shifts the shared leaves down by one.

        theorem Algebraic.Binary.Formula.eval_subst_substVarMap {N : ℕ} (φ : Formula N) (d : ℕ) (F : Formula (N + 1 + d)) (y : Fin (N + d) → Bool) :
        (subst (φ.substVarMap d) F).eval y = F.eval (KW.insertVal y (φ.eval fun (j : Fin N) => y (Fin.castLE ⋯ j)))

        Evaluating a substituted formula evaluates the original with φ's value inserted at N.

        Subfunctions of a program with shared gates #

        @[simp]

        castBlock Y never contains the new last variable.

        @[simp]

        A lifted old variable lies in castBlock Y iff it lies in Y.

        @[simp]

        snocBlock Y always contains the new last variable.

        @[simp]

        A lifted old variable lies in snocBlock Y iff it lies in Y.

        @[simp]

        A lifted old variable lies in stepBlock G Y iff it lies in Y.

        @[simp]

        The new last variable lies in stepBlock G Y iff G has a leaf in Y.

        Adding the new last variable commutes with extending a block by all shared variables.

        The block leaf count on an extended block is the input leaves in Y plus all shared leaves.

        On a primary block, the block leaf count is the input leaves in Y plus all shared leaves.

        The shared leaves from m on split into the occurrences of m and the shared leaves from m + 1 on.

        theorem Algebraic.Nechiporuk.SharedProgram.activeLeavesIn_eq_inputLeavesIn_add_sum_occ {N k : ℕ} (P : SharedProgram N k) {n : ℕ} (_hn : n ≤ N) (Y₀ : Finset (Fin n)) (Y : Finset (Fin N)) :
        (∀ (i : Fin N) (hi : ↑i < n), i ∈ Y ↔ ⟨↑i, hi⟩ ∈ Y₀) → P.activeLeavesIn Y = (inputLeavesIn Y₀ P + ∑ i ∈ Y, if n ≤ ↑i then occ (↑i) P else 0) + P.activeSharedLeaves Y

        The active leaves of P on Y split into input leaves in Y₀, occurrences of the shared variables in Y, and the active shared-variable leaves, when Y agrees with Y₀ below n.

        The active leaves of P on a primary block Y ⊆ Fin n equal P.inputLeavesIn Y plus P.activeSharedLeaves Y.

        def Algebraic.Nechiporuk.SharedProgram.castBlockVal {N : ℕ} {Y : Finset (Fin N)} (y : ↥Y → Bool) (j : ↥(castBlock Y)) :

        Project a coordinate in castBlock Y to Y.

        Equations
        Instances For
          def Algebraic.Nechiporuk.SharedProgram.snocComplVal {N : ℕ} {Y : Finset (Fin N)} (z : ↥Yᶜ → Bool) (b : Bool) (j : ↥(castBlock Y)ᶜ) :

          Extend an outside assignment z : ↥Yᶜ → Bool by b on Fin.last N.

          Equations
          Instances For
            theorem Algebraic.Nechiporuk.SharedProgram.glue_castBlock {N : ℕ} (Y : Finset (Fin N)) (y : ↥Y → Bool) (z : ↥Yᶜ → Bool) (b : Bool) :

            Appending a value outside the block: gluing over Y and appending b equals gluing over castBlock Y with b among the outside coordinates.

            Project a coordinate outside snocBlock Y to Yᶜ.

            Equations
            Instances For
              def Algebraic.Nechiporuk.SharedProgram.snocBlockVal {N : ℕ} {Y : Finset (Fin N)} (y : ↥Y → Bool) (b : Bool) (j : ↥(snocBlock Y)) :

              Extend a block assignment y : ↥Y → Bool by the value b on Fin.last N.

              Equations
              Instances For
                theorem Algebraic.Nechiporuk.SharedProgram.glue_snocBlock {N : ℕ} (Y : Finset (Fin N)) (y : ↥Y → Bool) (z : ↥Yᶜ → Bool) (b : Bool) :

                Appending a value inside the block: gluing over Y and appending b equals gluing over snocBlock Y with b among the block coordinates.

                If the shared formula G has no leaves in Y, then share G P has at most as many subfunctions on Y as P has on castBlock Y: the shared value is constant once the outside coordinates are fixed.

                The subfunctions of share G P on Y number at most the product of the subfunction counts of G on Y and of P on snocBlock Y.

                Substitution of a variable in a SharedProgram #

                Substitute the formula φ for variable N throughout a program on N + 1 + d variables.

                Equations
                Instances For
                  theorem Algebraic.Nechiporuk.SharedProgram.eval_substVar {N : ℕ} (φ : Binary.Formula N) {d k : ℕ} (P : SharedProgram (N + 1 + d) k) (y : Fin (N + d) → Bool) :
                  (substVar φ P).eval y = P.eval (KW.insertVal y (φ.eval fun (j : Fin N) => y (Fin.castLE ⋯ j)))

                  Evaluating substVar φ P evaluates P with φ's value inserted at variable N.

                  theorem Algebraic.Nechiporuk.SharedProgram.gates_substVar {N : ℕ} (φ : Binary.Formula N) {d k : ℕ} (P : SharedProgram (N + 1 + d) k) :
                  (substVar φ P).gates = P.gates + occ N P * φ.gates

                  Substituting φ adds φ.gates once per occurrence of variable N.

                  theorem Algebraic.Nechiporuk.SharedProgram.occ_substVar {N : ℕ} (φ : Binary.Formula N) {w : ℕ} (hw : w < N) {d k : ℕ} (P : SharedProgram (N + 1 + d) k) :
                  occ w (substVar φ P) = occ w P + occ N P * Binary.Formula.occ w φ

                  Substituting φ adds the occurrences of w < N in φ once per occurrence of variable N.

                  theorem Algebraic.Nechiporuk.SharedProgram.occ_substVar_ge {N : ℕ} (φ : Binary.Formula N) {w : ℕ} (hw : N ≤ w) {d k : ℕ} (P : SharedProgram (N + 1 + d) k) :
                  occ w (substVar φ P) = occ (w + 1) P

                  Substituting for variable N shifts the occurrences of variables above N down by one.

                  Substituting for variable N shifts the shared leaves down by one.

                  Substitution preserves active shared gates, measured on the lifted block.

                  Substituting φ for the first shared variable preserves active shared gates once the block is advanced through φ.

                  Substitution preserves active shared-variable leaves, measured on the lifted block.

                  Substituting φ for the first shared variable preserves active shared-variable leaves once the block is advanced through φ.

                  Shared fan-out and translation from binary circuits to SharedProgram #

                  def Algebraic.Nechiporuk.sharedFanOutCount {σ : Signature} {n t : ℕ} (p : Program σ n t) (u : Fin t → ℕ) :

                  The total fan-out of the gates of p whose fan-out is at least two when gate g is read u g more times.

                  Equations
                  Instances For
                    theorem Algebraic.Nechiporuk.sharedFanOut_eq {σ : Signature} {n m : ℕ} (c : Circuit σ n m) :

                    sharedFanOut c is sharedFanOutCount of its program with the output reads as extra uses.

                    theorem Algebraic.Nechiporuk.sharedFanOutCount_gate {σ : Signature} {n t : ℕ} (p : Program σ n t) (line : Line σ n t) (u : Fin (t + 1) → ℕ) :
                    sharedFanOutCount (p.gate line) u = (if 2 ≤ u (Fin.last t) then u (Fin.last t) else 0) + sharedFanOutCount p fun (g : Fin t) => u g.castSucc + KW.argUses line g

                    Peeling the last gate off a program: its shared fan-out is counted separately, and its reads move into the extra uses of the earlier gates.

                    theorem Algebraic.Nechiporuk.gateActive_gate_last {σ : Signature} {n t : ℕ} (Y : Finset (Fin n)) (p : Program σ n t) (line : Line σ n t) :
                    gateActive Y (p.gate line) (Fin.last t) = decide (∃ (a : Fin (σ.Arity line.op)), wireActive Y p (line.wires a) = true)

                    The last gate is active iff one of its argument wires is active.

                    @[simp]
                    theorem Algebraic.Nechiporuk.gateActive_gate_castSucc {σ : Signature} {n t : ℕ} (Y : Finset (Fin n)) (p : Program σ n t) (line : Line σ n t) (g : Fin t) :
                    gateActive Y (p.gate line) g.castSucc = gateActive Y p g

                    Appending a gate does not change whether an earlier gate is active.

                    def Algebraic.Nechiporuk.activeSharedCount {σ : Signature} {n t : ℕ} (Y : Finset (Fin n)) (p : Program σ n t) (u : Fin t → ℕ) :

                    The number of gates of p active on Y whose fan-out is at least two when gate g is read u g more times.

                    Equations
                    Instances For
                      def Algebraic.Nechiporuk.activeSharedFanOutCount {σ : Signature} {n t : ℕ} (Y : Finset (Fin n)) (p : Program σ n t) (u : Fin t → ℕ) :

                      The total fan-out of the gates of p active on Y whose fan-out is at least two when gate g is read u g more times.

                      Equations
                      Instances For
                        theorem Algebraic.Nechiporuk.activeSharedGateCount_eq {σ : Signature} {n m : ℕ} (c : Circuit σ n m) (Y : Finset (Fin n)) :

                        activeSharedGateCount c Y is activeSharedCount of its program with the output reads as extra uses.

                        theorem Algebraic.Nechiporuk.activeSharedFanOut_eq {σ : Signature} {n m : ℕ} (c : Circuit σ n m) (Y : Finset (Fin n)) :

                        activeSharedFanOut c Y is activeSharedFanOutCount of its program with the output reads as extra uses.

                        theorem Algebraic.Nechiporuk.activeSharedCount_gate {σ : Signature} {n t : ℕ} (Y : Finset (Fin n)) (p : Program σ n t) (line : Line σ n t) (u : Fin (t + 1) → ℕ) :
                        activeSharedCount Y (p.gate line) u = (if 2 ≤ u (Fin.last t) ∧ gateActive Y (p.gate line) (Fin.last t) = true then 1 else 0) + activeSharedCount Y p fun (g : Fin t) => u g.castSucc + KW.argUses line g

                        Peeling the last gate off a program for activeSharedCount.

                        theorem Algebraic.Nechiporuk.activeSharedFanOutCount_gate {σ : Signature} {n t : ℕ} (Y : Finset (Fin n)) (p : Program σ n t) (line : Line σ n t) (u : Fin (t + 1) → ℕ) :
                        activeSharedFanOutCount Y (p.gate line) u = (if 2 ≤ u (Fin.last t) ∧ gateActive Y (p.gate line) (Fin.last t) = true then u (Fin.last t) else 0) + activeSharedFanOutCount Y p fun (g : Fin t) => u g.castSucc + KW.argUses line g

                        Peeling the last gate off a program for activeSharedFanOutCount.

                        def Algebraic.Nechiporuk.activeWires {σ : Signature} {n t : ℕ} (Y : Finset (Fin n)) (p : Program σ n t) :
                        Finset (Fin (n + t))

                        The subset of Fin (n + t) consisting of wires of p active on Y.

                        Equations
                        Instances For
                          @[simp]

                          The active wires of the empty program are the block itself.

                          @[simp]
                          theorem Algebraic.Nechiporuk.index_mem_activeWires {σ : Signature} {n t : ℕ} (Y : Finset (Fin n)) (p : Program σ n t) (w : Wire n t) :

                          A wire's index is an active wire iff the wire is active.

                          The formula of one full-binary-basis gate over the earlier wires, numbered by Wire.index.

                          Equations
                          Instances For

                            The formula of the last gate has no leaves among the active wires iff the gate is inactive.

                            Advancing the active wires through the formula of a new gate gives the active wires of the extended program.

                            def Algebraic.Nechiporuk.wireValues {n t : ℕ} (p : Program Binary.signature n t) (x : Fin n → Bool) :
                            Fin (n + t) → Bool

                            The values of the inputs and gates of a binary program, numbered by Wire.index.

                            Equations
                            Instances For
                              theorem Algebraic.Nechiporuk.eval_lineFormula {n t : ℕ} (line : Line Binary.signature n t) (x : Fin n → Bool) (vals : Fin t → Bool) :

                              The formula of a gate evaluates as the gate.

                              The formula of a gate has exactly one binary gate.

                              The formula of a gate reads no variables beyond the existing wires.

                              The formula of a gate reads gate g at most as often as the gate's arguments do.

                              Evaluating a program with an appended gate appends the gate's value.

                              theorem Algebraic.Nechiporuk.wireValues_gate {n t : ℕ} (p : Program Binary.signature n t) (line : Line Binary.signature n t) (x : Fin n → Bool) :
                              wireValues (p.gate line) x = Fin.snoc (wireValues p x) ((lineFormula line).eval (wireValues p x))

                              The wire values of an extended program append the value of the new gate's formula.

                              The wire values of the empty program are the inputs.

                              theorem Algebraic.Nechiporuk.exists_sharedProgram_of_program {n : ℕ} (f : Cslib.BooleanFunction n) {t : ℕ} (p : Program Binary.signature n t) (u : Fin t → ℕ) {j : ℕ} (Q : SharedProgram (n + t) j) :
                              (∀ (x : Fin n → Bool), Q.eval (wireValues p x) = f x) → (∀ (g : Fin t), SharedProgram.occ (n + ↑g) Q ≤ u g) → ∃ (k : ℕ) (P : SharedProgram n k), k ≤ j + KW.sharedCount p u ∧ P.Computes f ∧ P.gates ≤ Q.gates + t ∧ P.sharedLeaves n ≤ Q.sharedLeaves (n + t) + sharedFanOutCount p u ∧ ∀ (Y : Finset (Fin n)), P.activeShared Y ≤ Q.activeShared (activeWires Y p) + activeSharedCount Y p u ∧ P.activeSharedLeaves Y ≤ Q.activeSharedLeaves (activeWires Y p) + activeSharedFanOutCount Y p u

                              Build a SharedProgram from the last gate of a full-binary-basis program down, simultaneously bounding both global and block-active shared gates and shared-variable leaves.

                              theorem Algebraic.Nechiporuk.Internal.gateActive_eq_true_iff {σ : Signature} {n t : ℕ} (Y : Finset (Fin n)) (p : Program σ n t) (g : Fin t) :
                              gateActive Y p g = true ↔ ∃ i ∈ Y, i ∈ p.wireSupport (Wire.gate g)

                              Gate g is active on Y iff its syntactic input support intersects Y.

                              theorem Algebraic.Nechiporuk.Internal.gateBlockSpan_le_card_wireSupport {σ : Signature} {n t B : ℕ} {Y : Fin B → Finset (Fin n)} (hdisj : Pairwise fun (i j : Fin B) => Disjoint (Y i) (Y j)) (p : Program σ n t) (g : Fin t) :

                              Over pairwise disjoint blocks Y, the number of blocks on which gate g is active is at most the cardinality of its syntactic input support.

                              In any single-output circuit over Binary.signature, the total fan-out of all shared gates is at most 2 * c.size + 1.