The machine of a CNF formula #
The program half of SAT ≤ᶠᵒ[≤] NTMAccept: the states, symbols and transitions
of the machine M_φ built inside an ordered SAT instance, on the tape laid out
in DescriptiveComplexity.Problems.Machine.Tape.
The program #
guess : ⊢ → at each cell (x,U) write (x,T) or (x,F), moving right → ⊣
check c: sweep back over the cells, accumulating
flag := flag ∨ (posIn c x ∧ b) ∨ (negIn c x ∧ ¬b)
at the far marker: if flag, take the next clause and turn round;
if not, no transition exists and the run dies
accept: when the clause just checked was the last one
Two things make this small. The check is an first-order test on the source
structure – DescriptiveComplexity.SatLit – evaluated by the formula that will define
the transition relation, so no clause-width bound and no occurrence machinery
are needed and the source can be plain SAT rather than 3SAT. And the sweeps
alternate direction instead of rewinding, so a clause costs one pass and
there are no rewind states; the markers are what tell the machine a pass has
ended.
The machine is nondeterministic in exactly one place, the choice of (x,T) or
(x,F) in the guess phase. That is a deliberate design decision, and it
is what will make the ⇒ half of correctness a corollary of uniqueness rather
than a second invariant induction.
Semantics first #
Everything here is a plain predicate on tagged tuples, as
DescriptiveComplexity.SatPosn and DescriptiveComplexity.SatInp are: the machine is
assembled as a DescriptiveComplexity.TMData and reasoned about directly. Only once
its correctness is proved does the first-order transcription happen, one
realization lemma per relFormula. A transition table type-checks whatever it
says, so it has to be validated by a proof, not by elaboration.
The instance, read #
Being a clause of the CNF instance.
Equations
Instances For
Dependency graph
The variable x occurs positively in the clause c.
Equations
Instances For
Dependency graph
The variable x occurs negatively in the clause c.
Equations
Instances For
Dependency graph
The literal test: the cell x, holding the truth value v, satisfies
the clause c. This is the first-order test on the source structure that the
transition relation performs; it is the whole of the check phase.
Equations
- DescriptiveComplexity.SatLit c x v = (DescriptiveComplexity.SatPos c x ∧ v = true ∨ DescriptiveComplexity.SatNeg c x ∧ v = false)
Instances For
Dependency graph
c is the lowest clause.
Equations
- DescriptiveComplexity.SatMinCl c = (DescriptiveComplexity.SatCl c ∧ ∀ (e : A), DescriptiveComplexity.SatCl e → c ≤ e)
Instances For
Dependency graph
c is the highest clause.
Equations
- DescriptiveComplexity.SatMaxCl c = (DescriptiveComplexity.SatCl c ∧ ∀ (e : A), DescriptiveComplexity.SatCl e → e ≤ c)
Instances For
Dependency graph
c' is the clause immediately above c.
Equations
- DescriptiveComplexity.SatNextCl c c' = (DescriptiveComplexity.SatCl c ∧ DescriptiveComplexity.SatCl c' ∧ c < c' ∧ ∀ (e : A), DescriptiveComplexity.SatCl e → c < e → c' ≤ e)
Instances For
Dependency graph
The elements of the machine #
The least element of the instance, to which every constant of the machine is pinned.
Equations
Instances For
Dependency graph
Dependency graph
Dependency graph
The universe of the machine: tagged pairs.
Equations
- DescriptiveComplexity.SatV A = (DescriptiveComplexity.SatTag × (Fin 2 → A))
Instances For
Dependency graph
A constant of the machine: a tag on the pair of least elements.
Equations
- DescriptiveComplexity.cst t = (t, fun (x : Fin 2) => DescriptiveComplexity.botA)
Instances For
Dependency graph
A tag carrying one element, pinned in the second coordinate.
Equations
Instances For
Dependency graph
Symbols #
The left-marker symbol.
Equations
Instances For
Dependency graph
The right-marker symbol.
Instances For
Dependency graph
The blank symbol.
Equations
Instances For
Dependency graph
The symbol of an unassigned cell.
Instances For
Dependency graph
The symbol of a cell assigned the truth value v.
Equations
Instances For
Dependency graph
Positions #
The left-marker cell.
Equations
Instances For
Dependency graph
The cell of the element x.
Equations
Instances For
Dependency graph
The right-marker cell.
Instances For
Dependency graph
States #
The guessing state.
Equations
Instances For
Dependency graph
Checking the clause c, flag f, sweeping in direction d.
Equations
Instances For
Dependency graph
The accepting state.
Instances For
Dependency graph
The transition table #
Which tagged tuples are transitions. The payload is pinned exactly as far as the transition needs it, and the clause coordinates are required to be clauses, so that no junk element is ever a transition.
Equations
- One or more equations did not get rendered due to their size.
Instances For
Dependency graph
The state a transition applies in.
Equations
- One or more equations did not get rendered due to their size.
Instances For
Dependency graph
The symbol a transition reads.
Equations
- One or more equations did not get rendered due to their size.
Instances For
Dependency graph
The state a transition moves to. The only place the instance is consulted
is the check clause, where the new flag depends on DescriptiveComplexity.SatLit.
Equations
- One or more equations did not get rendered due to their size.
Instances For
Dependency graph
The symbol a transition writes: everything but the guess phase leaves the tape as it found it.
Equations
- One or more equations did not get rendered due to their size.
Instances For
Dependency graph
Which transitions move the head right: the guess phase always does, a check sweep goes in its own direction, and a turn – whether it takes the next clause or accepts – reverses. A turn must reverse even when accepting: it fires at a marker, and there is no position beyond one.
Equations
- One or more equations did not get rendered due to their size.
Instances For
Dependency graph
Dependency graph
Dependency graph
The machine of a CNF instance.
Equations
- One or more equations did not get rendered due to their size.
Instances For
Dependency graph
The table is a table #
Before any run is considered: each transition has exactly one destination and
symbol written, and the two places where two tags could otherwise both apply
are exclusive. A mistake in the table shows up here first, which is why these
come before the correctness proof. (Sources and symbols read need no
functionality lemma of their own: DescriptiveComplexity.satTr_unique pins the whole
transition from them.)
Dependency graph
A transition writes exactly one symbol.
Dependency graph
A transition moves to exactly one state. The only case with a choice is the
check clause, whose two branches are separated by the flag and by
DescriptiveComplexity.SatLit.
Dependency graph
The end of the guess phase is not ambiguous: an instance either has a clause to check or has none.
Dependency graph
A turn is not ambiguous: the clause just checked either has a successor or is the last one.
Dependency graph
The tag of the state a transition applies in, as a function of its own tag. Junk tags are sent to themselves; they are never transitions.
Equations
- DescriptiveComplexity.stateTag DescriptiveComplexity.SatTag.tGuessStart = DescriptiveComplexity.SatTag.qGuess
- DescriptiveComplexity.stateTag (DescriptiveComplexity.SatTag.tGuessVal b) = DescriptiveComplexity.SatTag.qGuess
- DescriptiveComplexity.stateTag DescriptiveComplexity.SatTag.tGuessEndAcc = DescriptiveComplexity.SatTag.qGuess
- DescriptiveComplexity.stateTag DescriptiveComplexity.SatTag.tGuessEndChk = DescriptiveComplexity.SatTag.qGuess
- DescriptiveComplexity.stateTag (DescriptiveComplexity.SatTag.tChk b f d) = DescriptiveComplexity.SatTag.qChk f d
- DescriptiveComplexity.stateTag (DescriptiveComplexity.SatTag.tTurnNext d) = DescriptiveComplexity.SatTag.qChk true d
- DescriptiveComplexity.stateTag (DescriptiveComplexity.SatTag.tTurnAcc d) = DescriptiveComplexity.SatTag.qChk true d
- DescriptiveComplexity.stateTag x✝ = x✝
Instances For
Dependency graph
The tag of the symbol a transition reads, as a function of its own tag.
Equations
- DescriptiveComplexity.readTag DescriptiveComplexity.SatTag.tGuessStart = DescriptiveComplexity.SatTag.sStart
- DescriptiveComplexity.readTag (DescriptiveComplexity.SatTag.tGuessVal b) = DescriptiveComplexity.SatTag.sU
- DescriptiveComplexity.readTag DescriptiveComplexity.SatTag.tGuessEndAcc = DescriptiveComplexity.SatTag.sEnd
- DescriptiveComplexity.readTag DescriptiveComplexity.SatTag.tGuessEndChk = DescriptiveComplexity.SatTag.sEnd
- DescriptiveComplexity.readTag (DescriptiveComplexity.SatTag.tChk b f d) = if b = true then DescriptiveComplexity.SatTag.sT else DescriptiveComplexity.SatTag.sF
- DescriptiveComplexity.readTag (DescriptiveComplexity.SatTag.tTurnNext d) = if d = true then DescriptiveComplexity.SatTag.sEnd else DescriptiveComplexity.SatTag.sStart
- DescriptiveComplexity.readTag (DescriptiveComplexity.SatTag.tTurnAcc d) = if d = true then DescriptiveComplexity.SatTag.sEnd else DescriptiveComplexity.SatTag.sStart
- DescriptiveComplexity.readTag x✝ = x✝
Instances For
Dependency graph
The state pins the transition's tag.
Dependency graph
The symbol read pins the transition's tag.
Dependency graph
Being the tag of a transition.
Equations
- DescriptiveComplexity.isTrTag DescriptiveComplexity.SatTag.tGuessStart = true
- DescriptiveComplexity.isTrTag (DescriptiveComplexity.SatTag.tGuessVal b) = true
- DescriptiveComplexity.isTrTag DescriptiveComplexity.SatTag.tGuessEndAcc = true
- DescriptiveComplexity.isTrTag DescriptiveComplexity.SatTag.tGuessEndChk = true
- DescriptiveComplexity.isTrTag (DescriptiveComplexity.SatTag.tChk b f d) = true
- DescriptiveComplexity.isTrTag (DescriptiveComplexity.SatTag.tTurnNext d) = true
- DescriptiveComplexity.isTrTag (DescriptiveComplexity.SatTag.tTurnAcc d) = true
- DescriptiveComplexity.isTrTag x✝ = false
Instances For
Dependency graph
The tag of a guess-phase write.
Equations
Instances For
Dependency graph
The tag ending the guess phase with no clause to check.
Equations
Instances For
Dependency graph
The tag ending the guess phase with a clause to check.
Equations
Instances For
Dependency graph
The tag turning to the next clause.
Equations
Instances For
Dependency graph
The tag accepting after the last clause.
Equations
Instances For
Dependency graph
The state and the symbol determine the transition's tag, up to the three known ambiguities: the guess itself, the end of the guess phase, and a turn. A finite check over the tags – no case analysis by hand.
Dependency graph
Two elements agree when their tag and both coordinates do.
Dependency graph
Only transitions have transition tags.
Dependency graph
Dependency graph
Dependency graph
Dependency graph
Dependency graph
Dependency graph
Equal tags force equal payloads: the state and symbol pin one coordinate,
the promises in DescriptiveComplexity.SatTr pin the other.
Dependency graph
Reading off DescriptiveComplexity.SatSrc at a guess-write tag.
Dependency graph
Reading off DescriptiveComplexity.SatRead at a guess-write tag.
Dependency graph
Reading off DescriptiveComplexity.SatSrc at a turn-to-next tag.
Dependency graph
Reading off DescriptiveComplexity.SatSrc at a turn-to-accept tag.
Dependency graph
At most one transition applies, away from the one nondeterministic
choice of the guess phase: the state and the symbol read pin the tag
(DescriptiveComplexity.tag_cases), the tag pins the payload
(DescriptiveComplexity.satTr_payload), and the three ambiguities are the guess itself
and the two exclusive branch points.
Dependency graph
The positions of the tape, concretely #
The left marker is a position.
Dependency graph
The cell of an element is a position.
Dependency graph
The right marker is a position.
Dependency graph
The tape order is reflexive.
Dependency graph
A tag strictly below another puts its tuples below all of theirs.
Dependency graph
Every tag other than the left marker's is above it.
Dependency graph
There is only one left marker.
Dependency graph
The left marker is the lowest position: the head starts there.
Dependency graph
The left marker precedes every cell.
Dependency graph
Every cell precedes the right marker.
Dependency graph
The left marker precedes the right marker.
Dependency graph
The tape order refines the tag order.
Dependency graph
Cells are ordered as their elements are. The tape order between two cells is the source order between the elements they belong to – which is what makes a sweep over the cells a walk along the instance.
Dependency graph
Only the two lowest tags are at or below a cell's.
Dependency graph
A cell is the cell of the element it carries.
Dependency graph
The head's first move. The cell of the least element follows the left
marker immediately: the guess sweep starts by stepping over ⊢.
Dependency graph
The greatest element of the instance: the last cell of the tape.
Equations
Instances For
Dependency graph
Dependency graph
Only the two highest of the bracketing tags lie between a cell's and the right marker's.
Dependency graph
There is only one right marker.
Dependency graph
The head's last move of a sweep. The right marker follows the cell of the greatest element: this is where the guess sweep stops.
Dependency graph
The machine is deterministic away from the guess. Once the transition
is pinned (DescriptiveComplexity.satTr_unique), the successor configuration is too: its
state by satDst_functional, the cell under the head by satWrite_functional,
every other cell by the frame condition, and the head itself by uniqueness of
the neighbour in the direction the transition names.
This is a deliberate design decision: with only the guess phase
branching, the ⇒ half of correctness becomes a corollary of uniqueness rather
than a second invariant induction.
Dependency graph
The intended run: the guess phase #
The tape during the guess sweep, with the head at p: the markers hold
their own symbols, a cell strictly below the head has been assigned its value
under ν, a cell at or above the head is still unassigned, and every other
element reads blank.
A tuple carrying a cell's tag but a junk second coordinate is not a position,
and the machine never visits it – but the frame condition of a step quantifies
over it all the same, so its value must not move as the head advances. Hence
the guard ∀ a, q.2 1 ≤ a: junk cells read unassigned forever, which is also
what DescriptiveComplexity.SatInp says they hold initially.
Equations
- One or more equations did not get rendered due to their size.
Instances For
Dependency graph
The configuration during the guess sweep, with the head at p.
Equations
- DescriptiveComplexity.confGuess ν p = { state := DescriptiveComplexity.stGuess, head := p, tape := DescriptiveComplexity.guessTape ν p }
Instances For
Dependency graph
The guess sweep only ever changes the cell under the head. Every other
element reads the same before and after: markers and non-cells do not depend on
the head at all, junk cells are frozen, and a real cell is below the new head
exactly when it was below the old one – by the between-condition of
DescriptiveComplexity.SuccPos in one direction and transitivity in the other.
Dependency graph
The guess sweep starts from an initial configuration: at the left
marker no cell is below the head, so every cell still reads unassigned – which
is exactly the input DescriptiveComplexity.SatInp describes.
Dependency graph
Only the three bracketing tags are at or below the right marker's.
Dependency graph
One step of the guess sweep. At the left marker the machine steps over it; at a cell it writes the guessed value and moves on; past the right marker the segment bound leaves nothing to prove.
Dependency graph
The whole guess sweep. From the left marker to the right one, the machine writes a truth value in every cell, in as many steps as there are positions strictly between the markers – plus the two markers themselves.
Dependency graph
The turn out of the guess phase, when there is a clause to check: the machine reads the right marker, takes the lowest clause with an empty flag, and turns round to sweep leftwards.
Dependency graph
The turn out of the guess phase, when the instance has no clause at all: the formula is vacuously satisfiable and the machine accepts. Without this tag the run would die and the reduction would be wrong on the empty CNF.
Dependency graph
The intended run: a check sweep #
The tape once the guess sweep has finished: every cell assigned. It does
not change again, so the frame condition of every later step is rfl.
Equations
Instances For
Dependency graph
The flag of a leftward check sweep with the head at p: some cell already
visited – that is, strictly above p – satisfies the clause c.
Equations
- One or more equations did not get rendered due to their size.
Instances For
Dependency graph
The configuration during a leftward check sweep of the clause c.
Equations
- DescriptiveComplexity.confChkL ν c p = { state := DescriptiveComplexity.stChk (DescriptiveComplexity.chkFlagL ν c p) false c, head := p, tape := DescriptiveComplexity.doneTape ν }
Instances For
Dependency graph
A check sweep starts with an empty flag: at the highest cell nothing has been visited yet.
Dependency graph
Stepping down adds exactly one literal to the flag. Moving the head
from q to the position below it brings q's own cell into view and nothing
else, because DescriptiveComplexity.SuccPos leaves no room between them. This is the
whole content of a check sweep.
Dependency graph
After the guess sweep every real cell holds its assigned value.
Dependency graph
One step of a leftward check sweep. The machine reads the cell it is
on, folds that literal into the flag, and moves one place left. Which of the
two DescriptiveComplexity.SatDst branches applies is exactly
DescriptiveComplexity.chkFlagL_succ.
Dependency graph
A whole leftward check sweep. From the highest cell down to the left
marker, the flag accumulating the literals of c satisfied along the way.
Dependency graph
The flag of a rightward check sweep with the head at p: some cell
already visited – strictly below p – satisfies c.
Equations
- One or more equations did not get rendered due to their size.
Instances For
Dependency graph
The configuration during a rightward check sweep of the clause c.
Equations
- DescriptiveComplexity.confChkR ν c p = { state := DescriptiveComplexity.stChk (DescriptiveComplexity.chkFlagR ν c p) true c, head := p, tape := DescriptiveComplexity.doneTape ν }
Instances For
Dependency graph
A rightward sweep also starts with an empty flag: nothing lies below the lowest cell.
Dependency graph
The left marker keeps its symbol throughout.
Dependency graph
The turn at the left marker, when another clause follows: the flag is set, so the machine takes the next clause, empties the flag and reverses to sweep rightwards.
Dependency graph
Stepping up adds exactly one literal to the flag – the mirror of
DescriptiveComplexity.chkFlagL_succ.
Dependency graph
One step of a rightward check sweep – the mirror of
DescriptiveComplexity.step_chkL.
Dependency graph
The right marker keeps its symbol throughout.
Dependency graph
A whole rightward check sweep – the mirror of
DescriptiveComplexity.steps_chkL.
Dependency graph
The turn at the right marker, when another clause follows – the mirror
of DescriptiveComplexity.step_turnNextL.
Dependency graph
Accepting at the left marker: the flag is set and the clause just checked was the last one.
Dependency graph
Accepting at the right marker – the mirror.
Dependency graph
A completed leftward sweep has seen every cell: its flag says exactly that some element satisfies the clause.
Dependency graph
A completed rightward sweep has seen every cell – the same statement, which is why the alternating directions never have to be reconciled inside the induction over clauses.
Dependency graph
One clause, checked end to end #
Each of these is a sweep followed by its turn. They are the step and the base
case of the induction over clauses; the induction itself only has to choose
between them. Each carries its step count, bounded by the rank of the right
marker: that is the honest per-clause cost, roughly the size of the instance,
and what lets the whole run fit the budget of
DescriptiveComplexity.TMData.Accepts.
The left marker has rank 0: it is the lowest position.
Dependency graph
The right marker sits one step above the last cell.
Dependency graph
The first cell has rank 1: it follows the left marker.
Dependency graph
Checking c leftwards and moving on to the next clause.
Dependency graph
Checking c rightwards and moving on to the next clause.
Dependency graph
Checking the last clause leftwards, and accepting.
Dependency graph
Checking the last clause rightwards, and accepting.
Dependency graph
A sweep is short. Only the left marker and the cells lie below the
right marker, so a sweep of the tape takes about as many steps as the instance
has elements – not as many as the tape has positions, which is what makes the
run fit the budget. Proved by injecting into Option A rather than by counting.
Dependency graph
Every clause but the last has a next one. The clause the machine turns
to is the least one above the current one, which is what
DescriptiveComplexity.SatNextCl asserts.
Dependency graph
Passing to the next clause removes exactly one clause from the ones still to be checked.
Dependency graph
The machine checks every remaining clause and accepts, in at most one
sweep's worth of steps per clause. Induction along the clauses from c
upwards: if c is the last one the machine accepts at the marker it reaches,
and otherwise it turns to the next clause, reversing direction – which is why
the statement carries both orientations at once.
Dependency graph
The machine is well formed, which is all of
DescriptiveComplexity.TMData.WellFormed – the order is linear, there is a position,
the input is functional and the blank is unique. Every conjunct was proved on
the tape layer, before any transition existed.
Dependency graph
Correctness, the chaining half #
A satisfying assignment makes the machine accept, within the budget.
The run is the guess sweep, the turn into the lowest clause, and one sweep per
clause; its length is at most (m + 1) · (n + 2) steps for n elements and
m clauses, which DescriptiveComplexity.sat_budget puts strictly below the number
of filler positions alone.
Dependency graph
Correctness, from an accepting run to an assignment #
By design, the machine branches only at the guess, so
an accepting run is the intended run of the assignment it wrote, and the flag
conditions along it force every clause to be satisfied. The analysis is one
induction on the length of the run, with one case per tag of the head position.
At each non-guess configuration the transition that fired is identified through
its tag – a decide over the finite tag type – and the actual step is equated
with the intended one by DescriptiveComplexity.step_functional_off_guess; at a guess
configuration the transition itself says which value was written.
In the guessing state over an unassigned cell, only a guess write can fire.
Dependency graph
In the guessing state over the right marker, only the two turns out of the guess phase can fire.
Dependency graph
In a check state over the left marker, only a leftward turn can fire, and only with the flag set.
Dependency graph
In a check state over the right marker, only a rightward turn can fire, and only with the flag set.
Dependency graph
No transition reads the blank symbol: the head never leaves the bracketed tape, so a run that somehow stood on a filler could not move.
Dependency graph
Changing the assignment anywhere but strictly below the head leaves the guess tape unchanged: only the cells already passed read it.
Dependency graph
The initial configuration is unique: the start state and the lowest position are pinned, and the initial tape is functional, so any initial configuration starts a guess run – of every assignment at once, no cell of the guess tape at the left marker reading the assignment at all.
Dependency graph
The check-phase analysis, both directions at once: an accepting run from a check configuration forces every clause from the current one upwards to be satisfied. The only live positions are the cells – where the step is pinned by determinism and the sweep continues – and the marker the sweep is headed to, where the transition that fired says the flag was set, hence the clause satisfied, and either names the next clause or certifies this one was last.
Dependency graph
The guess-phase analysis: an accepting run from a guess configuration
yields a satisfying assignment. Walking the guess sweep, the assignment is
rebuilt one cell at a time from the values the run chose to write; at the right
marker the run either accepts – no clause exists – or enters the check phase,
where DescriptiveComplexity.sat_of_chk takes over.
Dependency graph
The machine accepts exactly the satisfiable instances #
Satisfiability with a Bool-valued assignment, the form the machine
manipulates.
Dependency graph
Correctness of the machine of a CNF formula: it accepts – within the budget – exactly the satisfiable instances.