Two-way multi-head automata over a structure #
The machine model of the logarithmic-space level: a fixed finite control with
k two-way heads, each head holding an element of the universe, with no
work tape at all. This is the machine side of DescriptiveComplexity.LOGSPACE and
DescriptiveComplexity.NL, and it is deliberately not the automaton of formal
language theory.
Which automaton this is, and which it is not #
Mathlib's FirstOrder-free DFA/NFA consume a word by a one-way left fold
over an alphabet. Neither half of that fits here:
- the input is a finite structure, not a string, so using them would require serializing the instance – fixing an order and an encoding – and the theorem would be about the encoding rather than about the structure;
- they are one-way and single-head. A one-way single-head automaton over any
such encoding recognizes only regular languages. Two-wayness and the
kheads are not decoration: they are the logarithmic-space resource bound,khead positions beingk · log |A|bits of storage.
So the model here is its own structure, in the style of
DescriptiveComplexity.TMData (which likewise presents a machine as relations on a
universe rather than as strings):
- a finite set of control states, one of them initial, some of them accepting;
kheads, each holding an element of the universe; a configuration is a state together with ak-tuple of elements;- what a step reads: the truth values of a fixed finite list of
quantifier-free formulas of the head variables
(
DescriptiveComplexity.HeadAutomaton.test, withtest_qfrecording the restriction). Quantifier-freeness is what keeps this a machine: the control may compare its heads and look at the relations holding between them, and nothing else. Without that field the model would be first-order logic in disguise; - what a step does: per head,
stay, jump to the minimum or the maximum, copy another head, or step to the immediate successor or predecessor of another head (DescriptiveComplexity.HeadMove). A head at the last element moving right has no successor and the transition is simply disabled, the same convention asDescriptiveComplexity.TMData.
Nondeterminism is a list of transitions per state and reading;
DescriptiveComplexity.HeadAutomaton.IsDeterministic restricts it to at most one, which
is the machine-level counterpart of the determinization of
DescriptiveComplexity.TCSpec.det.
What is proved here, and what is not #
A configuration – a control state with a k-tuple – is a
DescriptiveComplexity.TCSpec.Node: the control is the mode and the heads are the
tuple. So an automaton compiles into a specification
(DescriptiveComplexity.HeadAutomaton.toSpec) by writing each transition as a
first-order formula, and its acceptance is the acceptance of that specification
(DescriptiveComplexity.HeadAutomaton.accepts_toSpec). Hence
DescriptiveComplexity.tcDefinable_of_automaton: a problem recognized by such an automaton is FO(TC) definable, so inDescriptiveComplexity.NL;DescriptiveComplexity.dtcDefinable_of_automaton: recognized by a deterministic one, it is FO(DTC) definable, so inDescriptiveComplexity.LOGSPACE.
This direction is the cheap one, and it is also a practical membership tool:
exhibiting an automaton is often much easier than writing a
DescriptiveComplexity.TCSpec by hand.
The converse – every FO(TC) definable problem is recognized by such an
automaton – is proved in DescriptiveComplexity.HeadCapture, on top of the
guarded-transition presentation of DescriptiveComplexity.HeadProgram and the
formula evaluator of DescriptiveComplexity.HeadEval; together with the above it
gives the capture theorem DescriptiveComplexity.tcDefinable_iff_automaton, and
DescriptiveComplexity.mem_NL_iff_automaton. The deterministic level is
DescriptiveComplexity.HeadCaptureDet, where a machine for an arbitrary FO(DTC)
definition needs more than the evaluator – it has to search where the
nondeterministic one guesses, and to bound its own walk with a step budget –
giving DescriptiveComplexity.dtcDefinable_iff_automaton and
DescriptiveComplexity.mem_LOGSPACE_iff_automaton.
Moves #
What a head may do in one step: stay where it is, jump to an end of the order, copy another head, or step to the immediate successor or predecessor of another head. All of it is definable from the order, which is what lets a transition become a first-order formula.
- stay
{k : ℕ}
: HeadMove k
Stay on the current element.
- toMin
{k : ℕ}
: HeadMove k
Jump to the least element.
- toMax
{k : ℕ}
: HeadMove k
Jump to the greatest element.
- copy
{k : ℕ}
(i : Fin k)
: HeadMove k
Copy the position of head
i. - succ
{k : ℕ}
(i : Fin k)
: HeadMove k
Move to the immediate successor of head
i(disabled at the greatest element, which is how a head runs off the end). - pred
{k : ℕ}
(i : Fin k)
: HeadMove k
Move to the immediate predecessor of head
i(disabled at the least element).
Instances For
Dependency graph
Equations
- DescriptiveComplexity.instDecidableEqHeadMove.decEq DescriptiveComplexity.HeadMove.stay DescriptiveComplexity.HeadMove.stay = isTrue ⋯
- DescriptiveComplexity.instDecidableEqHeadMove.decEq DescriptiveComplexity.HeadMove.stay DescriptiveComplexity.HeadMove.toMin = isFalse ⋯
- DescriptiveComplexity.instDecidableEqHeadMove.decEq DescriptiveComplexity.HeadMove.stay DescriptiveComplexity.HeadMove.toMax = isFalse ⋯
- DescriptiveComplexity.instDecidableEqHeadMove.decEq DescriptiveComplexity.HeadMove.stay (DescriptiveComplexity.HeadMove.copy i) = isFalse ⋯
- DescriptiveComplexity.instDecidableEqHeadMove.decEq DescriptiveComplexity.HeadMove.stay (DescriptiveComplexity.HeadMove.succ i) = isFalse ⋯
- DescriptiveComplexity.instDecidableEqHeadMove.decEq DescriptiveComplexity.HeadMove.stay (DescriptiveComplexity.HeadMove.pred i) = isFalse ⋯
- DescriptiveComplexity.instDecidableEqHeadMove.decEq DescriptiveComplexity.HeadMove.toMin DescriptiveComplexity.HeadMove.stay = isFalse ⋯
- DescriptiveComplexity.instDecidableEqHeadMove.decEq DescriptiveComplexity.HeadMove.toMin DescriptiveComplexity.HeadMove.toMin = isTrue ⋯
- DescriptiveComplexity.instDecidableEqHeadMove.decEq DescriptiveComplexity.HeadMove.toMin DescriptiveComplexity.HeadMove.toMax = isFalse ⋯
- DescriptiveComplexity.instDecidableEqHeadMove.decEq DescriptiveComplexity.HeadMove.toMin (DescriptiveComplexity.HeadMove.copy i) = isFalse ⋯
- DescriptiveComplexity.instDecidableEqHeadMove.decEq DescriptiveComplexity.HeadMove.toMin (DescriptiveComplexity.HeadMove.succ i) = isFalse ⋯
- DescriptiveComplexity.instDecidableEqHeadMove.decEq DescriptiveComplexity.HeadMove.toMin (DescriptiveComplexity.HeadMove.pred i) = isFalse ⋯
- DescriptiveComplexity.instDecidableEqHeadMove.decEq DescriptiveComplexity.HeadMove.toMax DescriptiveComplexity.HeadMove.stay = isFalse ⋯
- DescriptiveComplexity.instDecidableEqHeadMove.decEq DescriptiveComplexity.HeadMove.toMax DescriptiveComplexity.HeadMove.toMin = isFalse ⋯
- DescriptiveComplexity.instDecidableEqHeadMove.decEq DescriptiveComplexity.HeadMove.toMax DescriptiveComplexity.HeadMove.toMax = isTrue ⋯
- DescriptiveComplexity.instDecidableEqHeadMove.decEq DescriptiveComplexity.HeadMove.toMax (DescriptiveComplexity.HeadMove.copy i) = isFalse ⋯
- DescriptiveComplexity.instDecidableEqHeadMove.decEq DescriptiveComplexity.HeadMove.toMax (DescriptiveComplexity.HeadMove.succ i) = isFalse ⋯
- DescriptiveComplexity.instDecidableEqHeadMove.decEq DescriptiveComplexity.HeadMove.toMax (DescriptiveComplexity.HeadMove.pred i) = isFalse ⋯
- DescriptiveComplexity.instDecidableEqHeadMove.decEq (DescriptiveComplexity.HeadMove.copy i) DescriptiveComplexity.HeadMove.stay = isFalse ⋯
- DescriptiveComplexity.instDecidableEqHeadMove.decEq (DescriptiveComplexity.HeadMove.copy i) DescriptiveComplexity.HeadMove.toMin = isFalse ⋯
- DescriptiveComplexity.instDecidableEqHeadMove.decEq (DescriptiveComplexity.HeadMove.copy i) DescriptiveComplexity.HeadMove.toMax = isFalse ⋯
- DescriptiveComplexity.instDecidableEqHeadMove.decEq (DescriptiveComplexity.HeadMove.copy a) (DescriptiveComplexity.HeadMove.copy b) = if h : a = b then h ▸ isTrue ⋯ else isFalse ⋯
- DescriptiveComplexity.instDecidableEqHeadMove.decEq (DescriptiveComplexity.HeadMove.copy i) (DescriptiveComplexity.HeadMove.succ i_1) = isFalse ⋯
- DescriptiveComplexity.instDecidableEqHeadMove.decEq (DescriptiveComplexity.HeadMove.copy i) (DescriptiveComplexity.HeadMove.pred i_1) = isFalse ⋯
- DescriptiveComplexity.instDecidableEqHeadMove.decEq (DescriptiveComplexity.HeadMove.succ i) DescriptiveComplexity.HeadMove.stay = isFalse ⋯
- DescriptiveComplexity.instDecidableEqHeadMove.decEq (DescriptiveComplexity.HeadMove.succ i) DescriptiveComplexity.HeadMove.toMin = isFalse ⋯
- DescriptiveComplexity.instDecidableEqHeadMove.decEq (DescriptiveComplexity.HeadMove.succ i) DescriptiveComplexity.HeadMove.toMax = isFalse ⋯
- DescriptiveComplexity.instDecidableEqHeadMove.decEq (DescriptiveComplexity.HeadMove.succ i) (DescriptiveComplexity.HeadMove.copy i_1) = isFalse ⋯
- DescriptiveComplexity.instDecidableEqHeadMove.decEq (DescriptiveComplexity.HeadMove.succ a) (DescriptiveComplexity.HeadMove.succ b) = if h : a = b then h ▸ isTrue ⋯ else isFalse ⋯
- DescriptiveComplexity.instDecidableEqHeadMove.decEq (DescriptiveComplexity.HeadMove.succ i) (DescriptiveComplexity.HeadMove.pred i_1) = isFalse ⋯
- DescriptiveComplexity.instDecidableEqHeadMove.decEq (DescriptiveComplexity.HeadMove.pred i) DescriptiveComplexity.HeadMove.stay = isFalse ⋯
- DescriptiveComplexity.instDecidableEqHeadMove.decEq (DescriptiveComplexity.HeadMove.pred i) DescriptiveComplexity.HeadMove.toMin = isFalse ⋯
- DescriptiveComplexity.instDecidableEqHeadMove.decEq (DescriptiveComplexity.HeadMove.pred i) DescriptiveComplexity.HeadMove.toMax = isFalse ⋯
- DescriptiveComplexity.instDecidableEqHeadMove.decEq (DescriptiveComplexity.HeadMove.pred i) (DescriptiveComplexity.HeadMove.copy i_1) = isFalse ⋯
- DescriptiveComplexity.instDecidableEqHeadMove.decEq (DescriptiveComplexity.HeadMove.pred i) (DescriptiveComplexity.HeadMove.succ i_1) = isFalse ⋯
- DescriptiveComplexity.instDecidableEqHeadMove.decEq (DescriptiveComplexity.HeadMove.pred a) (DescriptiveComplexity.HeadMove.pred b) = if h : a = b then h ▸ isTrue ⋯ else isFalse ⋯
Instances For
Dependency graph
Dependency graph
The semantics of a move: where head j may be after it, the current heads
being x.
Equations
- DescriptiveComplexity.HeadMove.stay.Holds x j y = (y = x j)
- DescriptiveComplexity.HeadMove.toMin.Holds x j y = ∀ (b : A), y ≤ b
- DescriptiveComplexity.HeadMove.toMax.Holds x j y = ∀ (b : A), b ≤ y
- (DescriptiveComplexity.HeadMove.copy i).Holds x j y = (y = x i)
- (DescriptiveComplexity.HeadMove.succ i).Holds x j y = (x i < y ∧ ∀ (a : A), ¬(x i < a ∧ a < y))
- (DescriptiveComplexity.HeadMove.pred i).Holds x j y = (y < x i ∧ ∀ (a : A), ¬(y < a ∧ a < x i))
Instances For
Dependency graph
A move determines the new position of its head.
Dependency graph
Equality of two variables, as a formula.
Equations
Instances For
Dependency graph
A move, as a formula relating the current heads (left) to the new position
of head j (right).
Equations
- DescriptiveComplexity.HeadMove.toFormula L j DescriptiveComplexity.HeadMove.stay = DescriptiveComplexity.HeadMove.eqVarF L (Sum.inr j) (Sum.inl j)
- DescriptiveComplexity.HeadMove.toFormula L j DescriptiveComplexity.HeadMove.toMin = DescriptiveComplexity.minF (Sum.inr j)
- DescriptiveComplexity.HeadMove.toFormula L j DescriptiveComplexity.HeadMove.toMax = DescriptiveComplexity.maxF (Sum.inr j)
- DescriptiveComplexity.HeadMove.toFormula L j (DescriptiveComplexity.HeadMove.copy i) = DescriptiveComplexity.HeadMove.eqVarF L (Sum.inr j) (Sum.inl i)
- DescriptiveComplexity.HeadMove.toFormula L j (DescriptiveComplexity.HeadMove.succ i) = DescriptiveComplexity.succF (Sum.inl i) (Sum.inr j)
- DescriptiveComplexity.HeadMove.toFormula L j (DescriptiveComplexity.HeadMove.pred i) = DescriptiveComplexity.succF (Sum.inr j) (Sum.inl i)
Instances For
Dependency graph
Dependency graph
Dependency graph
The automaton #
A two-way k-head automaton over L-structures: a finite control, a
finite list of quantifier-free tests of the head positions, and, per state and
per outcome of those tests, a list of possible transitions – a new state and one
move per head. No work tape: all the storage is in the k heads.
- State : Type
The control states.
The control is finite: that is what makes this a machine.
- start : self.State
The initial state.
The accepting states.
- TestIx : Type
What the control reads at each step, indexed by a finite type.
Finitely many tests: a control that could read unboundedly many facts would not be a finite control.
- test : self.TestIx → (L.sum FirstOrder.Language.order).Formula (Fin k)
The tests: what the control sees of the current head positions.
- test_qf (i : self.TestIx) : FirstOrder.Language.BoundedFormula.IsQF (self.test i)
The tests are quantifier-free. The control may compare its heads and look at the relations holding between them, and nothing else; a quantified test would make the model first-order logic in disguise.
The transitions available in a state, at a given outcome of the tests: a new state and a move for each head. Nondeterminism is the length of this list.
Instances For
Dependency graph
A configuration: a control state together with the positions of the heads.
It is exactly a node of a DescriptiveComplexity.TCSpec.
Instances For
Dependency graph
What the control reads at a configuration: the truth values of its tests.
Instances For
Dependency graph
Dependency graph
One step of the automaton: some transition available at the current state and reading leads to the new state, each head moving as it prescribes.
Equations
Instances For
Dependency graph
The automaton accepts the structure when an accepting state is reachable from an initial configuration – the initial state with every head on the least element.
Equations
Instances For
Dependency graph
The automaton is deterministic: at most one transition per state and reading.
Instances For
Dependency graph
Compiling an automaton into a specification #
All outcomes the tests may have, as a list: the transition formula is a disjunction over them.
Instances For
Dependency graph
Dependency graph
The test indices, as a list.
Equations
Instances For
Dependency graph
Dependency graph
The formula saying that the tests come out as r does.
Equations
- One or more equations did not get rendered due to their size.
Instances For
Dependency graph
Dependency graph
The formula prescribing the moves of every head.
Equations
- DescriptiveComplexity.HeadAutomaton.movesF mvs = DescriptiveComplexity.listInf (List.map (fun (j : Fin k) => DescriptiveComplexity.HeadMove.toFormula L j (mvs j)) (List.finRange k))
Instances For
Dependency graph
Dependency graph
The transition formula of the specification, at a pair of control states: a disjunction over the possible readings and over the transitions they enable that land in the second state.
Equations
- One or more equations did not get rendered due to their size.
Instances For
Dependency graph
Dependency graph
The specification of the automaton's walk: the control states are the modes, the heads are the tuple, and the transitions are the step formulas.
Equations
- One or more equations did not get rendered due to their size.
Instances For
Dependency graph
Dependency graph
Dependency graph
Dependency graph
The walk of the specification is the run of the automaton.
Dependency graph
The compilation is correct: the specification accepts exactly the structures the automaton does.
Dependency graph
A deterministic automaton has a functional walk: its transition list holds at most one transition, and each move determines where its head lands.
Dependency graph
Membership through an automaton #
A problem recognized by a two-way multi-head automaton is FO(TC)
definable – hence in DescriptiveComplexity.NL. The configurations of the automaton
are the nodes of the specification: the control is the mode, the heads are the
tuple.
Dependency graph
A problem recognized by a deterministic two-way multi-head automaton is
FO(DTC) definable – hence in DescriptiveComplexity.LOGSPACE. Determinism of the
control is exactly what makes the walk functional, so its determinization
changes nothing.
Dependency graph
A problem recognized by a two-way multi-head automaton is in NL, the membership tool the compilation provides: exhibiting a machine is usually easier than writing a specification by hand.
Dependency graph
A problem recognized by a deterministic two-way multi-head automaton is in LOGSPACE.