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 #
DescriptiveComplexity.HeadProgram.iteP– run a fragment, then one of two others depending on its answer. This is branching, sequencing and negation at once.DescriptiveComplexity.HeadProgram.scanP– the sweep just described, on a pair of heads:hwalks,hmmarks the greatest element. Why two heads and not one: the sweep must know when to stop, and “this head is at the greatest element” is not a quantifier-free fact of one head – while “these two heads are equal” is, being an atom. A single parked head buys the test. The step off the end is not needed as a guard:DescriptiveComplexity.HeadMove.succis simply disabled there.
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 free variables live wherever the caller says, through a map
hvinto heads below the protection leveld; - the
i-th bound variable lives at headd + 2 * i-ish – precisely, entering a quantifier at leveldclaims headsdandd + 1and recurses at leveld + 2, soDescriptiveComplexity.HeadProgram.qdepthcounts two heads per nested quantifier; - everything from the current level up is scratch.
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
Dependency graph
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
The wiring of a branch: the test hands over to one of the continuations, which then answer for the whole.
Equations
- DescriptiveComplexity.HeadProgram.iteWire DescriptiveComplexity.HeadProgram.IteNode.test true = Sum.inl DescriptiveComplexity.HeadProgram.IteNode.thenB
- DescriptiveComplexity.HeadProgram.iteWire DescriptiveComplexity.HeadProgram.IteNode.test false = Sum.inl DescriptiveComplexity.HeadProgram.IteNode.elseB
- DescriptiveComplexity.HeadProgram.iteWire x✝¹ x✝ = Sum.inr x✝
Instances For
Dependency graph
The fragments of a branch.
Equations
Instances For
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
Sweeping a head along the order #
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
The wiring of a sweep: a body that fails ends it, a body that succeeds asks whether the sweep is over, and if it is not the walking head steps on.
Equations
- DescriptiveComplexity.HeadProgram.scanWire DescriptiveComplexity.HeadProgram.ScanNode.reset x✝ = Sum.inl DescriptiveComplexity.HeadProgram.ScanNode.body
- DescriptiveComplexity.HeadProgram.scanWire DescriptiveComplexity.HeadProgram.ScanNode.body true = Sum.inl DescriptiveComplexity.HeadProgram.ScanNode.atMax
- DescriptiveComplexity.HeadProgram.scanWire DescriptiveComplexity.HeadProgram.ScanNode.body false = Sum.inr false
- DescriptiveComplexity.HeadProgram.scanWire DescriptiveComplexity.HeadProgram.ScanNode.atMax true = Sum.inr true
- DescriptiveComplexity.HeadProgram.scanWire DescriptiveComplexity.HeadProgram.ScanNode.atMax false = Sum.inl DescriptiveComplexity.HeadProgram.ScanNode.bump
- DescriptiveComplexity.HeadProgram.scanWire DescriptiveComplexity.HeadProgram.ScanNode.bump x✝ = Sum.inl DescriptiveComplexity.HeadProgram.ScanNode.body
Instances For
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
The fragments of a sweep.
Equations
- One or more equations did not get rendered due to their size.
- DescriptiveComplexity.HeadProgram.scanFam h hm F DescriptiveComplexity.HeadProgram.ScanNode.reset = DescriptiveComplexity.HeadProgram.moveP (DescriptiveComplexity.HeadProgram.resetMoves h hm)
- DescriptiveComplexity.HeadProgram.scanFam h hm F DescriptiveComplexity.HeadProgram.ScanNode.body = F
- DescriptiveComplexity.HeadProgram.scanFam h hm F DescriptiveComplexity.HeadProgram.ScanNode.atMax = DescriptiveComplexity.HeadProgram.leafP (DescriptiveComplexity.HeadMove.eqVarF L h hm) ⋯
Instances For
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
Restating what a fragment decides.
Dependency graph
What a sweep decides: the body, at every value of the walking head.
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
A guard read off a quantifier-free formula is quantifier-free, as a guard must be.
Dependency graph
The evaluator #
How many heads an evaluation needs: two per nested quantifier, one to walk and one to mark the greatest element.
Equations
- DescriptiveComplexity.HeadProgram.qdepth FirstOrder.Language.BoundedFormula.falsum = 0
- DescriptiveComplexity.HeadProgram.qdepth (FirstOrder.Language.BoundedFormula.equal t₁ t₂) = 0
- DescriptiveComplexity.HeadProgram.qdepth (FirstOrder.Language.BoundedFormula.rel R ts) = 0
- DescriptiveComplexity.HeadProgram.qdepth (φ₁.imp φ₂) = max (DescriptiveComplexity.HeadProgram.qdepth φ₁) (DescriptiveComplexity.HeadProgram.qdepth φ₂)
- DescriptiveComplexity.HeadProgram.qdepth φ.all = DescriptiveComplexity.HeadProgram.qdepth φ + 2
Instances For
Dependency graph
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
- One or more equations did not get rendered due to their size.
- DescriptiveComplexity.HeadProgram.evalP sh x✝¹ x✝ FirstOrder.Language.BoundedFormula.falsum = DescriptiveComplexity.HeadProgram.exitP false
Instances For
Dependency graph
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
The evaluator is deterministic: it sweeps, it does not guess. This is what lets the same programs serve the deterministic capture.