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
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
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
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
The relations the fragments of a branch run.
Equations
Instances For
Dependency graph
What a branch runs: the test, followed by whichever continuation its answer selects.
Dependency graph
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 #
Which heads a move looks at: the ones a fragment protecting m heads may
mention.
Equations
- DescriptiveComplexity.HeadProgram.MoveLocal m DescriptiveComplexity.HeadMove.stay = True
- DescriptiveComplexity.HeadProgram.MoveLocal m DescriptiveComplexity.HeadMove.toMin = True
- DescriptiveComplexity.HeadProgram.MoveLocal m DescriptiveComplexity.HeadMove.toMax = True
- DescriptiveComplexity.HeadProgram.MoveLocal m (DescriptiveComplexity.HeadMove.copy i) = (↑i < m)
- DescriptiveComplexity.HeadProgram.MoveLocal m (DescriptiveComplexity.HeadMove.succ i) = (↑i < m)
- DescriptiveComplexity.HeadProgram.MoveLocal m (DescriptiveComplexity.HeadMove.pred i) = (↑i < m)
Instances For
Dependency graph
A move that looks only at the first m heads cannot tell two assignments
agreeing there apart.
Dependency graph
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
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
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
Restating what a fragment decides.
Dependency graph
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
The guard holds exactly where the formula does, its variables read off the heads.
Dependency graph
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 #
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.