Programs: two-way multi-head automata, written with guarded transitions #
DescriptiveComplexity.HeadAutomaton is the machine model of the logarithmic-space
level, and it is stated the way a finished machine wants to be stated: a fixed
list of tests, and a transition table indexed by every outcome those tests may
have. That presentation is exactly wrong for building a machine, where one
wants to write one transition at a time, each carrying its own guard, and to
paste machines together.
This file is the assembly language. A DescriptiveComplexity.HeadProgram is the same
model with the transitions presented individually –
- a guard, a quantifier-free formula of the head positions;
- a move for every head;
- a target: another state of the program, or one of two exits,
trueandfalse
– and two compilations back into the finished form: toAutomaton, which enables
every transition whose guard holds, and toAutomatonPri, which enables the
first one, so that the compiled table has at most one entry per reading and
DescriptiveComplexity.HeadAutomaton.IsDeterministic holds on the nose. Programs whose
guards are mutually exclusive (DescriptiveComplexity.HeadProgram.Deterministic) run the
same way under both.
What a program is proved to do #
Two exits rather than one is what makes programs composable: a fragment can be
used as a test by another fragment. The specification of a fragment is
DescriptiveComplexity.HeadProgram.Runs: a relation R x b y describing which exits
b, with which head positions y, are reachable from the entry at head
positions x. It has two halves, and they are not symmetric –
- soundness: every reachable exit satisfies
R– the fragment never lies; - completeness: every
R-related outcome is reachable up to the scratch heads, the ones a fragment is allowed to leave dirty.
The scratch heads are the point of the number m carried by Runs: heads below
m are the fragment's protected interface, heads from m on are workspace.
DescriptiveComplexity.HeadAgree and DescriptiveComplexity.HeadLocal2 say "agrees on the
interface" and "depends only on the interface".
Composition #
Everything is built from four pieces:
DescriptiveComplexity.HeadProgram.exitP– exit at once;DescriptiveComplexity.HeadProgram.leafP– test a quantifier-free formula;DescriptiveComplexity.HeadProgram.moveP– move the heads;DescriptiveComplexity.HeadProgram.wireP– the combinator: a finite family of fragments, one per node of a control graph, each node saying where to go when its fragment exitstrueand where when it exitsfalse.
wireP subsumes sequencing, branching and looping, and
DescriptiveComplexity.HeadProgram.runs_wireP reduces the runs of the assembled program
to a walk in the control graph whose steps are the runs of the fragments. Every
later construction – the formula evaluator, and the drivers that turn a
DescriptiveComplexity.TCSpec into a machine – is a control graph over fragments, and
its correctness proof is an argument about that walk, never about states.
The engine room is DescriptiveComplexity.HeadProgram.Embeds: a fragment sitting inside
a larger program, with the two lemmas that a run of the fragment is a run of the
program, and – the one that does the work – that a run of the program which
starts inside the fragment either is still inside it or has left it through one
of its exits.
Agreement on an interface #
Two head assignments agree on the first m heads: the interface a
fragment must preserve, the rest being scratch.
Equations
- DescriptiveComplexity.HeadAgree m x y = ∀ (j : Fin K), ↑j < m → x j = y j
Instances For
Dependency graph
Dependency graph
Dependency graph
Dependency graph
Agreement on more heads is agreement on fewer.
Dependency graph
A property of the heads depends only on the first m of them.
Equations
- DescriptiveComplexity.HeadLocal m P = ∀ (x y : Fin K → A), DescriptiveComplexity.HeadAgree m x y → (P x ↔ P y)
Instances For
Dependency graph
A relation between two head assignments and an exit depends only on the
first m heads of each.
Equations
- DescriptiveComplexity.HeadLocal2 m R = ∀ (x x' y y' : Fin K → A), DescriptiveComplexity.HeadAgree m x x' → DescriptiveComplexity.HeadAgree m y y' → ∀ (b : Bool), R x b y ↔ R x' b y'
Instances For
Dependency graph
Depending on fewer heads is depending on more.
Dependency graph
Guarded transitions #
A guarded transition: a quantifier-free guard on the current head positions, a move for every head, and where to go – another state, or an exit.
- guard : (L.sum FirstOrder.Language.order).Formula (Fin K)
The guard: the transition is available only where it holds.
What each head does.
Where the transition goes: a state, or an exit.
Instances For
Dependency graph
Rewiring a transition, for pasting a fragment into a larger program.
Equations
Instances For
Dependency graph
Dependency graph
Dependency graph
Dependency graph
Programs #
A program: a two-way K-head automaton with its transitions presented
one at a time, each with its own quantifier-free guard, and with two exits.
- St : Type
The states.
Finitely many states: that is what makes this a machine.
- entry : self.St
Where a run starts.
The transitions available at each state, in order of priority.
- guard_qf (s : self.St) (t : HeadTrans L K self.St) : t ∈ self.tr s → FirstOrder.Language.BoundedFormula.IsQF t.guard
The guards are quantifier-free, as the tests of a machine must be.
Instances For
Dependency graph
Where a run can be: at a state, or at one of the two exits.
Instances For
Dependency graph
A configuration: a site together with the head positions.
Instances For
Dependency graph
One step: some transition of the current state whose guard holds, with each head moving as it prescribes.
Equations
Instances For
Dependency graph
Reachability: the reflexive-transitive closure of a step.
Equations
Instances For
Dependency graph
Nothing happens at an exit: it has no transitions.
Dependency graph
A run that has reached an exit stays there.
Dependency graph
The step relation, at a state, spelled out.
Dependency graph
Taking a named transition is a step.
Dependency graph
What a fragment does #
The specification of a fragment: R x b y describes the exits reachable
from the entry at head positions x. Soundness is exact – every reachable exit
is R-related – while completeness is up to the scratch heads, those from m
on.
- sound {x : Fin K → A} {b : Bool} {y : Fin K → A} : F.Reach (Sum.inl F.entry, x) (Sum.inr b, y) → R x b y
Every reachable exit is
R-related to the entry. - complete {x : Fin K → A} {b : Bool} {y : Fin K → A} : R x b y → ∃ (y' : Fin K → A), HeadAgree m y y' ∧ F.Reach (Sum.inl F.entry, x) (Sum.inr b, y')
Every
R-related outcome is reached, up to the scratch heads.
Instances For
Dependency graph
Leaving more heads dirty is allowed: a fragment protecting m heads
protects any smaller interface.
Dependency graph
A fragment that decides a property: it exits true exactly where the
property holds, and gives the interface heads back unchanged.
Equations
Instances For
Dependency graph
Dependency graph
The relation a decider runs is local when the property is.
Dependency graph
Fragments inside programs #
Where a site of the fragment sits in the larger program.
Equations
- DescriptiveComplexity.HeadProgram.esite e xt = Sum.elim (fun (s : F.St) => Sum.inl (e s)) xt
Instances For
Dependency graph
The fragment F sits inside P at e, its exits wired to xt: the
transitions of P at an embedded state are exactly those of F, retargeted.
Equations
- F.Embeds P e xt = ∀ (s : F.St), P.tr (e s) = List.map (DescriptiveComplexity.HeadTrans.retarget (DescriptiveComplexity.HeadProgram.esite e xt)) (F.tr s)
Instances For
Dependency graph
A step of the fragment is a step of the program.
Dependency graph
A run of the fragment is a run of the program.
Dependency graph
The decomposition lemma: a run of the program that starts inside the fragment either is still inside it, or has left it through one of its exits – in which case the program's run splits at that exit.
Dependency graph
A run of the program from the fragment's entry to an exit of the program must leave the fragment through one of its own exits.
Dependency graph
Determinism #
A program is deterministic when the transitions available at a state never disagree: any two whose guards hold at the same head positions have the same target and the same moves.
Equations
- One or more equations did not get rendered due to their size.
Instances For
Dependency graph
A deterministic program has a functional step relation: at most one successor per configuration.
Dependency graph
The pieces: exiting, testing, moving #
Exit at once, with the given answer.
Equations
- One or more equations did not get rendered due to their size.
Instances For
Dependency graph
Test a quantifier-free formula: exit true where it holds and false
where it does not, without moving a head.
Equations
- One or more equations did not get rendered due to their size.
Instances For
Dependency graph
Move the heads and exit true.
Equations
Instances For
Dependency graph
Weakening what a fragment is known to run: any relation implied by R and
whose outcomes R already realizes up to the scratch heads.
Dependency graph
A flat fragment – one whose every transition out of the entry goes straight to an exit – runs exactly one step.
Dependency graph
The transition tables of the pieces #
Dependency graph
Dependency graph
Dependency graph
Dependency graph
Dependency graph
Dependency graph
Dependency graph
Dependency graph
Dependency graph
Wiring fragments into a control graph #
Where a run goes when the fragment at control node c exits with b: to
the entry of the fragment at the next control node, or out of the program.
Equations
Instances For
Dependency graph
The control graph combinator: run the fragment at the current control
node, and on its exit follow the wiring w – to another control node, or out.
Sequencing, branching and looping are all instances.
Equations
- One or more equations did not get rendered due to their size.
Instances For
Dependency graph
Each fragment sits in the assembled program at its own control node.
Dependency graph
One step of the control walk: the fragment at u.1 runs from u.2 to
some exit, which the wiring sends on to the next control node.
Equations
Instances For
Dependency graph
How the control walk leaves the program.
Equations
Instances For
Dependency graph
What an assembled program runs is the control walk: its exits are those reached by walking the control graph, each step being a run of the fragment sitting at that node. This is the lemma every later construction is proved with.
Dependency graph
An assembled program is deterministic as soon as its fragments are.
Dependency graph
Compiling a program into an automaton #
The tests a compiled program reads: the guard of each of its transitions.
Instances For
Dependency graph
The entry a transition contributes to the compiled transition table.
Instances For
Dependency graph
The transitions of a state that a reading enables, by index.
Equations
Instances For
Dependency graph
The compiled automaton. At pri := false every transition whose guard
holds is enabled – the nondeterministic reading of a program. At pri := true
only the first one is, so that the table has at most one entry per reading and
DescriptiveComplexity.HeadAutomaton.IsDeterministic holds whatever the guards are.
Equations
- One or more equations did not get rendered due to their size.
Instances For
Dependency graph
Dependency graph
Dependency graph
The step relation of a program, indexed by transitions rather than by membership: the form the compiled table has.
Dependency graph
The step relation of a compiled automaton, in terms of the enabled transitions of the program.
Dependency graph
Nothing steps out of an exit of a compiled automaton.
Dependency graph
An index is enabled exactly when its guard holds.
Dependency graph
The compiled automaton runs the program, in the nondeterministic reading.
Dependency graph
The deterministic compilation has at most one transition per reading.
Dependency graph
A deterministic program runs the same way under the deterministic compilation: taking the first enabled transition is taking the only one.
Dependency graph
A run of the program is a run of the compiled automaton, and back.
Dependency graph
A compiled program is accepted exactly when its true exit is
reachable from the entry with every head on the least element.
Dependency graph
The nondeterministic compilation accepts exactly what the program reaches.
Dependency graph
The deterministic compilation of a deterministic program accepts exactly what the program reaches.