Documentation

DescriptiveComplexity.HeadEval

Evaluating a first-order formula with heads #

The half of the capture theorem that has content: a two-way multi-head automaton can decide any fixed first-order formula of its head positions, spending two extra heads per quantifier.

The guards of a DescriptiveComplexity.HeadProgram are quantifier-free by fiat – a control that could read a quantified fact would be first-order logic in disguise. This file removes the apparent limitation: quantifiers are not read, they are walked. To decide ∀ x, φ(x) the program parks a head at the greatest element, sweeps another head from the least element upwards, and evaluates φ at each stop; it answers false at the first stop where φ fails, and true when the sweep reaches the parked head. Existential quantification is with → ⊥ around it, which the imp case already handles, so a single sweep serves both.

The two combinators #

Both are DescriptiveComplexity.HeadProgram.wireP over a four- or three-node control graph, and both are proved by DescriptiveComplexity.HeadProgram.runs_wireP: the sweep's proof is an induction downwards along the order (DescriptiveComplexity.order_induction_down), which is the direction that knows about the elements a walker has not yet reached.

The evaluator #

DescriptiveComplexity.HeadProgram.evalP is defined by structural recursion on a BoundedFormula, with a fixed layout of the heads:

The recursion never inspects a state: each case is a combinator, and its correctness is the corresponding combinator lemma applied to the inductive hypothesis. The result, DescriptiveComplexity.HeadProgram.decides_evalP, is a DescriptiveComplexity.HeadProgram.Decides, and DescriptiveComplexity.HeadProgram.deterministic_evalP records that the evaluator is deterministic – a sweep is not a guess – which is what lets the same evaluator serve the deterministic capture.

Moving a single head #

The moves that send head h along mv and leave every other head where it is.

