Documentation

Complexitylib.Algebraic.LowerBound.AC0.CanonicalDecisionTree

Canonical decision trees for DNF formulas #

This module formalizes the dynamic canonical decision tree used in the decision-tree form of Hastad's switching lemma. At each partial assignment it restricts the whole DNF, selects the first surviving term, and queries every remaining variable of that term in input-coordinate order. A satisfying branch returns true; every other branch repeats the construction after the new assignments have simplified the entire formula.

The recursion is structural in the number of live variables. It is not an optimal-tree search. The distinguished tree makes the eventual switching event concrete and decidable while its correctness gives an ordinary existential decision-tree depth bound as a corollary.

The support of a literal set in the canonical input-coordinate order.

Equations
Instances For
    @[simp]
    theorem Algebraic.AC0.LiteralSet.mem_orderedSupport {n : ℕ} (set : LiteralSet n) (index : Fin n) :
    index ∈ set.orderedSupport ↔ index ∈ set.support

    Canonical support lists contain no repeated coordinate.

    The first source term not already falsified by a partial assignment.

    Equations
    Instances For
      def Algebraic.AC0.DNF.firstSurviving {n : ℕ} (formula : DNF n) (rho : PartialAssignment n) :

      The first term of an ordered DNF not falsified by the assignment.

      Equations
      Instances For
        theorem Algebraic.AC0.DNF.firstSurvivingIn_eq_none_iff {n : ℕ} (rho : PartialAssignment n) (terms : List (Term n)) :
        firstSurvivingIn rho terms = none ↔ ∀ term ∈ terms, LiteralSet.ConflictsWith term rho

        Failure to find a surviving term means that every source term conflicts with the assignment.

        theorem Algebraic.AC0.DNF.firstSurvivingIn_mem {n : ℕ} (rho : PartialAssignment n) (terms : List (Term n)) {term : Term n} (found : firstSurvivingIn rho terms = some term) :
        term ∈ terms

        A term returned by firstSurvivingIn occurs in the source list.

        theorem Algebraic.AC0.DNF.firstSurvivingIn_not_conflicts {n : ℕ} (rho : PartialAssignment n) (terms : List (Term n)) {term : Term n} (found : firstSurvivingIn rho terms = some term) :

        A term returned by firstSurvivingIn is not falsified.

        theorem Algebraic.AC0.DNF.firstSurvivingIn_refine {n : ℕ} (rho extension : PartialAssignment n) (terms : List (Term n)) {term : Term n} (found : firstSurvivingIn rho terms = some term) (survives : ¬LiteralSet.ConflictsWith term (rho.refine extension)) :
        firstSurvivingIn (rho.refine extension) terms = some term

        A first surviving term remains first after refinement whenever that term itself remains nonconflicting.

        def Algebraic.AC0.DNF.liveSupport {n : ℕ} (term : Term n) (rho : PartialAssignment n) :
        List (Fin n)

        Variables of term still live under rho, retained in canonical input order.

        Equations
        Instances For
          @[simp]
          theorem Algebraic.AC0.DNF.mem_liveSupport {n : ℕ} (term : Term n) (rho : PartialAssignment n) (index : Fin n) :
          index ∈ liveSupport term rho ↔ index ∈ LiteralSet.support term ∧ rho index = none
          theorem Algebraic.AC0.DNF.nodup_liveSupport {n : ℕ} (term : Term n) (rho : PartialAssignment n) :
          (liveSupport term rho).Nodup

          Live-support lists contain no repeated coordinate.

          Computing live support from the source term agrees with first taking its residual literal set.

          theorem Algebraic.AC0.DNF.firstSurviving_refine {n : ℕ} (formula : DNF n) (rho extension : PartialAssignment n) {term : Term n} (found : formula.firstSurviving rho = some term) (survives : ¬LiteralSet.ConflictsWith term (rho.refine extension)) :
          formula.firstSurviving (rho.refine extension) = some term

          A first surviving source term remains first after a refinement whenever that term itself remains nonconflicting.

          theorem Algebraic.AC0.DNF.eval_apply_eq_false_of_firstSurviving_eq_none {n : ℕ} (formula : DNF n) (rho : PartialAssignment n) (input : Fin n → Bool) (noneSurvives : formula.firstSurviving rho = none) :
          formula.eval (rho.apply input) = false

          If no source term survives, the restricted DNF is constantly false.

          theorem Algebraic.AC0.DNF.eval_apply_eq_true_of_firstSurviving_liveSupport_eq_nil {n : ℕ} (formula : DNF n) (rho : PartialAssignment n) {term : Term n} (found : formula.firstSurviving rho = some term) (supportEmpty : liveSupport term rho = []) (input : Fin n → Bool) :
          formula.eval (rho.apply input) = true

          A surviving term with no live variable makes the restricted DNF constantly true.

          theorem Algebraic.AC0.DNF.support_subset_live_of_mem_restrict {n : ℕ} (formula : DNF n) (rho : PartialAssignment n) {term : Term n} (present : term ∈ (formula.restrict rho).terms) :

          Every term returned by DNF restriction uses only variables left live by the restriction.

          def Algebraic.AC0.DNF.queryRemainingBelow {n : ℕ} (indices : List (Fin n)) (rho : PartialAssignment n) (bound : ℕ) (below : rho.liveCount < bound) (recurse : (sigma : PartialAssignment n) → sigma.liveCount < bound → DecisionTree n) :

          Query the listed variables in order, then continue with recurse on the refined restriction, whose number of live variables stays below bound.

          Equations
          Instances For
            def Algebraic.AC0.DNF.canonicalSupportStep {n : ℕ} (_formula : DNF n) (rho : PartialAssignment n) (recurse : (sigma : PartialAssignment n) → sigma.liveCount < rho.liveCount → DecisionTree n) (indices : List (Fin n)) (allLive : ∀ index ∈ indices, rho index = none) :

            One step of the canonical decision tree at a surviving term: query the term's live variables, answer true if the term is satisfied, and otherwise recurse on the refined restriction.

            Equations
            Instances For
              def Algebraic.AC0.DNF.canonicalDecisionTreeStep {n : ℕ} (formula : DNF n) (rho : PartialAssignment n) (recurse : (sigma : PartialAssignment n) → sigma.liveCount < rho.liveCount → DecisionTree n) :

              One step of the canonical decision tree of a DNF under restriction rho: answer false if no term survives, and otherwise query the first surviving term's live variables.

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

                The canonical decision tree of formula below a partial assignment.

                The whole formula is freshly restricted between queried terms. Hence later term selection incorporates every assignment made along the current branch.

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

                  A canonical path transcript partitioned into the successive source terms selected by the canonical procedure.

                  Instances For
                    inductive Algebraic.AC0.DNF.CanonicalBlockTrace {n : ℕ} (formula : DNF n) :

                    The part of a canonical transcript currently querying one source term. The final constructor returns to CanonicalTrace, which selects the next source term after the completed block assignment.

                    Instances For
                      theorem Algebraic.AC0.DNF.canonicalTrace_of_path {n : ℕ} (formula : DNF n) (rho : PartialAssignment n) {steps : List (DecisionTree.PathStep n)} {endpoint : DecisionTree n} (path : (formula.canonicalDecisionTree rho).Path steps endpoint) :
                      Nonempty (formula.CanonicalTrace rho steps)

                      Every path through the canonical decision tree carries a source-term block trace matching the canonical selection procedure.

                      theorem Algebraic.AC0.DNF.canonicalDecisionTree_computes {n : ℕ} (formula : DNF n) (rho : PartialAssignment n) :
                      (formula.canonicalDecisionTree rho).Computes fun (input : Fin n → Bool) => formula.eval (rho.apply input)

                      The canonical tree computes exactly the DNF under the supplied partial assignment.

                      The canonical tree never queries more coordinates than remain live.

                      Every canonical root-to-leaf path queries each initially live coordinate at most once.

                      Every finite canonical path has distinct queried coordinates, all of which were live before the path began.

                      def Algebraic.AC0.DNF.canonicalDepth {n : ℕ} (formula : DNF n) (rho : PartialAssignment n) :

                      The numeric depth of the distinguished canonical tree.

                      Equations
                      Instances For

                        Canonical depth is bounded by the number of live variables.

                        def Algebraic.AC0.DNF.CanonicalDepthAtLeast {n : ℕ} (formula : DNF n) (rho : PartialAssignment n) (threshold : ℕ) :

                        The concrete bad event counted by the canonical switching argument.

                        Equations
                        Instances For
                          structure Algebraic.AC0.DNF.CanonicalPath {n : ℕ} (formula : DNF n) (rho : PartialAssignment n) (length : ℕ) :

                          An exact-length prefix of a path through a canonical DNF decision tree.

                          Instances For
                            theorem Algebraic.AC0.DNF.exists_canonicalPath {n : ℕ} (formula : DNF n) (rho : PartialAssignment n) (length : ℕ) (deep : formula.CanonicalDepthAtLeast rho length) :
                            Nonempty (formula.CanonicalPath rho length)

                            A canonical-depth event supplies an exact-length canonical path prefix.

                            theorem Algebraic.AC0.DNF.CanonicalPath.indices_nodup {n : ℕ} {formula : DNF n} {rho : PartialAssignment n} {length : ℕ} (path : formula.CanonicalPath rho length) :

                            Canonical path coordinates contain no duplicates.

                            theorem Algebraic.AC0.DNF.CanonicalPath.indices_subset_live {n : ℕ} {formula : DNF n} {rho : PartialAssignment n} {length : ℕ} (path : formula.CanonicalPath rho length) :

                            Every canonical path coordinate was live at the path's initial restriction.

                            theorem Algebraic.AC0.DNF.CanonicalPath.assignment_fixedCount {n : ℕ} {formula : DNF n} {rho : PartialAssignment n} {length : ℕ} (path : formula.CanonicalPath rho length) :

                            The assignment carried by an exact canonical path fixes exactly the path length.

                            The assignment carried by a canonical path fixes only variables live at the path's initial restriction.

                            @[instance_reducible]
                            instance Algebraic.AC0.DNF.canonicalDepthAtLeastDecidable {n : ℕ} (formula : DNF n) (rho : PartialAssignment n) (threshold : ℕ) :
                            Decidable (formula.CanonicalDepthAtLeast rho threshold)
                            Equations

                            The canonical tree also computes the syntactically restricted DNF.

                            The canonical tree witnesses an ordinary decision-tree upper bound for the restricted DNF.

                            theorem Algebraic.AC0.DNF.canonicalDepthAtLeast_of_depthAtLeast {n : ℕ} (formula : DNF n) (rho : PartialAssignment n) (threshold : ℕ) (lower : DecisionTree.DepthAtLeast (formula.restrict rho).eval threshold) :
                            formula.CanonicalDepthAtLeast rho threshold

                            If every tree for the restricted function has depth at least threshold, then the canonical tree does too. This relates the concrete switching event to the representation-independent lower-depth predicate.

                            At the empty restriction, the canonical tree computes the original DNF.