Documentation

Complexitylib.Algebraic.PartialAssignment

Boolean partial assignments #

A partial assignment records, for each named Boolean variable, either a fixed value or a live variable. Restricted functions retain the original input indexing: values supplied at fixed coordinates are ignored. This representation is convenient for random restrictions and decision trees, while conversion to InputSubstitution connects it to the library's existing semantic interface.

Sequential refinement is left-biased. In rho.refine sigma, assignments already fixed by rho remain fixed, and sigma is consulted only at variables left live by rho.

@[reducible, inline]

A Boolean restriction on n named variables. none means that a variable is live; some value fixes it to value.

Equations
Instances For
    theorem Algebraic.PartialAssignment.ext {n : ℕ} {rho sigma : PartialAssignment n} (equal : ∀ (index : Fin n), rho index = sigma index) :
    rho = sigma

    Two partial assignments are equal when they agree on every variable.

    The empty partial assignment leaves every variable live.

    Equations
    Instances For

      A total assignment fixes every variable.

      Equations
      Instances For
        def Algebraic.PartialAssignment.fix {n : ℕ} (selected : Fin n) (value : Bool) :

        The partial assignment fixing exactly one variable.

        Equations
        Instances For
          @[simp]
          theorem Algebraic.PartialAssignment.empty_apply {n : ℕ} (index : Fin n) :
          empty index = none
          @[simp]
          theorem Algebraic.PartialAssignment.total_apply {n : ℕ} (input : Fin n → Bool) (index : Fin n) :
          total input index = some (input index)
          @[simp]
          theorem Algebraic.PartialAssignment.fix_selected {n : ℕ} (selected : Fin n) (value : Bool) :
          fix selected value selected = some value
          @[simp]
          theorem Algebraic.PartialAssignment.fix_other {n : ℕ} (selected index : Fin n) (value : Bool) (different : index ≠ selected) :
          fix selected value index = none
          def Algebraic.PartialAssignment.apply {n : ℕ} (rho : PartialAssignment n) (input : Fin n → Bool) :
          Fin n → Bool

          Apply a partial assignment to a complete input. Values at fixed variables are overwritten, while values at live variables are retained.

          Equations
          • rho.apply input index = (rho index).getD (input index)
          Instances For
            @[simp]
            theorem Algebraic.PartialAssignment.apply_of_live {n : ℕ} (rho : PartialAssignment n) (input : Fin n → Bool) {index : Fin n} (live : rho index = none) :
            rho.apply input index = input index
            @[simp]
            theorem Algebraic.PartialAssignment.apply_of_fixed {n : ℕ} (rho : PartialAssignment n) (input : Fin n → Bool) {index : Fin n} {value : Bool} (fixed : rho index = some value) :
            rho.apply input index = value
            @[simp]
            theorem Algebraic.PartialAssignment.apply_empty {n : ℕ} (input : Fin n → Bool) :
            empty.apply input = input
            @[simp]
            theorem Algebraic.PartialAssignment.apply_total {n : ℕ} (fixed input : Fin n → Bool) :
            (total fixed).apply input = fixed
            theorem Algebraic.PartialAssignment.apply_fix_eq_self {n : ℕ} (input : Fin n → Bool) (selected : Fin n) (value : Bool) (selectedValue : input selected = value) :
            (fix selected value).apply input = input

            Fixing a variable to the value it already has leaves a complete input unchanged.

            Refine rho with sigma, retaining every value already fixed by rho.

            Equations
            Instances For

              Clear a designated finite set of coordinates, leaving every other value unchanged. This is the inverse operation used by refinement encodings once their newly fixed support has been reconstructed.

              Equations
              Instances For
                @[simp]
                theorem Algebraic.PartialAssignment.clear_of_mem {n : ℕ} (rho : PartialAssignment n) (coordinates : Finset (Fin n)) {index : Fin n} (present : index ∈ coordinates) :
                rho.clear coordinates index = none
                @[simp]
                theorem Algebraic.PartialAssignment.clear_of_not_mem {n : ℕ} (rho : PartialAssignment n) (coordinates : Finset (Fin n)) {index : Fin n} (absent : index ∉ coordinates) :
                rho.clear coordinates index = rho index
                theorem Algebraic.PartialAssignment.apply_refine {n : ℕ} (rho sigma : PartialAssignment n) (input : Fin n → Bool) :
                (rho.refine sigma).apply input = rho.apply (sigma.apply input)

                Applying a sequential refinement is function composition on inputs.

                theorem Algebraic.PartialAssignment.refine_assoc {n : ℕ} (rho sigma tau : PartialAssignment n) :
                (rho.refine sigma).refine tau = rho.refine (sigma.refine tau)

                Sequential refinement is associative.

                theorem Algebraic.PartialAssignment.fix_refine_refine_fix {n : ℕ} (rho tail : PartialAssignment n) (selected : Fin n) (pathValue satisfyingValue : Bool) (live : rho selected = none) :
                (fix selected pathValue).refine (rho.refine ((fix selected satisfyingValue).refine tail)) = (rho.refine (fix selected pathValue)).refine tail

                Replacing the freshly assigned head coordinate by a path value commutes with retaining the rest of a refinement. The selected coordinate must be live in the original restriction.

                View a partial assignment as a semantic input substitution on the same named variables.

                Equations
                Instances For

                  Conversion to input substitutions preserves sequential composition.

                  The finite set of variables left live by a partial assignment.

                  Equations
                  Instances For
                    @[simp]
                    theorem Algebraic.PartialAssignment.mem_liveVariables {n : ℕ} (rho : PartialAssignment n) (index : Fin n) :
                    index ∈ rho.liveVariables ↔ rho index = none

                    The number of variables left live by a partial assignment.

                    Equations
                    Instances For

                      The increasing bijection from a compact input namespace to the variables left live by a partial assignment.

                      Equations
                      Instances For
                        noncomputable def Algebraic.PartialAssignment.liveVariable {n : ℕ} (rho : PartialAssignment n) :
                        Fin rho.liveCount → Fin n

                        The original input coordinate represented by a compact live-input index.

                        Equations
                        Instances For
                          noncomputable def Algebraic.PartialAssignment.liveIndex {n : ℕ} (rho : PartialAssignment n) (index : Fin n) (live : rho index = none) :

                          The compact index of an original coordinate known to be live.

                          Equations
                          Instances For
                            @[simp]
                            theorem Algebraic.PartialAssignment.liveVariable_liveIndex {n : ℕ} (rho : PartialAssignment n) (index : Fin n) (live : rho index = none) :
                            rho.liveVariable (rho.liveIndex index live) = index
                            @[simp]
                            theorem Algebraic.PartialAssignment.liveIndex_liveVariable {n : ℕ} (rho : PartialAssignment n) (index : Fin rho.liveCount) :
                            rho.liveIndex (rho.liveVariable index) ⋯ = index
                            noncomputable def Algebraic.PartialAssignment.projectLive {n : ℕ} (rho : PartialAssignment n) (input : Fin n → Bool) :

                            Read a complete input only at the coordinates left live by rho.

                            Equations
                            Instances For

                              Express every original input as either a fixed Boolean or one of the compactly reindexed live inputs.

                              Equations
                              Instances For
                                @[simp]
                                theorem Algebraic.PartialAssignment.toLiveInputSubstitution_of_fixed {n : ℕ} (rho : PartialAssignment n) (input : Fin rho.liveCount → Bool) {index : Fin n} {value : Bool} (fixed : rho index = some value) :
                                rho.toLiveInputSubstitution.apply input index = value
                                @[simp]
                                theorem Algebraic.PartialAssignment.toLiveInputSubstitution_liveVariable {n : ℕ} (rho : PartialAssignment n) (input : Fin rho.liveCount → Bool) (index : Fin rho.liveCount) :
                                rho.toLiveInputSubstitution.apply input (rho.liveVariable index) = input index

                                Projecting a complete input to its live coordinates and then restoring fixed coordinates is exactly ordinary application of the restriction.

                                @[simp]

                                Compact live inputs are recovered after restoring the original input namespace.

                                The finite set of variables fixed by a partial assignment.

                                Equations
                                Instances For
                                  @[simp]
                                  theorem Algebraic.PartialAssignment.mem_fixedVariables {n : ℕ} (rho : PartialAssignment n) (index : Fin n) :
                                  index ∈ rho.fixedVariables ↔ rho index ≠ none

                                  The number of variables fixed by a partial assignment.

                                  Equations
                                  Instances For
                                    @[simp]
                                    theorem Algebraic.PartialAssignment.liveCount_total {n : ℕ} (input : Fin n → Bool) :
                                    (total input).liveCount = 0
                                    @[simp]
                                    theorem Algebraic.PartialAssignment.fixedCount_total {n : ℕ} (input : Fin n → Bool) :
                                    (total input).fixedCount = n

                                    Every variable is either live or fixed, but not both.

                                    The live and fixed variable sets are disjoint.

                                    Live and fixed variables partition the input coordinates exactly.

                                    theorem Algebraic.PartialAssignment.liveVariables_fix {n : ℕ} (selected : Fin n) (value : Bool) :
                                    (fix selected value).liveVariables = Finset.univ.erase selected

                                    Fixing one variable removes exactly that variable from the live set.

                                    theorem Algebraic.PartialAssignment.fixedVariables_fix {n : ℕ} (selected : Fin n) (value : Bool) :
                                    (fix selected value).fixedVariables = {selected}

                                    A one-variable assignment fixes exactly its selected coordinate.

                                    The live variables after sequential refinement are the variables left live by both constituent partial assignments.

                                    The variables fixed by a sequential refinement are exactly those fixed by either constituent assignment.

                                    Sequential refinement cannot increase the number of live variables.

                                    theorem Algebraic.PartialAssignment.liveVariables_refine_fix {n : ℕ} (rho : PartialAssignment n) (selected : Fin n) (value : Bool) :
                                    (rho.refine (fix selected value)).liveVariables = rho.liveVariables.erase selected

                                    Refining by a one-variable assignment removes exactly that variable from the live set. If it was already fixed, the set is unchanged.

                                    theorem Algebraic.PartialAssignment.liveCount_refine_fix_lt_of_live {n : ℕ} (rho : PartialAssignment n) (selected : Fin n) (value : Bool) (live : rho selected = none) :
                                    (rho.refine (fix selected value)).liveCount < rho.liveCount

                                    Fixing a currently live variable strictly decreases the live count.

                                    If the second assignment fixes only variables left live by the first, their fixed-variable counts add under refinement.

                                    theorem Algebraic.PartialAssignment.clear_refine_fixedVariables {n : ℕ} (rho extension : PartialAssignment n) (newFixes : extension.fixedVariables ⊆ rho.liveVariables) :
                                    (rho.refine extension).clear extension.fixedVariables = rho

                                    Clearing exactly the support added by a refinement recovers the original restriction, provided the refinement fixed only previously live variables.

                                    Under a refinement that fixes only live variables, the decrease in live count is exactly the second assignment's fixed count.

                                    theorem Algebraic.PartialAssignment.apply_eq_of_agree_live {n : ℕ} (rho : PartialAssignment n) {left right : Fin n → Bool} (agree : ∀ index ∈ rho.liveVariables, left index = right index) :
                                    rho.apply left = rho.apply right

                                    Inputs that agree on every live variable become equal after applying the partial assignment.

                                    Restrict a scalar Boolean function by a partial assignment.

                                    Equations
                                    Instances For
                                      @[simp]
                                      theorem Algebraic.ScalarFunction.restrict_apply {n : ℕ} (function : ScalarFunction Bool n) (rho : PartialAssignment n) (input : Fin n → Bool) :
                                      function.restrict rho input = function (rho.apply input)
                                      theorem Algebraic.ScalarFunction.restrict_refine {n : ℕ} (function : ScalarFunction Bool n) (rho sigma : PartialAssignment n) :
                                      (function.restrict rho).restrict sigma = function.restrict (rho.refine sigma)

                                      Restricting twice agrees with restriction by sequential refinement.

                                      A restricted scalar function depends only on variables left live.

                                      def Algebraic.Target.restrict {n m : ℕ} (target : Target Bool n m) (rho : PartialAssignment n) :

                                      Restrict every output of a Boolean target by a partial assignment.

                                      Equations
                                      Instances For
                                        @[simp]
                                        theorem Algebraic.Target.restrict_apply {n m : ℕ} (target : Target Bool n m) (rho : PartialAssignment n) (input : Fin n → Bool) :
                                        target.restrict rho input = target (rho.apply input)
                                        @[simp]
                                        theorem Algebraic.Target.restrict_empty {n m : ℕ} (target : Target Bool n m) :
                                        theorem Algebraic.Target.restrict_refine {n m : ℕ} (target : Target Bool n m) (rho sigma : PartialAssignment n) :
                                        (target.restrict rho).restrict sigma = target.restrict (rho.refine sigma)

                                        Restricting a target twice agrees with sequential refinement.

                                        A restricted target depends only on variables left live.