Equations
Instances For
    Dependency graph
    @[simp]
    theorem DescriptiveComplexity.HeadProgram.setHead_self {K : } (h : Fin K) (mv : HeadMove K) :
    setHead h mv h = mv
    Dependency graph
    @[simp]
    theorem DescriptiveComplexity.HeadProgram.setHead_of_ne {K : } {h j : Fin K} (mv : HeadMove K) (hj : j h) :
    Dependency graph
    theorem DescriptiveComplexity.HeadProgram.runs_moveP_local {L : FirstOrder.Language} {K : } {A : Type} [L.Structure A] [LinearOrder A] (mvs : Fin KHeadMove K) (m : ) (hstay : ∀ (j : Fin K), m jmvs j = HeadMove.stay) :
    (moveP mvs).Runs A m fun (x : Fin KA) (b : Bool) (y : Fin KA) => b = true ∀ (j : Fin K), j < m(mvs j).Holds x j (y j)

    Moving, seen from the interface: a fragment that only moves heads below m runs a relation about those heads alone.

    Dependency graph

    Branching #

    The control nodes of a branch: the test, and its two continuations.

    • test : IteNode

      Running the test.

    • thenB : IteNode

      Running the continuation taken when the test says true.

    • elseB : IteNode

      Running the continuation taken when the test says false.

    Instances For
      Dependency graph
      Dependency graph
      Dependency graph
      Dependency graph
      Dependency graph

      Branching: run F; continue with G if it says true and with H if it says false, and answer what the continuation answers.

      Equations
      Instances For
        Dependency graph
        theorem DescriptiveComplexity.HeadProgram.iteWalk {K : } {A : Type} {R : IteNode(Fin KA)Bool(Fin KA)Prop} {x : Fin KA} {u : IteNode × (Fin KA)} (h : Relation.ReflTransGen (wireStep R iteWire) (IteNode.test, x) u) :
        u = (IteNode.test, x) (∃ (y : Fin KA), u = (IteNode.thenB, y) R IteNode.test x true y) ∃ (y : Fin KA), u = (IteNode.elseB, y) R IteNode.test x false y

        The walk of a branch: from the test, one either has not moved, or has handed over to one of the two continuations.

        Dependency graph
        Dependency graph
        theorem DescriptiveComplexity.HeadProgram.runs_iteP {L : FirstOrder.Language} {K : } {A : Type} [L.Structure A] [LinearOrder A] {m : } {F G H : HeadProgram L K} {R S T : (Fin KA)Bool(Fin KA)Prop} (hF : F.Runs A m R) (hG : G.Runs A m S) (hH : H.Runs A m T) (hRl : HeadLocal2 m R) (hSl : HeadLocal2 m S) (hTl : HeadLocal2 m T) :
        (F.iteP G H).Runs A m fun (x : Fin KA) (b : Bool) (z : Fin KA) => ∃ (y : Fin KA), R x true y S y b z R x false y T y b z

        What a branch runs: the test, followed by whichever continuation its answer selects.

        Dependency graph
        theorem DescriptiveComplexity.HeadProgram.decides_iteP {L : FirstOrder.Language} {K : } {A : Type} [L.Structure A] [LinearOrder A] {m : } {F G H : HeadProgram L K} {P Q₁ Q₂ : (Fin KA)Prop} (hF : F.Decides A m P) (hG : G.Decides A m Q₁) (hH : H.Decides A m Q₂) (hP : HeadLocal m P) (hQ₁ : HeadLocal m Q₁) (hQ₂ : HeadLocal m Q₂) :
        (F.iteP G H).Decides A m fun (x : Fin KA) => P x Q₁ x ¬P x Q₂ x

        What a branch decides: the test's property, with the continuations' properties under it.

        Dependency graph

        A branch is deterministic as soon as its three fragments are.

        Dependency graph

        Sweeping a head along the order #

        Dependency graph
        theorem DescriptiveComplexity.HeadProgram.holds_congr {K : } {A : Type} [LinearOrder A] {mv : HeadMove K} {m : } (hmv : MoveLocal m mv) {x x' : Fin KA} (hx : HeadAgree m x x') {j : Fin K} (hj : j < m) (v : A) :
        mv.Holds x j v mv.Holds x' j v

        A move that looks only at the first m heads cannot tell two assignments agreeing there apart.

        Dependency graph
        theorem DescriptiveComplexity.HeadProgram.headLocal2_moveP {K : } {A : Type} [LinearOrder A] {mvs : Fin KHeadMove K} {m : } (hloc : ∀ (j : Fin K), j < mMoveLocal m (mvs j)) :
        HeadLocal2 m fun (x : Fin KA) (b : Bool) (y : Fin KA) => b = true ∀ (j : Fin K), j < m(mvs j).Holds x j (y j)

        The relation a move fragment runs is local when its moves are.

        Dependency graph

        The control nodes of a sweep.

        • reset : ScanNode

          Putting the walking head at the least element and the marker at the greatest.

        • body : ScanNode

          Evaluating the body at the current value of the walking head.

        • atMax : ScanNode

          Asking whether the walking head has reached the marker.

        • bump : ScanNode

          Stepping the walking head to the next element.

        Instances For
          Dependency graph
          Dependency graph
          Dependency graph
          Dependency graph

          The moves that start a sweep: the walking head to the least element, the marker to the greatest.

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

            The sweep: run F at every value of head h in turn, from the least element up to the marker head hm; answer false at the first value where F does, and true if it never does.

            Equations
            • One or more equations did not get rendered due to their size.
            Instances For
              Dependency graph
              def DescriptiveComplexity.HeadProgram.scanRel {K : } {A : Type} [LinearOrder A] (d : ) (h hm : Fin K) (P : (Fin KA)Prop) :
              ScanNode(Fin KA)Bool(Fin KA)Prop

              The relations the fragments of a sweep run.

              Equations
              • One or more equations did not get rendered due to their size.
              Instances For
                Dependency graph
                theorem DescriptiveComplexity.HeadProgram.Decides.congr {L : FirstOrder.Language} {K : } {A : Type} [L.Structure A] [LinearOrder A] {F : HeadProgram L K} {m : } {P P' : (Fin KA)Prop} (h : F.Decides A m P) (hPP : ∀ (x : Fin KA), P x P' x) :
                F.Decides A m P'

                Restating what a fragment decides.

                Dependency graph
                theorem DescriptiveComplexity.HeadProgram.decides_scanP {L : FirstOrder.Language} {K : } {A : Type} [L.Structure A] [LinearOrder A] [Finite A] {d : } {h hm : Fin K} (hh : h = d) (hhm : hm = d + 1) {F : HeadProgram L K} {P : (Fin KA)Prop} (hF : F.Decides A (d + 2) P) (hP : HeadLocal (d + 1) P) :
                (scanP h hm F).Decides A d fun (x : Fin KA) => ∀ (a : A), P (Function.update x h a)

                What a sweep decides: the body, at every value of the walking head.

                Dependency graph

                A sweep is deterministic as soon as its body is: it walks, it does not guess.

                Dependency graph

                Atoms as guards #

                An atomic formula, read as a guard on the heads: its variables are sent to the heads that hold them.

                Equations
                Instances For
                  Dependency graph

                  Turning the bound variables into free ones keeps a formula quantifier-free.

                  Dependency graph

                  A guard read off a quantifier-free formula is quantifier-free, as a guard must be.

                  Dependency graph
                  theorem DescriptiveComplexity.HeadProgram.realize_atomGuard {L : FirstOrder.Language} {K : } {α A : Type} [L.Structure A] [LinearOrder A] {n : } (hv : α Fin nFin K) (ψ : (L.sum FirstOrder.Language.order).BoundedFormula α n) (x : Fin KA) :
                  (atomGuard hv ψ).Realize x ψ.Realize (fun (a : α) => x (hv (Sum.inl a))) fun (i : Fin n) => x (hv (Sum.inr i))

                  The guard holds exactly where the formula does, its variables read off the heads.

                  Dependency graph
                  theorem DescriptiveComplexity.HeadProgram.headLocal_realize {L : FirstOrder.Language} {K : } {α A : Type} [L.Structure A] [LinearOrder A] {n d : } (hv : α Fin nFin K) (ψ : (L.sum FirstOrder.Language.order).BoundedFormula α n) (hlow : ∀ (v : α Fin n), (hv v) < d) :
                  HeadLocal d fun (x : Fin KA) => ψ.Realize (fun (a : α) => x (hv (Sum.inl a))) fun (i : Fin n) => x (hv (Sum.inr i))

                  What a formula says of the heads depends only on the heads its variables live in.

                  Dependency graph

                  Exiting at once decides falsity.

                  Dependency graph

                  Exiting at once decides truth.

                  Dependency graph

                  The evaluator #

                  Dependency graph
                  def DescriptiveComplexity.HeadProgram.evalP {L : FirstOrder.Language} {K : } {α : Type} (sh : Fin K) {n : } :
                  (α Fin nFin K)(L.sum FirstOrder.Language.order).BoundedFormula α nHeadProgram L K

                  The evaluator: a program deciding a fixed first-order formula of the heads. Atoms are guards, implication is a branch, and a quantifier is a sweep of two fresh heads – sh d walking, sh (d + 1) marking the greatest element.

                  Equations
                  Instances For
                    Dependency graph
                    theorem DescriptiveComplexity.HeadProgram.decides_evalP {L : FirstOrder.Language} {K : } {α A : Type} [L.Structure A] [LinearOrder A] [Finite A] (sh : Fin K) (hsh : i < K, (sh i) = i) {n : } (ψ : (L.sum FirstOrder.Language.order).BoundedFormula α n) (d : ) (hv : α Fin nFin K) :
                    (∀ (v : α Fin n), (hv v) < d)d + qdepth ψ K(evalP sh d hv ψ).Decides A d fun (x : Fin KA) => ψ.Realize (fun (a : α) => x (hv (Sum.inl a))) fun (i : Fin n) => x (hv (Sum.inr i))

                    The evaluator is correct: it decides the formula, reading its variables off the heads they live in, and gives those heads back untouched.

                    Dependency graph
                    theorem DescriptiveComplexity.HeadProgram.deterministic_evalP {L : FirstOrder.Language} {K : } {α A : Type} [L.Structure A] [LinearOrder A] (sh : Fin K) {n : } (ψ : (L.sum FirstOrder.Language.order).BoundedFormula α n) (d : ) (hv : α Fin nFin K) :
                    (evalP sh d hv ψ).Deterministic A

                    The evaluator is deterministic: it sweeps, it does not guess. This is what lets the same programs serve the deterministic capture.

                    Dependency graph