The capture theorem for NL: FO(TC) is what a multi-head automaton recognizes #
DescriptiveComplexity.HeadAutomaton compiles a machine into a
DescriptiveComplexity.TCSpec, which is the easy half. This file is the other half:
every FO(TC) definable problem is recognized by a two-way multi-head
automaton, so that the two notions coincide and
DescriptiveComplexity.NL is captured by the machine model as well as by the logic.
The machine #
Given a specification with arity k, the machine has 2 * k + D + 1 heads:
- the first
khold the current tuple of the walk; - the next
khold a candidate for the next tuple; - the remaining
Dare the workspace ofDescriptiveComplexity.HeadProgram.evalP, which evaluates the specification's formulas –Dbeing the largest quantifier budget among them – plus one spare head so that the head type is never empty.
The mode of the walk is not on a head – it cannot be, a one-element universe having only one tuple – but in the control, which is what a finite control is for.
The loop #
Written as a control graph over fragments
(DescriptiveComplexity.HeadProgram.wireP), the machine is:
- pick a source mode: a chain of free choices
(
DescriptiveComplexity.HeadProgram.chooseP) walking the list of modes, so that any mode may be selected; - try it: guess the current tuple (
DescriptiveComplexity.HeadProgram.guessP, a head walked up the order by a nondeterministic number of steps) and evaluate the source formula; a failure leads nowhere; - at a node: evaluate the target formula – if it holds, accept;
- otherwise pick a candidate mode, guess the candidate tuple, evaluate the transition formula, and, if it holds, commit: copy the candidate onto the current tuple and go back to evaluating the target formula.
Guessing is where the nondeterminism lives, and it is the only place: the evaluator itself is deterministic.
The proof #
DescriptiveComplexity.HeadProgram.runs_wireP turns the machine's runs into a walk in
the control graph, and the correctness is then an argument about that walk, in
two directions:
- soundness – an invariant carried along the walk: at a node of the control
graph, the tuple on the first
kheads is a node of the specification reachable from a source. It is preserved by every arc, and at the accepting arc it says exactly that the specification accepts; - completeness – by induction along
DescriptiveComplexity.TCSpec.Reach: every step of the specification's walk is imitated by the loop above, unless the target formula holds on the way, in which case the machine has already accepted.
The result is DescriptiveComplexity.tcDefinable_iff_automaton, and with it
DescriptiveComplexity.mem_NL_iff_automaton.
Free choices and guesses #
A free choice: exit either way, moving no head. It is the only source of
nondeterminism in the machines built here, together with
DescriptiveComplexity.HeadProgram.guessP.
Equations
- One or more equations did not get rendered due to their size.
Instances For
Dependency graph
One step of a guess: either walk head h to the next element, or stop.
Equations
- One or more equations did not get rendered due to their size.
Instances For
Dependency graph
Dependency graph
Dependency graph
Dependency graph
Dependency graph
Guessing one head #
The control nodes of a guess.
- reset : GuessNode
Putting the head on the least element.
- loop : GuessNode
Walking it up, for as long as the machine chooses to.
Instances For
Dependency graph
Dependency graph
Dependency graph
The wiring of a guess: walk up, or stop and answer true.
Equations
- DescriptiveComplexity.HeadProgram.guessWire DescriptiveComplexity.HeadProgram.GuessNode.reset x✝ = Sum.inl DescriptiveComplexity.HeadProgram.GuessNode.loop
- DescriptiveComplexity.HeadProgram.guessWire DescriptiveComplexity.HeadProgram.GuessNode.loop true = Sum.inl DescriptiveComplexity.HeadProgram.GuessNode.loop
- DescriptiveComplexity.HeadProgram.guessWire DescriptiveComplexity.HeadProgram.GuessNode.loop false = Sum.inr true
Instances For
Dependency graph
The fragments of a guess.
Equations
- One or more equations did not get rendered due to their size.
- DescriptiveComplexity.HeadProgram.guessFam h DescriptiveComplexity.HeadProgram.GuessNode.loop = DescriptiveComplexity.HeadProgram.guessStepP h
Instances For
Dependency graph
Guessing a head: put head h on the least element and walk it up a
nondeterministic number of steps, so that it may end anywhere.
Equations
- One or more equations did not get rendered due to their size.
Instances For
Dependency graph
The relations the fragments of a guess run.
Equations
- One or more equations did not get rendered due to their size.
Instances For
Dependency graph
What a guess runs: head h may end anywhere, every other head staying
where it was.
Dependency graph
Guessing a block of heads #
Dependency graph
Dependency graph
Guessing several heads: the heads hd lo, …, hd (lo + n - 1), in turn.
Equations
- One or more equations did not get rendered due to their size.
- DescriptiveComplexity.HeadProgram.guessManyP hd lo 0 = DescriptiveComplexity.HeadProgram.exitP true
Instances For
Dependency graph
What guessing a block runs: the heads of the block may end anywhere, and no other head moves.
Dependency graph
The control graph of the machine #
The control nodes of the machine simulating a specification: which mode the
walk is in, and what it is doing. r is the number of modes, and the Fin (r + 1) indices walk the list of modes, one free choice at a time.
- pickSrc
{M : Type}
{r : ℕ}
(i : Fin (r + 1))
: DrvNode M r
Choosing which mode to start the walk in.
- trySrc
{M : Type}
{r : ℕ}
(m : M)
: DrvNode M r
Guessing a starting tuple and testing the source formula.
- target
{M : Type}
{r : ℕ}
(m : M)
: DrvNode M r
Testing the target formula at the current node.
- pickCand
{M : Type}
{r : ℕ}
(m : M)
(i : Fin (r + 1))
: DrvNode M r
Choosing which mode to step into.
- tryCand
{M : Type}
{r : ℕ}
(m m' : M)
: DrvNode M r
Guessing the next tuple and testing the transition formula.
- commit
{M : Type}
{r : ℕ}
(m m' : M)
: DrvNode M r
Copying the guessed tuple onto the current one.
- dead
{M : Type}
{r : ℕ}
: DrvNode M r
Nothing more to do.
Instances For
Dependency graph
Dependency graph
Where the machine goes when a fragment exits.
Equations
- One or more equations did not get rendered due to their size.
- DescriptiveComplexity.HeadProgram.drvWire modeAt nextIx i₀ (DescriptiveComplexity.HeadProgram.DrvNode.pickSrc i) false = Sum.inl (DescriptiveComplexity.HeadProgram.DrvNode.pickSrc (nextIx i))
- DescriptiveComplexity.HeadProgram.drvWire modeAt nextIx i₀ (DescriptiveComplexity.HeadProgram.DrvNode.trySrc m) true = Sum.inl (DescriptiveComplexity.HeadProgram.DrvNode.target m)
- DescriptiveComplexity.HeadProgram.drvWire modeAt nextIx i₀ (DescriptiveComplexity.HeadProgram.DrvNode.trySrc m) false = Sum.inl DescriptiveComplexity.HeadProgram.DrvNode.dead
- DescriptiveComplexity.HeadProgram.drvWire modeAt nextIx i₀ (DescriptiveComplexity.HeadProgram.DrvNode.target m) true = Sum.inr true
- DescriptiveComplexity.HeadProgram.drvWire modeAt nextIx i₀ (DescriptiveComplexity.HeadProgram.DrvNode.target m) false = Sum.inl (DescriptiveComplexity.HeadProgram.DrvNode.pickCand m i₀)
- DescriptiveComplexity.HeadProgram.drvWire modeAt nextIx i₀ (DescriptiveComplexity.HeadProgram.DrvNode.tryCand m m') true = Sum.inl (DescriptiveComplexity.HeadProgram.DrvNode.commit m m')
- DescriptiveComplexity.HeadProgram.drvWire modeAt nextIx i₀ (DescriptiveComplexity.HeadProgram.DrvNode.tryCand m m') false = Sum.inl DescriptiveComplexity.HeadProgram.DrvNode.dead
- DescriptiveComplexity.HeadProgram.drvWire modeAt nextIx i₀ (DescriptiveComplexity.HeadProgram.DrvNode.commit m m') x✝ = Sum.inl (DescriptiveComplexity.HeadProgram.DrvNode.target m')
- DescriptiveComplexity.HeadProgram.drvWire modeAt nextIx i₀ DescriptiveComplexity.HeadProgram.DrvNode.dead x✝ = Sum.inr false
Instances For
Dependency graph
The machine of a specification #
The quantifier budget of a specification: the largest number of extra heads the evaluation of one of its formulas needs.
Equations
- One or more equations did not get rendered due to their size.
Instances For
Dependency graph
How many heads the machine of a specification has: two tuples, the evaluator's workspace, and a spare one so that there is always a head.
Equations
- DescriptiveComplexity.specHeads spec = 2 * spec.k + DescriptiveComplexity.specDepth spec + 1
Instances For
Dependency graph
Dependency graph
The heads holding the current tuple.
Equations
- DescriptiveComplexity.blk0 spec i = ⟨↑i, ⋯⟩
Instances For
Dependency graph
The heads holding the candidate tuple.
Instances For
Dependency graph
The head at a given index, for the evaluator's workspace.
Equations
- DescriptiveComplexity.shd spec i = if h : i < DescriptiveComplexity.specHeads spec then ⟨i, h⟩ else ⟨0, ⋯⟩
Instances For
Dependency graph
Dependency graph
Dependency graph
Dependency graph
The node of the specification the machine is at: its mode, and the tuple on the first block of heads.
Equations
- DescriptiveComplexity.curNode spec x m = (m, fun (i : Fin spec.k) => x (DescriptiveComplexity.blk0 spec i))
Instances For
Dependency graph
The node the machine is considering stepping into: the tuple on the second block of heads.
Equations
- DescriptiveComplexity.candNode spec x m = (m, fun (i : Fin spec.k) => x (DescriptiveComplexity.blk1 spec i))
Instances For
Dependency graph
The fragments #
Dependency graph
Dependency graph
Dependency graph
The variables of a formula about the current tuple live in the first block of heads.
Equations
Instances For
Dependency graph
The variables of a transition formula live in the two blocks of heads.
Equations
- DescriptiveComplexity.hv01 spec = Sum.elim (Sum.elim (DescriptiveComplexity.blk0 spec) (DescriptiveComplexity.blk1 spec)) Fin.elim0
Instances For
Dependency graph
Dependency graph
Dependency graph
The evaluator for a source formula.
Equations
- DescriptiveComplexity.evalSrcP spec m = DescriptiveComplexity.HeadProgram.evalP (DescriptiveComplexity.shd spec) (2 * spec.k) (DescriptiveComplexity.hv0 spec) (spec.src m)
Instances For
Dependency graph
The evaluator for a target formula.
Equations
- DescriptiveComplexity.evalTgtP spec m = DescriptiveComplexity.HeadProgram.evalP (DescriptiveComplexity.shd spec) (2 * spec.k) (DescriptiveComplexity.hv0 spec) (spec.tgt m)
Instances For
Dependency graph
The evaluator for a transition formula.
Equations
- DescriptiveComplexity.evalStepP spec m m' = DescriptiveComplexity.HeadProgram.evalP (DescriptiveComplexity.shd spec) (2 * spec.k) (DescriptiveComplexity.hv01 spec) (spec.step m m')
Instances For
Dependency graph
The moves that copy the candidate tuple onto the current one.
Equations
- DescriptiveComplexity.commitMoves spec j = if h : ↑j < spec.k then DescriptiveComplexity.HeadMove.copy (DescriptiveComplexity.blk1 spec ⟨↑j, h⟩) else DescriptiveComplexity.HeadMove.stay
Instances For
Dependency graph
Dependency graph
Dependency graph
Dependency graph
Dependency graph
Dependency graph
Dependency graph
Dependency graph
The machine #
Dependency graph
An enumeration of the modes.
Equations
- DescriptiveComplexity.modeEquiv spec = Finite.equivFin spec.Mode
Instances For
Dependency graph
The mode at an index of the enumeration, if any.
Equations
- DescriptiveComplexity.modeAt spec i = if h : ↑i < DescriptiveComplexity.modeCard spec then some ((DescriptiveComplexity.modeEquiv spec).symm ⟨↑i, h⟩) else none
Instances For
Dependency graph
The next index of the enumeration; it stops at the last one.
Equations
- DescriptiveComplexity.nextIx spec i = if h : ↑i < DescriptiveComplexity.modeCard spec then ⟨↑i + 1, ⋯⟩ else i
Instances For
Dependency graph
The index the enumeration starts at.
Equations
- DescriptiveComplexity.ix0 spec = ⟨0, ⋯⟩
Instances For
Dependency graph
The index of a mode in the enumeration.
Equations
- DescriptiveComplexity.ixOf spec m = ⟨↑((DescriptiveComplexity.modeEquiv spec) m), ⋯⟩
Instances For
Dependency graph
Dependency graph
The fragments of the machine.
Equations
- One or more equations did not get rendered due to their size.
- DescriptiveComplexity.drvFam spec (DescriptiveComplexity.HeadProgram.DrvNode.pickSrc i) = DescriptiveComplexity.HeadProgram.chooseP
- DescriptiveComplexity.drvFam spec (DescriptiveComplexity.HeadProgram.DrvNode.target m) = DescriptiveComplexity.evalTgtP spec m
- DescriptiveComplexity.drvFam spec (DescriptiveComplexity.HeadProgram.DrvNode.pickCand m i) = DescriptiveComplexity.HeadProgram.chooseP
- DescriptiveComplexity.drvFam spec (DescriptiveComplexity.HeadProgram.DrvNode.commit m m') = DescriptiveComplexity.HeadProgram.moveP (DescriptiveComplexity.commitMoves spec)
- DescriptiveComplexity.drvFam spec DescriptiveComplexity.HeadProgram.DrvNode.dead = DescriptiveComplexity.HeadProgram.exitP false
Instances For
Dependency graph
The machine of a specification: the loop described in the header, as a control graph over those fragments.
Equations
- One or more equations did not get rendered due to their size.
Instances For
Dependency graph
What the fragments of the machine run.
Equations
- One or more equations did not get rendered due to their size.
Instances For
Dependency graph
Dependency graph
Dependency graph
Dependency graph
The fragments run what they are meant to.
Dependency graph
The relations the fragments run see only the two tuples.
Dependency graph
Soundness: what the machine knows #
The invariant the machine carries: at a control node, the tuple on the first
block of heads is a node of the specification reachable from a source – and, at
commit, the candidate is a step away.
Equations
- One or more equations did not get rendered due to their size.
Instances For
Dependency graph
The wiring, arc by arc.
Dependency graph
Dependency graph
Dependency graph
Dependency graph
Dependency graph
Dependency graph
Dependency graph
Dependency graph
Dependency graph
Dependency graph
Dependency graph
Dependency graph
The invariant is carried along the machine's walk.
Dependency graph
Soundness: if the machine accepts, the specification does.
Dependency graph
Completeness: the machine imitates the walk #
Putting a tuple on the first block of heads.
Instances For
Dependency graph
Putting a tuple on the second block of heads.
Equations
Instances For
Dependency graph
Dependency graph
Dependency graph
Dependency graph
Dependency graph
The chain of free choices reaches every mode.
Dependency graph
The same chain, for the candidate mode.
Dependency graph
Completeness: the machine imitates the specification's walk, node by node, unless it has already accepted on the way.
Dependency graph
The capture theorem #
The machine of a specification accepts exactly what the specification does.
Dependency graph
The capture theorem #
The capture theorem for FO(TC): a problem is definable by a single
transitive closure exactly when a two-way multi-head automaton recognizes it.
One direction is DescriptiveComplexity.tcDefinable_of_automaton – a configuration is
a node of a specification – and the other is the machine built here.
Dependency graph
NL is the class of the two-way multi-head automata: membership in
DescriptiveComplexity.NL is recognizability by such a machine.