Documentation

Complexitylib.Circuits.Restriction

Restrictions #

A restriction is a partial assignment that fixes some variables to constants and leaves the rest free — the basic operation behind random-restriction and switching-lemma arguments (roadmap track L4). This module defines restrictions, their composition, and proves that evaluating a restricted Boolean formula agrees with evaluating the original under the restriction applied to the assignment (evaluation commutes with restriction).

Main definitions and results #

@[reducible, inline]

A restriction: a partial assignment fixing some variables (some b) and leaving the rest free (none).

Equations
Instances For

    The restriction leaving every variable free.

    Equations
    Instances For

      Apply a restriction on top of a total assignment: fixed variables take the restriction's value, free variables fall back to the assignment.

      Equations
      Instances For

        Compose two restrictions: the first takes precedence, the second fills in the variables the first leaves free.

        Equations
        • ρ₁.comp ρ₂ i = (ρ₁ i).or (ρ₂ i)
        Instances For
          theorem Complexity.Restriction.comp_assoc (ρ₁ ρ₂ ρ₃ : Restriction) :
          (ρ₁.comp ρ₂).comp ρ₃ = ρ₁.comp (ρ₂.comp ρ₃)

          Restriction composition is associative, with the leftmost fixed value taking precedence.

          theorem Complexity.Restriction.applyTo_comp (ρ₁ ρ₂ : Restriction) (α : Bool) :
          (ρ₁.comp ρ₂).applyTo α = ρ₁.applyTo (ρ₂.applyTo α)

          Applying a composite restriction is the same as applying the two restrictions in sequence.

          Finite-arity restrictions #

          @[reducible, inline]

          A restriction on exactly N variables.

          Unlike the ambient Restriction = NatOption Bool, this is a finite type and can therefore be used directly as a finite probability space.

          Equations
          Instances For

            The finite restriction leaving every coordinate free.

            Equations
            Instances For
              def Complexity.Restriction.On.single {N : } (index : Fin N) (value : Bool) :
              On N

              Fix exactly one coordinate and leave every other coordinate free.

              Equations
              Instances For
                def Complexity.Restriction.On.comp {N : } (ρ₁ ρ₂ : On N) :
                On N

                Left-biased composition of finite restrictions.

                Equations
                • ρ₁.comp ρ₂ index = (ρ₁ index).or (ρ₂ index)
                Instances For

                  Apply a finite-arity restriction to a matching bit string.

                  Equations
                  Instances For

                    The finite set of coordinates left free by a finite-arity restriction.

                    Equations
                    Instances For

                      Extend a finite-arity restriction by leaving every index outside its declared arity free.

                      Equations
                      Instances For
                        @[simp]
                        theorem Complexity.Restriction.On.toRestriction_apply {N : } (ρ : On N) (i : Fin N) :
                        ρ.toRestriction i = ρ i
                        @[simp]
                        theorem Complexity.Restriction.On.empty_apply {N : } (index : Fin N) :
                        empty index = none
                        @[simp]
                        theorem Complexity.Restriction.On.single_apply_self {N : } (index : Fin N) (value : Bool) :
                        single index value index = some value
                        theorem Complexity.Restriction.On.single_apply_of_ne {N : } {index other : Fin N} (h : other index) (value : Bool) :
                        single index value other = none
                        @[simp]
                        theorem Complexity.Restriction.On.mem_freeVariables {N : } (ρ : On N) (index : Fin N) :
                        index ρ.freeVariables ρ index = none
                        theorem Complexity.Restriction.On.applyTo_single {N : } (index : Fin N) (value : Bool) (x : BitString N) :
                        (single index value).applyTo x = Function.update x index value

                        Applying a singleton restriction is function update at its fixed index.

                        @[simp]
                        theorem Complexity.Restriction.On.empty_comp {N : } (ρ : On N) :
                        empty.comp ρ = ρ
                        @[simp]
                        theorem Complexity.Restriction.On.comp_empty {N : } (ρ : On N) :
                        ρ.comp empty = ρ
                        theorem Complexity.Restriction.On.comp_assoc {N : } (ρ₁ ρ₂ ρ₃ : On N) :
                        (ρ₁.comp ρ₂).comp ρ₃ = ρ₁.comp (ρ₂.comp ρ₃)
                        theorem Complexity.Restriction.On.comp_comm_of_disjoint {N : } (first second : On N) (hdisjoint : ∀ (index : Fin N), first index = none second index = none) :
                        first.comp second = second.comp first

                        Disjoint finite restrictions commute despite composition being left-biased in general.

                        theorem Complexity.Restriction.On.applyTo_comp {N : } (ρ₁ ρ₂ : On N) (x : BitString N) :
                        (ρ₁.comp ρ₂).applyTo x = ρ₁.applyTo (ρ₂.applyTo x)

                        Finite restriction application respects left-biased composition.

                        @[simp]

                        The empty restriction is the identity on formulas.

                        theorem Complexity.BoolFormula.eval_restrict (ρ : Restriction) (α : Bool) (φ : BoolFormula) :
                        eval α (restrict ρ φ) = eval (ρ.applyTo α) φ

                        Evaluation commutes with restriction. Evaluating a restricted formula at α equals evaluating the original formula at the restriction applied to α.

                        theorem Complexity.BoolFormula.restrict_comp (ρ₁ ρ₂ : Restriction) (φ : BoolFormula) :
                        restrict ρ₂ (restrict ρ₁ φ) = restrict (ρ₁.comp ρ₂) φ

                        Applying ρ₁ and then ρ₂ to a formula is syntactically the same as applying their left-biased composition.

                        Restriction preserves the tree size: fixing a variable replaces a leaf by a constant leaf, and connectives are untouched. So (restrict ρ φ).size = φ.size — restriction never grows a formula (a fact width/size arguments rely on).

                        Restriction also preserves the leaf count: (restrict ρ φ).leaves = φ.leaves.

                        Restriction preserves the formula depth exactly: it only relabels leaves, leaving the connective tree — and hence every root-to-leaf path length — untouched. So (restrict ρ φ).depth = φ.depth.

                        Restriction only ever removes variables: vars (restrict ρ φ) ⊆ vars φ. Fixing a variable turns its leaf into a constant (dropping it); free variables are untouched. This is the variable-tracking fact switching-lemma arguments use to bound the surviving support after a random restriction.

                        Restriction removes exactly the fixed variables from a formula's support.