Documentation

DescriptiveComplexity.Problems.Wide

The wide machine: a machine model for NEXPTIME and EXPSPACE #

Umbrella file for the wide machine – a Turing machine whose control is an ordinary part of its instance and whose tape is addressed by the subsets of that instance. An instance of size n therefore describes a machine with 2^n cells and 2^n time steps, and the two resource variants of the model live one exponential above DescriptiveComplexity.NTMAccept and DescriptiveComplexity.NTMAcceptSpace:

problemresourceclass
DescriptiveComplexity.WideAccept2^n steps, nondeterministicNEXPTIME
DescriptiveComplexity.WideAcceptSpace2^n cells, no step boundEXPSPACE
DescriptiveComplexity.DWideAcceptSpacethe same, deterministicEXPSPACE

Why this is the right shape #

DescriptiveComplexity.ATMAcceptSpace reaches EXPTIME because alternation supplies an exponential for free: the machine has polynomially many cells and it is its configuration space that is exponential. That ceiling is hard – with polynomially many cells an ordinary machine problem tops out at PSPACE and an alternating one at EXPTIME, whatever the play length – so NEXPTIME and EXPSPACE need the exponentially large index set to appear in the target problem's own semantics, which is exactly what this model does: its universe (DescriptiveComplexity.WPoint) is the power set of the instance plus the instance itself.

Read that way the model is not new. It is an ordinary machine, over the universe of an exponential expansion, and that is how the memberships are proved: DescriptiveComplexity.Problems.Wide.Expansion writes the expansion of FirstOrder.Language.wide-structures whose expanded vocabulary is FirstOrder.Language.turing, DescriptiveComplexity.Problems.Wide.Membership identifies its points with the machine's universe, and the memberships are then DescriptiveComplexity.ExpDefinable applied to DescriptiveComplexity.ntmAccept_mem_NP and DescriptiveComplexity.ntmAcceptSpace_mem_PSPACE. No resource argument occurs anywhere; the composition used is an expansion after a problem, which is the composition that exists.

What is proved here, and what is not #

Proved: the three problems are iso-invariant problems of the catalog and not vacuousDescriptiveComplexity.wideAccept_nonvacuous and its two siblings exhibit the smallest instance there is, two elements and no transitions, whose machine starts on the empty address in an accepting state – their promises reduce to three first-order conditions on the instance (DescriptiveComplexity.wideData_wellFormed_iff), all three are members of their class – the first natural members NEXPTIME and EXPSPACE have – and the machine's three head primitives are identified (DescriptiveComplexity.Problems.Wide.Increment): the head starts on the empty address, the last cell is the full one, and one step is the binary increment. That last one is what a hardness reduction will build on, since a head cannot read the digits of its own address and must instead maintain a mirror of it by incrementing. DescriptiveComplexity.Problems.Wide.Blocks then reads an address block by block, which is how a reduction will lay one out – one block per variable of the kernel, one for scratch – and proves the two facts the layout turns on: the address order is lexicographic on the blocks (DescriptiveComplexity.wmSetLt_lexRel_iff), so addresses sharing a prefix of blocks are consecutive, and the increment carries block by block (DescriptiveComplexity.wmIncr_lexRel_iff), which is the roll-over information a sweep folds by. DescriptiveComplexity.Problems.Wide.Sweep closes the layer with the primitive a program cites instead of reasoning about runs: a machine that steps at every increment of its address runs from the empty address to any address, within its clock (DescriptiveComplexity.stepsIn_of_wideSweep, DescriptiveComplexity.accepts_of_wideSweep), together with the initial configuration a reduction starts from – a start state, the head on the empty address, every cell blank (DescriptiveComplexity.isInit_wide). Both promises a reduction owes are reduced to first-order conditions on the instance – well-formedness by DescriptiveComplexity.wideData_wellFormed_iff and determinism by DescriptiveComplexity.wideData_deterministic_iff, the latter being what lets the deterministic side of EXPSPACE be proved hard and the nondeterministic one inherit it. Finally DescriptiveComplexity.Problems.Wide.Fold supplies the machine-free half of a sweep, and the reason a nondeterministic machine can evaluate a first-order kernel at all: an alternating quantifier prefix (DescriptiveComplexity.altQuantFrom) is the fold of its matrix along the lexicographic enumeration of its valuations, so k accumulator bits in the control and one matrix evaluation per step suffice (DescriptiveComplexity.foldFrom_bot, DescriptiveComplexity.foldFrom_top, DescriptiveComplexity.foldFrom_above, DescriptiveComplexity.foldFrom_carry, DescriptiveComplexity.foldFrom_below), and DescriptiveComplexity.Problems.Wide.Step packages the eight obligations of a single machine step into one right-moving (or left-moving) move and, on top of them, the shape a one-pass program has: DescriptiveComplexity.accepts_of_rightSweep – give a state and a tape per address, check one transition per increment, start blank on the empty address, end accepting. DescriptiveComplexity.Problems.Wide.Bridge joins the two halves: with the block index type taken to be Fin n – one index per variable of the kernel, as a reduction may simply choose – the blocks of an address are a valuation, and every hypothesis the fold's step rules ask for is read off DescriptiveComplexity.wmIncr_lexRel_iff (DescriptiveComplexity.foldFrom_carry_of_wmIncr and its two siblings). That the layout is definable and not merely convenient is DescriptiveComplexity.Problems.Wide.Key: the only order a first-order interpretation can put on a tagged tuple universe is DescriptiveComplexity.tagTupleLe, whose formula is DescriptiveComplexity.lexLeF, and that order is the block-major DescriptiveComplexity.lexRel (DescriptiveComplexity.Wide.tagTupleLe_iff_lexRel) – so a reduction with tag type Fin n draws an instance whose addresses decompose into one block per tag.

The two programming models #

DescriptiveComplexity.WideAccept counts its steps against the number of addresses; the two space-bounded problems have no clock, acceptance being Relation.ReflTransGen of the step relation. Programs for either may roam – sweep up, sweep back down and start again – and the difference is only whether the lengths are added up. DescriptiveComplexity.Problems.Wide.Roam is that interface, and it states every phase twice: once with a budget (DescriptiveComplexity.TMData.ReachesIn, a run of at most n steps, which composes by adding and may be raised) and once without, the second being the first with the count forgotten. A phase up (DescriptiveComplexity.reachesIn_of_wideUp, DescriptiveComplexity.reaches_of_wideUp), a phase down (DescriptiveComplexity.reachesIn_of_wideDown), the scan they are almost always used for (DescriptiveComplexity.reachesIn_scanRight, DescriptiveComplexity.reachesIn_scanLeft – hold the state, rewrite each symbol by itself, walk until the scanning transition is withheld), and the two run shapes DescriptiveComplexity.accepts_of_wideRoam and DescriptiveComplexity.acceptsSpace_of_wideRoam. Every budget is a difference of DescriptiveComplexity.wideRanks – of the number of addresses below one address and below another – so consecutive phases telescope and no phase has to know where the next one starts.

What the sum is compared against is DescriptiveComplexity.card_wideAddr: the addresses are the subsets of the instance, so a wide machine's clock is 2 ^ n exactly, and a reduction buys itself 2 ^ (|Tag| · nᵈ) steps by choosing the tags and the dimension of its interpretation. DescriptiveComplexity.accepts_of_wideRoam_lt_two_pow is the acceptance statement in that form, which is the one a program's arithmetic produces.

Roaming is what dissolves the difficulty the model is built around – a head cannot read the digits of its own address – without the lockstep mirror a one-pass program needs. DescriptiveComplexity.Problems.Wide.Marks supplies the missing half: the input channel writes at the initial-segment addresses, so a reduction that names each element in the cell that element cuts gets n distinguished cells, ordered like the elements (DescriptiveComplexity.wmSetLt_wmSeg), disjoint (DescriptiveComplexity.wmSeg_injective), missing the head's starting cell (DescriptiveComplexity.wmSetLt_empty_wmSeg) and set up at time zero (DescriptiveComplexity.isInit_wide_marks). One tape track over those n cells is an n-bit register, a register is a mirror of an address, and a roaming machine may walk to it and back as often as it likes. That is the register file a space-bounded program computes with.

What a walk asks of a file is only that its cells be strictly monotone in the address order, and that none of them be the empty address: DescriptiveComplexity.RegFile is that interface, and distinctness (DescriptiveComplexity.RegFile.injective), the converse comparison (DescriptiveComplexity.RegFile.lt_iff) and the fact that nothing is a register between two consecutive ones (DescriptiveComplexity.RegFile.gap) are all derived from it. The interface does not care what indexes the cells: DescriptiveComplexity.IxFile is it at an arbitrary ordered index, of which DescriptiveComplexity.RegFile – one register per element – is the diagonal case, and the general form is what a program too tightly clocked to lay a register out per element will need. The input channel's ladder is one such file (DescriptiveComplexity.wmSegFile) and it is the one a space-bounded program uses; but it is a geometric ruler in the top half of the tape, so a program on a clock cannot walk it twice. DescriptiveComplexity.Problems.Wide.LowFile builds the other one: the registers are n consecutive addresses (DescriptiveComplexity.segFile), so consecutive registers are consecutive cells (DescriptiveComplexity.segFile_gap) and a pass over the file costs one step per element. Where the stretch sits is the caller's choice and is not a free one – the subroutines written for the ruler assume the file lies above the data, so a program that wants them unchanged puts its own file above its data too, while DescriptiveComplexity.lowFile takes the first n nonempty addresses and lies below everything (DescriptiveComplexity.wideRank_lowCell_le). The same construction at a coarser index is DescriptiveComplexity.blkFile, one register per block and tuple (DescriptiveComplexity.Problems.Wide.BlkFile): what a program too tightly clocked to give every element a register can afford, and all a register's contents ever depend on. What such a file can still do is hold an address, which is what a random access needs: DescriptiveComplexity.ixAddr (DescriptiveComplexity.Problems.Wide.IxAddr) is the address a mark on the registers stands for, and it carries the order – comparison (DescriptiveComplexity.wmSetLe_ixAddr) and increment (DescriptiveComplexity.wmIncr_ixAddr) – as soon as the elements the registers name are upward closed. For a clocked program's file they are, the argument tags being the last ones (DescriptiveComplexity.blkIxElt_mono, DescriptiveComplexity.blkIxElt_up), so the addresses it can hold are exactly the logical ones. A program with that file writes its own names into those cells as it walks past them – it knows which is whose by DescriptiveComplexity.exists_lowCell_eq, the registers being exactly the addresses of rank between 1 and n and a rank determining its address (DescriptiveComplexity.wideRank_injective) – and that there is room for it is DescriptiveComplexity.card_lt_card_wideAddr.

Two files finish the model. DescriptiveComplexity.Problems.Wide.Tape observes that a program's tape is never a general WPoint A → WPoint A but a function of the address – the control points are not cells and keep their blank for ever – and restates the step, the scans and the initial configuration in that form (DescriptiveComplexity.wideTape, DescriptiveComplexity.step_wideTape_right, DescriptiveComplexity.reaches_scan_tape, DescriptiveComplexity.isInit_wideTape, DescriptiveComplexity.acceptsSpace_of_wideTape), which removes the frame condition, the symbol equation and the control-point case from every step of every phase. It also has the phase a program lays anything out with – the writing sweep DescriptiveComplexity.reachesIn_of_wideWrite: sweep up, writing one symbol per cell, holding the tape DescriptiveComplexity.midTape that is rewritten below the head and untouched above it. The new symbols are a parameter, so the same statement is a deterministic layout phase and a guessing one: whatever the certificate, the run that writes it exists. DescriptiveComplexity.Problems.Wide.Walk is then the phase a space-bounded machine spends its life in: stand on the cell of u, write there, scan right to the cell of the next element, repeat (DescriptiveComplexity.reaches_regStep), and the traversal of the whole file by one induction given once (DescriptiveComplexity.reaches_regWalk) – state and tape handed over as functions of the element the pointer has reached. What makes the move a single scan rather than a search is that consecutive elements mark cells with nothing marked between them (DescriptiveComplexity.not_wmSeg_between).

The first subroutine written on all of it is DescriptiveComplexity.Problems.Wide.Mirror, and it is the one every address computation goes through: incrementing the mirror (DescriptiveComplexity.reaches_mirrorIncr). Moving the working cell one to the right means adding one to the mirror, and adding one is a walk down the register file clearing the digits that are set, setting the first that is clear and stopping – which is the binary increment of DescriptiveComplexity.Problems.Wide.Increment because its least significant digit is the WMLe-greatest element. The tape is taken as a function of the mirror, with one coherence condition saying that changing a digit changes that digit's cell and nothing else, so whatever else a program keeps on its tape rides along untouched and no track discipline is fixed. The machine ends in the stopped state whatever the mirror was, so a caller reads “the increment is finished” off the state and never off the tape.

DescriptiveComplexity.Problems.Wide.Test is the read-only half: DescriptiveComplexity.reaches_fileTest walks the file asking one question of each register – do these two tracks agree here?, is this track clear here? – and comes back with the verdict in its state, the tape exactly as it found it. Both subroutines are the same shape, so what they share is settled in DescriptiveComplexity.Problems.Wide.Walk: a downward pass carries one bit in its control, and since it walks downwards that bit is a function of the suffix (DescriptiveComplexity.accState, DescriptiveComplexity.accStateAfter, with DescriptiveComplexity.accStateAfter_succ saying that leaving one register is arriving at the next one down, and DescriptiveComplexity.accStateAfter_bot_pos/_neg reading off the verdict). Getting to a register is DescriptiveComplexity.reaches_toReg and its downward twin – one scan each, stopped by the name the register carries.

Two facts about the layout keep all of this from colliding with the program's data. Every marked cell contains the WMLe-least element, and that element is the most significant digit, so the register file sits in the upper half of the tape and the addresses missing it – the working area, still exponentially many cells – lie below every register (DescriptiveComplexity.wmSetLt_wmSeg_of_not_bot). And an outer loop over that working area is DescriptiveComplexity.reachesIn_of_wideRounds and its erasure DescriptiveComplexity.reaches_of_wideRounds: the same shape as a sweep, but with a whole run between an address and its increment rather than a single step. That is what a program's loops are written with. The budgeted form charges a round w steps and the loop the product of w with the addresses crossed; the erased form charges nothing, which is what lets a space-bounded program iterate a fixed point through exponentially many stages and what a clock forbids. Its semantic twin DescriptiveComplexity.holds_of_wideRounds walks the same stretch at the same measure to say what is true when the machine gets there: a property of the addresses established at the bottom and carried across each increment holds everywhere the loop has been. The two are used together, one taking the round's machine hypothesis and the other its tape hypothesis.

One more piece of the layer belongs to no single pass and is used by all three. The passes take the tape as a function of one track and each asks the same coherence condition: changing the track at one element changes the tape at that element's cell and nowhere else. A program does not check that by hand – it reads its track through DescriptiveComplexity.regBit (the digit at a register cell, nothing anywhere else) and DescriptiveComplexity.regBit_congr is the condition, discharged once for every program and every alphabet.

The EXPSPACE reduction, begun #

Everything below lives in DescriptiveComplexity.Draw, and the modules carrying it are the Draw… ones: the name is what a reduction does with them – it draws a program for the wide machine, tags, tracks, rules, sweeps, seeks and the evaluation of a DescriptiveComplexity.StepDef – and not which problem it draws it for. The partial fixed point is the first client and the clocked machine of DescriptiveComplexity.Problems.Wide.NexRun the second, running the same drawing with the iteration removed and one field of the record left unread (DescriptiveComplexity.Draw.Data.ofKernel, step formulas ); the DrawIx… modules are the same statements at an arbitrary register file, which is what the second client needed.

DescriptiveComplexity.Problems.Wide.DrawTags fixes the universe the hardness reduction draws: a tagged tuple universe whose tags are ctrl (the states and transitions), sym (the alphabet) and the point-valued blocks arg iin that order, so the point-valued blocks are the least significant ones. Their index is an arbitrary type rather than Fin κ, and for a reason: a program's outer loop runs the head over the valuations of the fixed-point variable, so it needs one block per argument of it, while its inner loop runs a register over the valuations of the step formula's quantifier prefix, and a register is an address too, so it needs one block per quantified variable. The two counts have no reason to agree. Putting the fixed-point's arguments first makes the rest the deeper blocks, which costs nothing: a stage is written at the argument blocks only, hence is constant below them and may be read at any address with the right prefix.

Two consequences follow from the order alone, and the whole layout rests on them: the addresses a program reasons about, the valuations of the fixed-point variable, are an initial interval of the tape (DescriptiveComplexity.Draw.wmSetLe_logicalTop, joined to the machine's own order by DescriptiveComplexity.Draw.Table.wmSetLe_logicalTop_reads), which is the upper bound DescriptiveComplexity.reaches_of_wideRounds asks for; and the least element of the universe lies in the ctrl block, so the register file – every cell of which contains it – sits above every logical address, and data and registers cannot collide.

One structural note, since it is what the transition table will hang on: the subroutines above take their states as parameters, so a program with several call sites of the same subroutine gives each its own states and needs no continuation label and no dispatch. Its phase set is exactly the list of its call sites.

DescriptiveComplexity.Problems.Wide.DrawMatrix supplies the semantic half of the step the program spends its time in. The machine evaluates the matrix of its step formula atom by atom – a subroutine per atom, the accumulating assignment in the coordinates of the state – and that is correct because a quantifier-free formula is a Boolean function of its atoms: DescriptiveComplexity.Draw.realize_qfValue says its realization is DescriptiveComplexity.Draw.qfValue at the assignment that reads each atom off the structure, and DescriptiveComplexity.Draw.qfValue_congr says only the atoms of DescriptiveComplexity.Draw.qfAtoms matter. Those two are why the phase count is linear in the number of atoms rather than exponential: the machine visits the atoms once, and the final transition is a disjunction over the assignments that satisfy qfValue, a finite list a defining formula can write out. The recursion is total and the correctness is by induction on IsQF, the shape Exponential/Matrix.lean uses for the same reason.

DescriptiveComplexity.Problems.Wide.DrawGeom says which elements the states, the symbols and the transitions are: each carries a payload of c coordinates (DescriptiveComplexity.Draw.pad) with a designated element beyond it, and the kind is the tag – phase p for a state, sym for a symbol, ctrl r for a transition of the rule r. The padding is not decoration: without it an element would have n^(dd-c) spellings, and the machine's promises are that there is one start state, one blank and at most one transition per state and symbol. DescriptiveComplexity.Draw.pad_injective and the three _ne_ lemmas are the distinctness those obligations are discharged from.

DescriptiveComplexity.Problems.Wide.DrawTable is the transition table itself, and the two promises the emitted instance has to keep. A table names, rule by rule, a guard, the two phases, the payloads of the state and of the symbol on each side, and the direction; the eleven relations of FirstOrder.Language.wide are then read off it (DescriptiveComplexity.Draw.Table.Reads), and a program's whole interaction with it is two theorems – DescriptiveComplexity.Draw.Table.fire_right and DescriptiveComplexity.Draw.Table.fire_left, a rule firing with its six attributes, which is the shape every subroutine above asks for. The promises cost what the layout was built to make them cost: DescriptiveComplexity.Draw.Table.wellFormed is the order being DescriptiveComplexity.tagTupleLe plus the input and the blank being written as equations, and DescriptiveComplexity.Draw.Table.deterministic reduces to one condition on the table, DescriptiveComplexity.Draw.Table.Sep: two guarded rules that apply in the same state and read the same symbol are the same rule with the same data.

What the interpretation that emits such an instance owes, and the algebra that pays it, is DescriptiveComplexity.Problems.Wide.DrawFactor. An interpretation carries one formula per relation symbol and tag tuple, so the obligation is quantified over the instance: DescriptiveComplexity.Draw.Env bundles a finite nonempty linearly ordered structure with the two elements a reduction may designate – the order's least and greatest – and DescriptiveComplexity.Draw.URuleDefinable says of a rule, at every such environment at once, that its two phases and its direction are decided when the formula is built, that its guard is a function of the equality pattern of its data (DescriptiveComplexity.EqPattern), and that the pointer it leaves and the tracks it writes are named slot by slot by DescriptiveComplexity.SlotVal – a copy, one of the two designated elements, or the next element after a slot, which is what advancing a loop variable needs and the only source that reads the order. The atoms and connectives are there (a slot holds one, a slot holds zero, two slots hold the same element; conjunctions and disjunctions over an arbitrary index; a bit whose question is itself definable; a choice between definably separated cases), and the discharge follows the program's own shape: DescriptiveComplexity.Problems.Wide.DrawDefKit does every leaf kit – the read and write trips, the file test, the three track passes, the increment, the seek, the advance, the reset, the walk home and the two sweeps – and DescriptiveComplexity.Problems.Wide.DrawDefTower carries the statement through the combinators – the chain, the sequencer, the element loop, the tag-branched machinery and the tuple loop – each checkpoint's dispatch being the standard exit guard conjoined with the caller's question, with the caller's control update as its dstSt. Above them the program's own two guards are definable once (DescriptiveComplexity.Draw.Data.uGDefinable_exitG and uGDefinable_nameG) and the tower closes: DescriptiveComplexity.Problems.Wide.DrawDefStage the stage atom's machinery, DrawDefKind the three parameter packs (DescriptiveComplexity.Draw.UElemArgsDef, UTagArgsDef, DescriptiveComplexity.Draw.Data.UStageArgsDef – a pack's static fields, which slot a trip walks and which block it names, may not depend on the instance, and DescriptiveComplexity.Draw.UConst says so) and an atom kind's machinery, DrawDefVar the matrix and the two runs of gates, DrawDefProg one round, one variable's machinery, the evaluation's spine and the outer loop, and DrawDefAsm the assembly – uRulesDefinable_progAsm, the whole rule set, conditional only on the semantic packs meeting DescriptiveComplexity.Draw.Data.UVarArgsDef.

Two files pay the packs' recurring debts. The loop element is the one write that is not a copy (DescriptiveComplexity.Problems.Wide.DrawDefLoop): advancing it is DescriptiveComplexity.Draw.tupNext, whose coordinate at the carry is the order-successor, and DescriptiveComplexity.Draw.tupNext_apply_of_carry reads it off – below the carry a copy, at it the next element, above it the least one – with the carry itself decided by which coordinates are maximal, hence by the pattern (uStDefinable_advLvE/uStDefinable_initLvE/uGDefinable_isMaxLvE, and their narrow twins). And the control is bits throughout (DescriptiveComplexity.Problems.Wide.DrawDefCtl): every write is DescriptiveComplexity.Draw.Data.putVec or its one-slot case setCtl, and every read an existential over the levels of a slot family, so one lemma per shape settles the layer. On top of it the folds (DescriptiveComplexity.Problems.Wide.DrawDefAcc): reading one back is DescriptiveComplexity.Draw.chainFrom, a recursion down a fixed number of levels, so recursing the same way builds the pattern function (uGDefinable_chainFrom, accVerdict, sacVerdict); writing one at a carry is uStDefinable_carryVec and its two instances; and the matrix's own value at its atoms' verdicts is the same shape over the syntax (uGDefinable_qfValue, uGDefinable_postLeaf). DescriptiveComplexity.Problems.Wide.DrawDefTags settles what a gate's branch dispatches on – the decoding outright, and the total dispatch because DescriptiveComplexity.Draw.Data.defTag takes its tag from a nonemptiness of X.Tag rather than from a point, so that no instance can move it (uConst_defTag). And DescriptiveComplexity.Problems.Wide.DrawDefName settles the names a trip walks to: an encoded coordinate holds a component of the one-hot code, a payload position or the clear element, and which it holds the layout decides when the formula is built (uReadable_encTup), so a naming guard is definable as soon as its payload is (uGDefinable_nameGF_of_readable, uGDefinable_tagWitnessMatch, uGDefinable_domMatch). The same reading removes the existential over a tuple of the instance in the gates' well-shapedness question: the payload coordinates carry no condition – a witness is read straight off the cell – and every other coordinate is pinned (uGDefinable_exists_encAsgTup, uGDefinable_wellShapedG). Last, DescriptiveComplexity.Problems.Wide.DrawDefGate does a gate's four folds – started, advanced, and the two conjoining exits. Each is two or three writes nested, and what makes them definable is not new machinery but the commutations: the loop element, the sub-fold's accumulators and the sub-leaf flag are disjoint registers, so each write reads what it was given (uStDefinable_putVec_comp, uStDefinable_putLvE_comp), and the coordinate the fold carries is again a question about which coordinates are maximal (uGDefinable_tupCarry_eq). With them DescriptiveComplexity.Problems.Wide.DrawDefExp closes the discharge: an expansion atom runs the gates' machinery one exponent along, so its pack is a field-by-field check (uTagArgsDef_expArgs), and beside it the comparison and stage atoms (uElemArgsDef_cmpArgs, uStageArgsDef_stageArgs) and the two gate blocks (uTagArgsDef_gateArgs, uTagArgsDef_igateArgs). The result is DescriptiveComplexity.Draw.Data.uVarArgsDef_varArgsOf – the semantic packs the reduction computes meet their obligation – and with it uRulesDefinable_progOf: every rule of the emitted machine is written down by one formula for every instance, which is what an interpretation needs.

DescriptiveComplexity.Problems.Wide.DrawInterp begins the writing down. Where the coordinates go is fixed once: a defining formula of an n-ary relation has free variables Fin n × Fin dd, a payload occupies the first card (CtlIx ⊕ SlotIx) of an argument's, and the guard and payload formulas the definability layer hands over are relabeled onto them and nothing else (DescriptiveComplexity.Draw.guardAt, payAt). Every one of the eleven relations is then one of three shapes: a guarded padded tuple (padGuardF – a transition, an accepting state), an attribute (attrF – an element of a tag the rule names whose payload it writes from the transition's own), or a constant (constF – a tag and the all-clear tuple, the start state and the blank), each with its realization, and DescriptiveComplexity.Draw.eq_pad_iff is what splits “is this padded tuple” into the two halves a formula can say separately. The input channel's mark asks two questions the interpreted universe would otherwise have to be quantified over – is this cell the first, is it the last – and it must not be: DescriptiveComplexity.Draw.isLeast_tagTupleLe_iff and isGreatest_tagTupleLe_iff say that in the block-major order an element is least exactly when its tag is the least tag and its tuple is all-clear, and greatest exactly when its tag is the greatest and its tuple all-set – a tag decision conjoined with a shape formula.

On top of them the transitions and their five attributes are written down. DescriptiveComplexity.Draw.Data.RTag is the rule names as a type the instance does not mention and ITag the tags of the interpreted universe; srcPhOf, dstPhOf, rightOf, guardFOf, dstFOf, wrFOf (and the two rule-independent srcFOf, readFOf) are the static data DescriptiveComplexity.Draw.URuleDefinable says a rule has, extracted with their specifications; and trF, rightF, srcF, readF, dstF, writeF are the formulas, each with the realization that says it holds exactly of what DescriptiveComplexity.Draw.Table says it should.

The remaining five are the two constants (startF, blankF), the accepting states (accF, a padGuardF at the program's accepting predicate), the order – which is DescriptiveComplexity.lexLeF, the tags compared when the formula is built – and the input channel, the one with content. Its mark is DescriptiveComplexity.Draw.slotMark, a register file, and every slot of it is a tag decision, a shape formula or an equality of variables: the register flag is set, the two extremes are the lemmas above, the block flags decode the cell's tag, the name slots carry the cell's own first dd₀ coordinates and the padding flag is canonF dd0 (markSlotF, markCoordF, markF, inpF). Not one of them quantifies over the interpreted universe.

DescriptiveComplexity.Draw.Data.drawInterp is then the interpretation – one formula per relation symbol and tuple of tags – and DescriptiveComplexity.Draw.Data.reads_progFrom its point: the interpreted structure reads the program's table (DescriptiveComplexity.Draw.Table.Reads), so everything the run layer proved under that hypothesis applies to it. The eleven obligations are eleven definitional unfoldings through relMap_one/relMap_two; the only two rewrites are a rule's two phases, which srcPhOf and dstPhOf name. DescriptiveComplexity.Draw.Data.progFrom is the program at one instance – the rules the definability layer hands over with the reduction's constants, an all-clear pointer, an all-clear blank and the register file.

DescriptiveComplexity.Problems.Wide.DrawPack packs a source into that record. DescriptiveComplexity.Draw.exists_prenexPack gives the prefix normal form of every formula the program evaluates, but the shortest one, and a step definition with only nullary variables and quantifier-free packs would leave the address blocks Fin ko ⊕ₗ Fin ki empty – which is what reaches_mainB spends. So the packs are padded, not cased on: DescriptiveComplexity.Draw.PrenexPack.succ adds one vacuous innermost level, whose whole content is DescriptiveComplexity.Draw.altQuantFrom_liftLast – a prefix over a predicate that ignores its last coordinate is the prefix without it, in both polarities, because the universe is nonempty. Beside it DescriptiveComplexity.Draw.stdLayout is the encoding layout at the budget encDim X (the one-hot code first, the payload after it) and DescriptiveComplexity.Draw.Data.ofSource is the record, with Draw.Data.ki_pos for the block index.

DescriptiveComplexity.Problems.Wide.NexPack packs the source a nondeterministic program is built from into the same record. That source is a DescriptiveComplexity.NexKernel – an expansion, a block of relation variables to guess, a first-order sentence to check of the guess – which is what DescriptiveComplexity.ExpDefinable DescriptiveComplexity.NP unfolds to (DescriptiveComplexity.exists_nexKernel). Put the guessed block where the fixed-point variables go and the kernel where the output sentence goes (DescriptiveComplexity.NexKernel.toStepDef) and there is nothing left to define: the tracks a symbol carries are indexed by the block either way, DescriptiveComplexity.Draw.MatAtom classifies the atoms of a matrix over a block rather than over a fixed-point definition, so a stage atom and an atom of a guess are the same thing, and DescriptiveComplexity.Draw.StepDef.out_iff_gateMat – the output evaluation of a fixed-point program – is already the whole evaluation of a nondeterministic one (DescriptiveComplexity.Draw.Data.exists_out_iff_gateMat). The step formulas of a packed kernel are and no program reads them; their only trace is that the derived dimensions, being maxima over the variables, are the kernel's own values or an unread step's vacuous demand, whichever is larger.

DescriptiveComplexity.Problems.Wide.Double fixes the one thing the reduction cannot arrange after the fact. Every track of the machine is an element of the base universe, so the construction needs two of them, and a reduction has to be correct at one-element structures too. So the machinery is run not at the instance but at a doubled universe (DescriptiveComplexity.Draw.dblInterp): Bool × (Fin 1 → A), the false copy carrying the instance's relations and marked by the old symbol of DescriptiveComplexity.newLang, the true copy junk. It is never a singleton (DescriptiveComplexity.Draw.dblPt_ne), it is a plain one-dimensional interpretation – so composing it under the wide interpretation keeps the dimension and only multiplies the tags by Bool ^ dd – and it is exactly the extended universe of value invention, so DescriptiveComplexity.relativizeTo is what reads a formula about the instance inside it. The same file carries DescriptiveComplexity.Draw.boolEnv, the two-element environment over any relational vocabulary – the structure in which nothing holds – which is all uRulesDefinable_progOf wants an environment for: naming the gate dispatch's default tag, which is a nonemptiness the instance does not see.

DescriptiveComplexity.Problems.Wide.RelExp pays the price of that move, one sentence at a time. A sentence about the instance's ordered vocabulary expanded by a block is renamed into the extended one (DescriptiveComplexity.Draw.newBlockLHom) and relativized to the mark, and then says in the doubled universe exactly what it said in the instance (DescriptiveComplexity.Draw.realize_relOldBlock): the marked part is a substructure – the vocabularies are relational, so nothing has to be closed under anything – and it carries the instance (DescriptiveComplexity.Draw.oldSubDLEquiv), the reduct of its induced structure along the renaming being what a block assignment restricts to. The assignment travels by DescriptiveComplexity.Draw.extAssign, which holds of a tuple exactly when every entry is marked and the entries' elements satisfy it; that is the shape the support condition pins down (DescriptiveComplexity.Draw.extAssign_resAssign), and it is what makes an assignment over the doubled universe an assignment of the instance and nothing more.

DescriptiveComplexity.Problems.Wide.RelExpansion puts the two together: DescriptiveComplexity.Draw.relExp is the expansion relativized to the marked part – the same block and the same expanded vocabulary, every sentence renamed and relativized, every assignment required to be supported – so that a point of it over the doubled universe is a point of the original expansion over the instance. One tag is added, and only because FirstOrder.Language.ExpExpansion demands its domain sentence be satisfiable at every structure, including ones with no marked part at all, where a relativized sentence has nothing to be about: the tag none is the point that exists exactly there (DescriptiveComplexity.Draw.noOldSentence, DescriptiveComplexity.Draw.emptyBlocksSentence), and over a doubled universe – which always has a marked part – it contributes nothing. Discharging dom_nonempty at an arbitrary structure is what DescriptiveComplexity.Draw.MarkPart and realize_relOldMark are for: the marked part is an instance in its own right wherever there is one.

DescriptiveComplexity.Problems.Wide.RelExpMap discharges the point of all that: over a doubled universe the relativized expansion is the expansion over the instance, points and relations alike (DescriptiveComplexity.Draw.relExpMapEquiv). Three things make it work, and each was arranged for it: a doubled universe always has a marked part, so the fallback tag contributes no point (not_domHolds_none); a point's assignment is supported, so it is the extension of a unique assignment of the instance (supported_of_domHolds, extAssign_resAssign); and every sentence transports by realize_relOldBlock – the domain sentence at one copy of the block, each defining sentence at n copies, where extending commutes with replication on the nose (extAssign_replicateAssign, which is rfl).

DescriptiveComplexity.Problems.Wide.ShFinite closes the one hypothesis the run layer carries that was not yet a theorem. Every site type of the tower has a Finite instance where it is defined, and so does every leaf kit's rule type; what was missing is the tower's shapes, one instance per level (ChainSh, SeqSh, ElemSh, StageSh, TagSh, RoundSh, VarSh, EvalSh, OuterSh, then the concrete KindShSFSh). With them DescriptiveComplexity.Draw.Data.finite_RIx is Finite (Sigma …): the rule names of the emitted machine are finitely many, which is what the run layer assumed and what an interpretation needs of its tag type. Each instance has to be applied, not searched for, one level up: a shape's argument has the type of a site one level down, and instance search does not unfold the site definitions.

DescriptiveComplexity.Problems.Wide.Reduce chooses the reduction's constants and writes the machine down. The base's extremes are DescriptiveComplexity.Draw.isBot_dblPt and isTop_dblPt – the bottom of the doubled universe is the marked copy of the instance's minimum, the top the junk copy of its maximum. The dimension is DescriptiveComplexity.Draw.srcDim, one coordinate of slack beyond the encoding budget and wide enough for a rule's payload, and srcData is the record at it, with srcData_dd0_lt, srcData_payload_le and srcKIx.

That payload bound is where the one subtlety of the packing sits. It is true because no budget of a Draw.Data reads the dimension – but it is not rfl: DescriptiveComplexity.Draw.Data.nOf and its relatives are defined by a match, so their compiled matchers take the whole record as a parameter and two records differing in the dimension are opaque to each other (… .VarIx = … .VarIx is rfl; … .nOf ≍ … .nOf is not). What closes it is a congruence at every level – ofSource_nOf, ofSource_natOf, ofSource_kindDepth/kindReads/kindArgs, then ofSource_ki/naDim/natMax/eDim/nfDim/ntgDim by Finset.sup_congr – each instantiated at a constructor of the scrutinee, where the matcher reduces, giving ofSource_ctlIx and ofSource_slotIx.

On them DescriptiveComplexity.Draw.dblWideInterp is the machine written down over the doubled universe – drawInterp at the packed record, the environment boolEnv, and the accepting predicate srcAccept – and DescriptiveComplexity.Draw.wideInterp is that composed with the doubling, an interpretation of Language.wide in the instance's own ordered vocabulary whose dimension is unchanged (the doubling is one-dimensional) and whose tags only gain a Boolean per coordinate.

The correctness is then four equalities in a row. DescriptiveComplexity.Draw.srcReads says the interpreted structure reads the program's table; dwideAcceptSpace_srcEnv_iff runs the run layer at the environment srcEnv – the doubled universe with the marked copy of the instance's minimum and the junk copy of its maximum as designated elements, and with the expanded universe's order chosen to be encOrder, which makes the run layer's hordP an Iff.rfl; wideInterpEquiv carries that back along the composition; and relExpMapEquiv plus the source problem's own iso_invariant turn the fixed point into the source. The last two are the whole of DescriptiveComplexity.Draw.wideProblem_wideInterp_iff, which never asks what the machine decides – three isomorphisms, one wide problem, one source problem – so DescriptiveComplexity.Draw.dwideAcceptSpace_wideInterp_iff is that theorem with the run layer's answer supplied, and with it DescriptiveComplexity.dwideAcceptSpace_EXPSPACE_complete and DescriptiveComplexity.wideAcceptSpace_EXPSPACE_complete.

DescriptiveComplexity.Problems.Wide.DrawTracks names the coordinates. A payload is a function of a finite slot type (DescriptiveComplexity.Draw.slotPl, read back by DescriptiveComplexity.Draw.unslot) and a slot carrying a bit holds one of the two designated elements (DescriptiveComplexity.Draw.bitVal, DescriptiveComplexity.Draw.bitVal_iff), so a program never counts a coordinate and the distinctness obligations of the table are statements about named fields.

DescriptiveComplexity.Problems.Wide.DrawRules writes a program rule by rule, and splits the slots in the one way that works. A transition's data must carry both payloads – the state's and the symbol's – because neither determines the other: the symbol under the head cannot name the register the head is on, the registers being anonymous, and the state cannot name the symbol it is about to read. So the slots are Q ⊕ W, the control slots a state uses and the track slots a symbol uses (DescriptiveComplexity.Draw.stVec, DescriptiveComplexity.Draw.syVec), and two things follow. Firing a rule needs no payload arithmetic – the data is the pointer and the tracks side by side, so DescriptiveComplexity.Draw.Prog.fire_left and its rightward twin hand a program its six attributes at the elements it named. And determinism becomes a check on rules: the two payloads occupy disjoint coordinates, so DescriptiveComplexity.Draw.Table.Sep reduces to DescriptiveComplexity.Draw.Prog.sep_of – two rules that fire on the same symbol from the same state are the same rule.

The same file carries the tape a register pass runs over, DescriptiveComplexity.Draw.Prog.trackTapeAt: the track slot being walked holds the digit of the track at this cell and the others hold whatever the program keeps there. Its coherence condition – changing the track at one element moves the tape only at that element's cell – is DescriptiveComplexity.Draw.Prog.trackTape_coh, proved once for every program and every alphabet, so the three passes are entered with nothing to discharge.

DescriptiveComplexity.Problems.Wide.DrawPass runs the three register passes off the program's rules. What a program owes is DescriptiveComplexity.Draw.Prog.HasLeftin this phase, at this pointer, reading these tracks, a rule of mine goes to that phase and that pointer, writes those tracks and moves left – and nothing else: the symbols are computed for it, so it never sees DescriptiveComplexity.regBit, never writes a tape equation and never mentions FirstOrder.Language.wide. With four such families DescriptiveComplexity.Draw.Prog.reaches_fileIncr is the mirror increment, and with four DescriptiveComplexity.Draw.Prog.reaches_fileTestG (DescriptiveComplexity.Problems.Wide.DrawSub) asks one question of every register – a question the tracks decide – and brings the verdict back in the phase. One track slot carries this cell is a register, which is both what tells the acting rules from the walking one and what their separation argument is discharged from. The background of the walked track is element-valued, so the tape can carry the name marks; the mark hypotheses are bitVal equations.

The increment comes in two forms, and the difference is the one thing the anonymity of the registers costs. DescriptiveComplexity.Draw.Prog.reaches_fileIncrBlk stops in the phase of the block that carried – which is what the fold of DescriptiveComplexity.Problems.Wide.Fold has to know, and which the machine learns not by naming the register (it cannot: a state's payload holds elements of the source structure) but by reading the block off that cell's mark, one stopping rule per block. DescriptiveComplexity.Draw.Prog.reaches_fileIncr is the single-block case, the register mark serving as its own indicator, and is the form every use that only has to move an address takes.

Between passes the program writes its own data, and that is one step: DescriptiveComplexity.Draw.Prog.step_move and its leftward twin change the background at the cell the head leaves while carrying the track along untouched, so a step and a register pass compose without either knowing what the other keeps on the tape.

Navigation is there too, and it is two theorems rather than four: DescriptiveComplexity.Draw.Prog.reaches_fileToMark and its downward twin get the head to a register the caller has marked – the two ends of the file, which are the only cells that have to be recognized on sight – taking the target as a parameter rather than naming it; and DescriptiveComplexity.Draw.Prog.reaches_seek and reaches_seekBack walk the working area to the nearest cell carrying a given slot, arriving with the promise that nothing passed carried it, which is where the extremum a program cannot name is taken.

On top of the pass layer sit the pieces the EXPSPACE program's atom subroutines consume. DescriptiveComplexity.Problems.Wide.DrawScan scans to a cell recognized by an arbitrary guard on its tracks (DescriptiveComplexity.Draw.Prog.reaches_toCell and its three variants) – the navigation to a register cell whose name marks match a tuple held in the control. DescriptiveComplexity.Problems.Wide.DrawEnc encodes the points of an exponential expansion injectively as block values (DescriptiveComplexity.Draw.encPt, one membership question per bit of the assignment, DescriptiveComplexity.Draw.mem_encPt_asg), and DescriptiveComplexity.Problems.Wide.DrawRel moves an alternating quantifier prefix from the points to the block values a register enumerates, by gating the matrix polarity-correctly (DescriptiveComplexity.Draw.altQuantFrom_gateMat). DescriptiveComplexity.Problems.Wide.DrawInner restates the fold–increment join of DescriptiveComplexity.Problems.Wide.Bridge on a final segment of the blocks – the Kin half of the argument tags, where the inner loop's register enumerates the prefix valuations – and adds the control-scale fold rules along a tuple successor; DescriptiveComplexity.Problems.Wide.DrawLoop supplies the induction the control loops run on (DescriptiveComplexity.Draw.reflTransGen_of_tupLoop).

DescriptiveComplexity.Problems.Wide.DrawSpec states what the program's inner loop computes, with no machine in sight: one step of the iteration at a tuple of points is the gated prefix over block values (DescriptiveComplexity.Draw.StepDef.next_iff_gateMat), the step formula put once into prefix normal form with its free variables re-bound first (DescriptiveComplexity.Draw.PrenexPack). And DescriptiveComplexity.Problems.Wide.DrawAddr fixes the argument blocks – outer arguments first, inner prefix variables last, K := Fin ko ⊕ₗ Fin ki – proves the inner tags a final segment of the tag order (DescriptiveComplexity.Draw.kinSeg, the hypothesis pack of the inner loop's fold rules), and writes the stage dictionary: the content of a stage track at an address (DescriptiveComplexity.Draw.trackOf), reading only the blocks below the variable's arity, False off the encodings, so the all-blank initial tape is exactly stage 0. Finally, DescriptiveComplexity.Problems.Wide.DrawOrd is the order the reduction puts on the points: DescriptiveComplexity.PFPDefinable quantifies over every linear order on the expanded universe, so the reduction chooses the pullback of the binary block-value order along the encoding (DescriptiveComplexity.Draw.encOrder), making an order atom exactly the comparison of two encodings in the machine's own reading (DescriptiveComplexity.Draw.encOrder_le_iff, DescriptiveComplexity.Draw.wmSetLe_iff_setLe).

The first two concrete pieces of the program are in place. DescriptiveComplexity.Problems.Wide.DrawGate decomposes the gate the way the machine checks it (DescriptiveComplexity.Draw.isEnc_iff_parts: a tag witness, well-shapedness of every member, the domain sentence at the decoded assignment DescriptiveComplexity.Draw.decRho), and DescriptiveComplexity.Problems.Wide.DrawSlots fixes the track and control slot inventories (DescriptiveComplexity.Draw.Slot, DescriptiveComplexity.Draw.Ctl) and the mark of every register cell (DescriptiveComplexity.Draw.slotMark) – including the budgeted register naming, whose uniqueness among padded cells (DescriptiveComplexity.Draw.eq_of_slotMark_name) is what stops the navigation-by-name scans at exactly one cell. DescriptiveComplexity.Problems.Wide.DrawSub holds two corrections the interface needed once its discharge was attempted: a single-cell write is a navigation plus one step (DescriptiveComplexity.Draw.Prog.step_writeCell), not a pass – a pass's rules compute their written symbol from the tracks they read, which say nothing about an independently quantified cell – and a file test must be decided by the tracks (DescriptiveComplexity.Draw.Prog.reaches_fileTestG, the question a predicate of the symbol, tied to the per-cell question by one compatibility hypothesis). And DescriptiveComplexity.Problems.Wide.DrawInit joins the two ends of a run to the pass-layer presentation: the initial tape is the presentation walking any clear track with the empty track (DescriptiveComplexity.Draw.Prog.trackTape_initBack, the background DescriptiveComplexity.Draw.Prog.initBack being the marks over the blank), so a program starts from DescriptiveComplexity.Draw.Prog.isInit_prog with no initialization sweep, and DescriptiveComplexity.Draw.Prog.dwideAcceptSpace_prog turns an accepting run plus the separation argument into a yes-instance of DescriptiveComplexity.DWideAcceptSpace.

DescriptiveComplexity.Problems.Wide.DrawAdv is the first composite, and the round every sweep repeats: DescriptiveComplexity.Draw.Prog.reaches_fileAdvance moves the working-cell marker one address with the mirror in tow – two marker steps, the scan to the file top, the bounce turnaround (the scan cannot overshoot the maximal cell, so entering the downward pass costs two steps changing phase), the mirror increment, and the scan back to the marker. Its hypotheses are the rule families of the six phases it visits and the slot equations of its backgrounds, which is the evidence the layer's interfaces are the right ones: the walking hypotheses had to be cell-coupled and bounded to the register file – a pass whose walking rules covered every cell could never be followed by anything, the unique deterministic continuation being to walk on for ever – and the scans now hand their step suppliers the fact that a stopping cell is still ahead, which is where those bounds come from.

DescriptiveComplexity.Problems.Wide.DrawSweep is the two shapes of a plain sweep – one step per address, no register visits: DescriptiveComplexity.Draw.Prog.reaches_flagSweep asks one question per cell with the verdict in the phase (DescriptiveComplexity.sweepState – COMPARE), and DescriptiveComplexity.Draw.Prog.reaches_writeSweep rewrites each cell once, the background a function of the frontier (COPY). Their rules are cell-coupled and bounded to the stretch; the program's device for the bound is a permanent end marker planted at the top of the logical interval once, at startup, a cell of the working area being otherwise unrecognizable. And DescriptiveComplexity.Problems.Wide.DrawTrip factors the itinerary of every visit to the register file – scan up, bounce, one pass down, scan back to the marker – into DescriptiveComplexity.Draw.Prog.reaches_fileRoundTrip, the middle pass a hypothesis: the seek loop, the test rounds of a random access and the gate checks are all this composite around their respective passes.

On top of them, DescriptiveComplexity.Problems.Wide.DrawSeek is random access: DescriptiveComplexity.Draw.Prog.reaches_fileSeekTo carries the working-cell marker from the empty address to any target strictly below the register file – rounds of a turnaround step, a round trip around the file test mirror = target, and an ADVANCE, driven by DescriptiveComplexity.reaches_of_wideRounds, the mirror invariant holding by construction (the mirror track is the marker's address, the same predicate). This is what evaluates a stage atom at a computed tuple of points. And DescriptiveComplexity.Problems.Wide.DrawRead reads or writes one named register bit – the leaves of the element loops: DescriptiveComplexity.Draw.Prog.reaches_readBit_pos/_neg scan up to the cell the name guard identifies, take one branching step, and return to the marker; DescriptiveComplexity.Draw.Prog.reaches_writeBit is the same trip with the walked track updated at that cell.

One design correction closes the semantic layer (DescriptiveComplexity.Problems.Wide.DrawAcc): the sweep's control cannot carry the fold values – at a carry they are not closed under the update – so it carries the per-level contributions (DescriptiveComplexity.Draw.accCVal), from which every fold value is a finite Boolean chain (DescriptiveComplexity.Draw.foldFrom_eq_accCVal); the three update rules along an increment are DescriptiveComplexity.Draw.accCVal_congr_above, DescriptiveComplexity.Draw.accCVal_carry and DescriptiveComplexity.Draw.accCVal_reset.

Finally, DescriptiveComplexity.Problems.Wide.DrawKit is how the program instantiates its subroutines: composite kits – per composite shape, a phase inductive, a rule inductive with concrete guards, the rules function at a phase embedding, an in-shape separation lemma, and a discharge showing any program containing the kit's rules satisfies the composite's run theorem. Global determinism reduces to in-shape separation plus injective, disjoint phase embeddings. DescriptiveComplexity.Draw.ReadKit – the named-bit read – is the template (DescriptiveComplexity.Draw.ReadKit.rule, DescriptiveComplexity.Draw.ReadKit.sep, DescriptiveComplexity.Draw.ReadKit.reaches_pos/_neg), and the full inventory covers every composite: DescriptiveComplexity.Draw.WriteKit (the named-bit write), DescriptiveComplexity.Draw.TestKit (the file test in its round trip, DescriptiveComplexity.Problems.Wide.DrawTripKits), DescriptiveComplexity.Draw.ClearKit and DescriptiveComplexity.Draw.CopyKit (the whole-track writes), DescriptiveComplexity.Draw.IncrKit (the block-indexed increment, landing in the phase of the block that carried), DescriptiveComplexity.Draw.FlagSweepKit and DescriptiveComplexity.Draw.WriteSweepKit (the plain sweeps, bounded by the ltp end marker), DescriptiveComplexity.Draw.AdvKit (one round of a sweep) and DescriptiveComplexity.Draw.SeekKit (the whole random-access loop, seventeen rule families). Their disjoint guards forced three further hardenings of the pass layer, each making a demanded rule and a supplyable guard coincide: the return scans of the verdict phases are cell-coupled (DescriptiveComplexity.Draw.Prog.reaches_toCellBackC, threaded through DescriptiveComplexity.Draw.Prog.reaches_fileRoundTrip), the block-indexed increment's stopping rule takes a one-hot clause (DescriptiveComplexity.Draw.Prog.reaches_fileIncrBlk), and the seek's turnaround and walking hypotheses are stated at exactly the guards' slot conditions (DescriptiveComplexity.Draw.Prog.reaches_fileSeekTo). The program itself is then assembled from call sites (DescriptiveComplexity.Problems.Wide.DrawAsm): DescriptiveComplexity.Draw.Assembly packages per-site rule shapes with an ownership map from phases to sites, DescriptiveComplexity.Draw.Assembly.prog is the program whose rule names are the sigma, and DescriptiveComplexity.Draw.Assembly.sep its separation, via DescriptiveComplexity.Draw.sep_sigma – so each call site is built and checked in its own file, its in-shape separation the kit's sep plus its exit_disjoint. The per-atom call sites are indexed by the classified atoms of the step matrices (DescriptiveComplexity.Problems.Wide.DrawAtoms): DescriptiveComplexity.Draw.MatAtom is the kind – equality, order, expansion relation, stage atom – DescriptiveComplexity.Draw.matAtom? reads it off the syntax (total on the atoms DescriptiveComplexity.Draw.qfAtoms emits), and DescriptiveComplexity.Draw.realize_iff_qfValue_holds is the semantic capstone: a quantifier-free matrix realizes as its Boolean function at the kinds' readings, which is what the machine computes once its per-atom subroutines have filled the verdict slots. And DescriptiveComplexity.Draw.Data (DescriptiveComplexity.Problems.Wide.DrawData) bundles the reduction's data – the expansion, the definition, the prenex packs, the encoding layout with its coordinate budget – with the derived dimensions the inventories are sized by (ko, ki, the per-variable atom lists and their classified kinds), so every site file takes one record and nothing else. The kit instances at the concrete slots are in DescriptiveComplexity.Problems.Wide.DrawSites: the two plain sweeps, the seek, the advance, the block-indexed VAL increment, the clears and copies of the registers, the pattern write of startup (DescriptiveComplexity.Draw.MapKit, wrapping the generalizing composite DescriptiveComplexity.Draw.Prog.reaches_fileMapTrack), the VAL-exhausted file test, and the navigation-by-name read/write trips with their DescriptiveComplexity.Draw.Data.nameG guard. The one itinerary running down the working area – resetting the marker to the bottom before a random access – is DescriptiveComplexity.Draw.Prog.reaches_reset with its DescriptiveComplexity.Draw.ResetKit (DescriptiveComplexity.Problems.Wide.DrawReset), designed to erase and step right so the empty address needs no special case. Finally, DescriptiveComplexity.Draw.TapeSt (DescriptiveComplexity.Problems.Wide.DrawBack) is the machine's mutable state – registers per element, stage tracks and markers per cell – and DescriptiveComplexity.Draw.Data.back its presentation as the background family the pass layer walks, with the slot equations every kit discharge takes proved once over it – including the one that says what a symbol does not depend on: the four register slots read DescriptiveComplexity.bitAtOf, set at a register cell alone, so off the register file the background is blind to the mirror, the target, the saved mirror and VAL alike (DescriptiveComplexity.Draw.Data.back_congr_off_reg). Which cells those are is the caller's: back reads the permanent marks at whatever family of cells it is given, so a program that builds its own file runs the same background at it. That phase is DescriptiveComplexity.Draw.Prog.reachesIn_buildFile (DescriptiveComplexity.Problems.Wide.DrawBuild): a sweep of the file's stretch that turns the blank background into back, the mark of each cell written from the pointer, which holds the element and moves along by the order successor (DescriptiveComplexity.Draw.Prog.reachesIn_installSweep). The sweep is the stretch and no more, because off the file the background to install is already the blank (DescriptiveComplexity.Draw.Data.back_of_not_reg). The same file holds the other opening phase, DescriptiveComplexity.Draw.Prog.reachesIn_guessTracks: the same sweep with the background on both sides, the stage tracks the only thing that changes (DescriptiveComplexity.Draw.Data.back_old_congr) and the assignment a parameter – which is what makes it a guess, the run existing for every certificate. What those two phases sit inside is DescriptiveComplexity.Draw.NexPh (DescriptiveComplexity.Problems.Wide.NexOuter), the clocked program's outer layer: the file-laying sweep, a walk home, the guess, a walk home, the evaluation, and the accepting phase, with the evaluation's rules and the two sweeps' writes as parameters. It does not separate in-shape at the guess and must not – that is the program's whole nondeterminism – so what it proves instead is DescriptiveComplexity.Draw.Data.nexSep_postGuess, separation at the phases no rule returns to the guess from (DescriptiveComplexity.Draw.Data.postGuess_nexRule). What turns that into determinism where it is used is DescriptiveComplexity.Draw.Table.uniqueFrom_of_sepOn (DescriptiveComplexity.Problems.Wide.NexDet), by way of DescriptiveComplexity.Draw.Table.SepOn and DescriptiveComplexity.TMData.uniqueFrom_of_invariant: the machine is unique from any configuration whose phase the program separates at, which is all the read-off lemmas of DescriptiveComplexity.Problems.Machine.DetRun ask for. That blindness is what separates the machine's threaded states from the unthreaded ones the semantics is stated at: a VAL round rewrites SAV and TARGET and nothing else (DescriptiveComplexity.Draw.Data.ScratchEq, DescriptiveComplexity.Draw.Data.roundEndSt_eq), and every control the machinery computes is blind to that difference – the generated families read their background at the working cell alone (DescriptiveComplexity.Draw.elemFam_congr_rest and its two siblings), each atom kind's loop and exit follow (DescriptiveComplexity.Draw.Data.kindExitCtl_congr_scratch), and so do the matrix and the round (DescriptiveComplexity.Draw.Data.matFs_congr_scratch, DescriptiveComplexity.Draw.Data.matFsT_eq_matFs, DescriptiveComplexity.Draw.Data.igFs_congr_scratch, DescriptiveComplexity.Draw.Data.roundCtl_congr_scratch, DescriptiveComplexity.Draw.Data.roundCtlT_eq_roundCtl), and with them the VAL loop and one position's leg (DescriptiveComplexity.Draw.Data.varFXT_eq_roundFX, DescriptiveComplexity.Draw.Data.varFMT_eq_varFM, DescriptiveComplexity.Draw.Data.legCtlT_eq_legCtl, and at the output variable outCtlT_eq_outCtl, which is what lets outLeg_run_thread – the out machinery's run with hsav/htgt dropped, since a sweep leaves the two scratch registers wherever the last position's evaluation left them – ask for its accepting verdict in the unthreaded form the semantics reads). What the threading can change is the semantic pack – a family indexed by the scratch registers may pick different points at different registers – so the loop's bridge is stated at a pack that is one pack at the round state transported (DescriptiveComplexity.Draw.Data.semCastT, closed by DescriptiveComplexity.Draw.Data.kindSemCast_triple: the pack leaves the round state, travels to the round's own state and to the state its matrix threads, and comes back). A gated position's own pack is of that shape (DescriptiveComplexity.Draw.Data.gatedSem_eq_semCastT, its points being isEnc_of_gatedAt's choices – a function of the mirror alone), so the branched leg's stage bit is the verdict the semantics reads (DescriptiveComplexity.Draw.Data.legBitB_gatedSem), which is what DescriptiveComplexity.Draw.Data.new_last_next_at – the per-position form of new_last_next, gating being per variable – consumes; and gating at a position is «the blocks below that variable's arity encode points», both directions (DescriptiveComplexity.Draw.Data.isEnc_of_gatedAt, DescriptiveComplexity.Draw.Data.gatedAt_of_isEnc). With those, the branched spine's own reading at one address is DescriptiveComplexity.Draw.Data.new_last_trackOf_B – per variable, nothing assumed of the other variables' blocks – and along a whole sweep DescriptiveComplexity.Draw.Data.sweep_new_trackOf: below the address reached every stage track holds the dictionary of the next stage, elsewhere what the sweep started with. One scale up again, a stage's old tracks hold that stage of the iteration (DescriptiveComplexity.Draw.Data.stageSt_old, by induction through the copy-back), so the machine's convergence test is exactly the semantic one: DescriptiveComplexity.Draw.Data.stageEnd_conv_iffthis stage and the next agree at every address below the end marker – which is what DescriptiveComplexity.Draw.Data.reaches_main's hconv/hnotconv ask for, with DescriptiveComplexity.StepDef.partStage on both sides. And the dictionary is faithful: DescriptiveComplexity.Draw.assignment_ext_of_trackOf – two assignments whose tracks agree over a family of addresses carrying every tuple's own (DescriptiveComplexity.Draw.tupAddr) are equal – so the test decides the stages, not merely their readings. A tuple's address lies in the logical interval because it has no non-argument block, and strictly below its top because the top's blocks are full while an encoding's never are – every member of one carries a one-hot code, so the all-zero tuple is not one (DescriptiveComplexity.Draw.not_encPt_zeroTup, DescriptiveComplexity.Draw.wmSetLt_tupAddr_logicalTop; at a nullary variable the address is the empty one and what places it is the interval's nonemptiness, the two cases joined in DescriptiveComplexity.Draw.wmSetLt_tupAddr_logicalTop'). And the induction starts on a blank tape, which is stage 0 because the empty stage writes an empty track (DescriptiveComplexity.Draw.Data.old_trackOf_zero_of_blank). With that, DescriptiveComplexity.Draw.Data.stageEnd_conv_of_eq and stageEnd_not_conv_of_ne are the loop's two remaining hypotheses at the first stable stage, which DescriptiveComplexity.StepDef.exists_least_stable supplies from convergence – so what the machine's rounds test is the stage sequence itself. The invariant is stated over the logical interval and nowhere else, and that restriction is not a convenience: outside it an address may read a stage all the same – a tuple's address with one ctrl cell added lies above the top, non-argument tags being the most significant – while the machine's tracks there stay blank. So every dictionary hypothesis of the layer, from DescriptiveComplexity.Draw.Data.old_trackOf_stageTgtD up, is an equivalence at the addresses that are read rather than an equation of tracks; what each site owes in exchange is that the address it reads lies in the interval, and for a stage atom that address is DescriptiveComplexity.Draw.Data.stageTgtD, which is in it (DescriptiveComplexity.Draw.Data.wmSetLt_stageTgtD_logicalTop): every cell it holds was written by a copy round at that round's destination, so it carries argument cells alone (stageTgtD_arg) and each of them is a padded one (stageTgtD_isPad) – which is the general DescriptiveComplexity.Draw.wmSetLt_logicalTop_of_isPad, an address a program builds out of padded cells being strictly below a top whose blocks are full. Unlike the address a program reads from a register, this one is placed with no hypothesis on the machine's state at all.

From the initial configuration the run reaches MAIN's starting one by DescriptiveComplexity.Draw.Data.reaches_evalEntry: the startup, then two steps – step_clearMir1_exit, which leaves the marker to the right, and step_chk0_back, the checkpoint's stay rule walking back onto it – with the two presentations of the tape one term (DescriptiveComplexity.Draw.Data.trackTape_val_eq_mir). The state it arrives with is startupSt, which is what reaches_mainB asks of its st₀, and whose ltp field is what pins the end marker of the whole run.

With that the forward half of the reduction is assembled (DescriptiveComplexity.Problems.Wide.DrawYes): a partial fixed point that holds makes the emitted instance a yes-instance of DescriptiveComplexity.DWideAcceptSpace (DescriptiveComplexity.Draw.Data.dwideAcceptSpace_of_pfpHolds), the two promises coming for free – well-formedness from the layout, determinism from prog_sep – and the run being reaches_evalEntry, reaches_mainB and the output leg in sequence (DescriptiveComplexity.Draw.Data.reaches_outVerdict). Everything semantic the loop asks for is a choice made once here: the end marker is DescriptiveComplexity.Draw.logicalTop, which is what the startup writes (DescriptiveComplexity.Draw.Data.tgtTopSt_tgt – a tag has a block exactly when it is an argument tag), and which lies below every register because the least element of the universe is not an argument (tagBlk_eq_none_of_least, wmSetLt_wmSeg_of_not_bot); the VAL enumeration is exists_valEnum's chain over Fin (n + 1), whose bottom and top are 0 and Fin.last n; and the stage the machine stops at is the first stable one (DescriptiveComplexity.StepDef.exists_least_stable), whose two sides are stageEnd_conv_of_eq and stageEnd_not_conv_of_ne. The output leg (DescriptiveComplexity.Draw.Data.outLeg_verdict) is the one place a verdict is read: the output variable is nullary, so every hypothesis the machinery asks about the working address's blocks is a function on Fin 0, its pack is passSem transported by semCastT, and what is left is accVerdict_out – the machinery's bit at the empty address is the output sentence at the stage the tracks hold.

The other half is rejection, and it costs no invariant over the program's rules. The emitted machine is deterministic, so the configurations reachable from its initial one are linearly ordered (DescriptiveComplexity.TMData.reach_total), and it is enough to exhibit one run of the machine's own choosing that ends badly – provided accepting configurations are stuck. They are (DescriptiveComplexity.Draw.Data.stuck_acc), and the fact is one the assembly already carries: every rule fires from a phase its own site owns (DescriptiveComplexity.Draw.Assembly.howner), the accepting phase's site contributes no rules at all (OuterSh … .accept is Empty), so no rule has it as a source (DescriptiveComplexity.Draw.Assembly.srcPh_ne_of_isEmpty, DescriptiveComplexity.Draw.Data.srcPh_ne_acceptP) and the case analysis is on the tag of a transition rather than one case per rule. With it, DescriptiveComplexity.Problems.Machine.DetRun supplies both shapes of rejection: a run that ends badly (DescriptiveComplexity.TMData.not_acceptsSpace_of_reaches_dead) and one that never ends (DescriptiveComplexity.TMData.not_acceptsSpace_of_chain – each link of an unbounded chain costs at least one step, while a stuck configuration is reached in one fixed number of them, so a diverging fixed point is a correct rejection with no clock anywhere).

With that the converging case is settled both ways at once (DescriptiveComplexity.Problems.Wide.DrawNo). The output leg does not need its verdict as a hypothesis: it lands in the accepting phase whatever the verdict, and what the verdict decides is the bit the exit writes at the marker (DescriptiveComplexity.Draw.Data.outStA, DescriptiveComplexity.Draw.Data.outLeg_run_verdict – the current outLeg_run_thread is its idempotent special case). So DescriptiveComplexity.Draw.Data.reaches_outVerdict asks only that the iteration converge and delivers one run with an equivalence at its end: the machine's accepting predicate at the state it stops in holds exactly when the partial fixed point does. One direction is DescriptiveComplexity.Draw.Data.dwideAcceptSpace_of_pfpHolds; the other, with the dead end, is DescriptiveComplexity.Draw.Data.not_dwideAcceptSpace_of_converges.

A diverging iteration is the remaining case, and the machine's lack of a clock is what makes it correct rather than a bug: when no stage is stable every convergence test fails, so MAIN keeps sweeping and its run passes an unbounded chain of stage entries (DescriptiveComplexity.Draw.Data.transGen_stageB – each link at least one step, because the sweep leaves the head at the end-marked address and not at the empty one). A chain like that reaches no halting configuration at all (DescriptiveComplexity.TMData.not_acceptsSpace_of_chain), whence DescriptiveComplexity.Draw.Data.not_dwideAcceptSpace_of_diverges.

The three cases together are the correctness of the reduction, DescriptiveComplexity.Draw.Data.dwideAcceptSpace_iff_pfpHolds: the emitted instance is a yes-instance exactly when the partial fixed point holds. No induction over the program's rules appears anywhere in it – the machine's determinism does that work, and the only side condition is that its accepting phase is a dead end.

The transfer to the nondeterministic problem costs nothing and is written once (DescriptiveComplexity.Problems.Wide.Det): hardness travels forward along reductions, so proving the deterministic problem hard – which is what a program with a unique run naturally gives – hands DescriptiveComplexity.WideAcceptSpace its own hardness through DescriptiveComplexity.dwideAcceptSpace_fo_reduction_wideAcceptSpace. The reduction is the identity interpretation with its accepting states guarded by the determinism sentence (DescriptiveComplexity.SpaceTM.detF read at FirstOrder.Language.wide's symbols, the very sentence the polynomial-level bridge uses): a deterministic instance is copied verbatim, so the two are isomorphic; a nondeterministic one loses every accepting state, so both sides are no-instances. This is DescriptiveComplexity.Problems.Machine.SpaceDet one exponent up, and it is why PSPACE = NPSPACE needs no machine-side Savitch here either.

The outer program is assembled (DescriptiveComplexity.Problems.Wide.DrawOuter): the program factors as an outer loop – startup, the sweep's advance, the convergence test, the copy-back, the output dispatch – around a per-address evaluation that stays abstract (its phase type, site family and boundary rules are parameters, the same move Prog.reaches_fileRoundTrip makes for the middle of a trip). DescriptiveComplexity.Draw.OuterPh/OuterSite/OuterSh are the phases, sites and rule shapes; DescriptiveComplexity.Draw.Data.outerRule the rules (each site its kit's rules plus its exit rules, a sweep's first step folded into the rule that enters it); DescriptiveComplexity.Draw.Data.outerSep the in-shape separation, one case per site from the kits' sep and exit_disjoint; and DescriptiveComplexity.Draw.Data.outerAsm the DescriptiveComplexity.Draw.Assembly. The evaluation itself factors once more (DescriptiveComplexity.Problems.Wide.DrawEval): a spine of checkpoints, one per variable position (DescriptiveComplexity.Draw.EvalPh/EvalSite/EvalSh, DescriptiveComplexity.Draw.Data.evalRule/evalSep/evalHosrc), each walking back to the marker and dispatching into that variable's machinery – the last into the outer boundary pair, erasing the marker towards the advance or the post-sweep reset – around per-variable sub-machineries that stay abstract in turn. One variable's machinery (DescriptiveComplexity.Problems.Wide.DrawVar) is the next layer: the gates (abstract, verdict in a control flag), the junk path writing False directly, and the VAL loop – clear, matrix (abstract), exhaustion test, block-indexed increment – with the accumulator folds as dstSt parameters of the dispatching rules (DescriptiveComplexity.Draw.Data.varRule, DescriptiveComplexity.Draw.Data.varSep), since separation never reads dstSt; their content is fixed with the runs. The recurring checkpoint-around-stages pattern is a combinator (DescriptiveComplexity.Problems.Wide.DrawChain: DescriptiveComplexity.Draw.chainRule/chainSep/chainHosrc, dispatches given as source-phase-less DescriptiveComplexity.Draw.PreRule descriptors, so loops cost nothing), and the tuple loop – the stage atoms' bit-by-bit block copy, a read trip storing its verdict into the control and a write trip reading it back, around the loop-variable enumeration – is its first client (DescriptiveComplexity.Problems.Wide.DrawTuple: DescriptiveComplexity.Draw.tupleRule/tupleSep). The read and write trips gained a stay rule at their start phase for it: every kit is now enterable by the standard rightward dispatch off the marker. On top of them, the stage atom's machinery – the random access, the largest atom subroutine – is complete (DescriptiveComplexity.Problems.Wide.DrawStageAtom: DescriptiveComplexity.Draw.Data.stageRule/stageSep): save the mirror, clear and build the target by per-argument tuple loops chained head to tail, reset–clear–seek out, read the stage bit under the head in the seek's verdict exits, restore, and reset–clear–seek home. The remaining atom subroutines are all one shape, the element loop (DescriptiveComplexity.Problems.Wide.DrawElem: DescriptiveComplexity.Draw.elemRule/elemSep – leaf reads chained head to tail, the folds in the checkpoints' dstSt parameters, the base-structure atoms of a leaf evaluated in guards, which see the control), wrapped for the tag-dependent sentences in the tag-branched form (DescriptiveComplexity.Problems.Wide.DrawTagged: DescriptiveComplexity.Draw.tagRule/tagSep – witness reads, an n-ary branch checkpoint whose dispatches the decoding makes exclusive, one loop per tag tuple): the expansion atoms at their arity, the domain gates at one. And the sequencer (DescriptiveComplexity.Problems.Wide.DrawSeq: DescriptiveComplexity.Draw.seqRule/seqSep) chains heterogeneous stages – the matrix's kind-dependent atom machineries, the gates' per-block ones – behind checkpoints, so the machinery vocabulary of the program is now complete: what remains is instantiation and the runs. The instantiation has begun: DescriptiveComplexity.Problems.Wide.DrawRepAtoms classifies the atoms of the defining sentences' replicated-block language – base-vocabulary kinds are guards, the replicated-block kind the read leaves – with the same capstone (DescriptiveComplexity.Draw.realize_iff_qfValue_blkHolds), and DescriptiveComplexity.Problems.Wide.DrawTower assembles the phase tower: per-kind machinery types indexed by the DescriptiveComplexity.Draw.MatAtom itself (so everything reduces per constructor, the stuck kindOf application confined to the last step), the matrix and gates as sequences, one variable's machinery, the spine over the enumerated variables, and DescriptiveComplexity.Draw.Data.PF – the program's phase type – with its site mirror, the owner maps down the tower (DescriptiveComplexity.Draw.Data.sfOwn) and finiteness throughout. The rule tower has begun: DescriptiveComplexity.Problems.Wide.DrawKindRule dispatches each atom to its kind's machinery behind a parameter pack (DescriptiveComplexity.Draw.StageArgs/TagArgs/ElemArgs – the matches and control updates stay packed until the runs, while DescriptiveComplexity.Draw.Data.kindSep closes separation from the packs alone), and DescriptiveComplexity.Problems.Wide.DrawVarRule builds the matrix (DescriptiveComplexity.Draw.Data.matrixRule/matrixSep, the sequencer over the classified atoms) and the gates (DescriptiveComplexity.Draw.Data.gatesRule/gatesSep, per block a well-shapedness test whose failing exit clears the verdict flag and whose passing exit runs the tag-branched domain evaluation). Every layer also carries its ownership obligation (DescriptiveComplexity.Draw.elemHosrc and its siblings up to DescriptiveComplexity.Draw.Data.gatesHosrc): a rule fires from a phase its own site owns, which is what makes separation compose. DescriptiveComplexity.Problems.Wide.DrawProg closes the shape layer – one variable's machinery with its gates and matrix plugged in (DescriptiveComplexity.Draw.Data.varRuleF), one copy per enumerated variable and one for the output (DescriptiveComplexity.Draw.Data.smRule), the spine over them (DescriptiveComplexity.Draw.Data.evalRuleF) and the outer loop around it, delivering the program's whole rule set as one DescriptiveComplexity.Draw.Assembly (DescriptiveComplexity.Draw.Data.progAsm), whose DescriptiveComplexity.Draw.Assembly.prog and DescriptiveComplexity.Draw.Assembly.sep are the program and its determinism. The semantic content rides in one pack per variable (DescriptiveComplexity.Draw.Data.VarArgs), untouched by separation and fixed with the runs. DescriptiveComplexity.Problems.Wide.DrawRun begins the runs: the program's rules are its kits' rules (one rfl per call site, DescriptiveComplexity.Draw.Data.prog_rules_seek1 and its siblings), a rule of the assembly drives a step at its own destination data (DescriptiveComplexity.Draw.Data.prog_hasRight/prog_hasLeft), the initial tape is the empty state's background (DescriptiveComplexity.Draw.Data.initBack_eq_back, the joint between the input channel's marks and the presentation every pass walks), and the first leg is proved – DescriptiveComplexity.Draw.Data.step_start, planting the marker and the bottom mark at the empty address. The glue between legs is DescriptiveComplexity.Draw.Data.trackTape_back: a pass's presentation is the background it walks, so one leg's conclusion is the next's hypothesis whichever track each walks (DescriptiveComplexity.Draw.Data.trackTape_back_swap). With it the next legs follow: DescriptiveComplexity.Draw.Data.reaches_tgtTop (the round trip writing the logical top into TARGET) and DescriptiveComplexity.Draw.Data.reaches_seek1 (the random access taking the working cell there, the target address strictly below the file because the least element carries no argument block – DescriptiveComplexity.Draw.tagBlk_eq_none_of_least), with the two single steps that bracket a loop head (an exit steps right off the marker, the head's stay rule walks back). Then the reset takes the marker home (DescriptiveComplexity.Draw.Data.reaches_reset1, whose one hypothesis beyond the slot equations is the seek's own erasing exit – it plants the permanent ltp end marker there) and a clear empties the mirror (DescriptiveComplexity.Draw.Data.reaches_clearMir1). All of it chains into DescriptiveComplexity.Draw.Data.reaches_startup: from the initial configuration – the marks over the blank – to the entry of the per-address evaluation, with both permanent markers planted and every register where the loop expects it. The outer loop's other legs are built too: the two plain sweepsDescriptiveComplexity.Draw.Data.reaches_compare (the verdict accumulated in the phase by DescriptiveComplexity.sweepState, its per-cell question read off the stage tracks) and DescriptiveComplexity.Draw.Data.reaches_copy (the background a family indexed by the sweep's frontier: the addresses already passed hold the next stage) – the three walks home (DescriptiveComplexity.Draw.Data.reaches_home and its three instances) and one round of the outer sweep (DescriptiveComplexity.Draw.Data.reaches_sweepAdv: the marker and the mirror step on in lockstep, the erasing entry being the caller's rule, as the reset's is). Every kit the outer program instantiates has now been driven at the program level; what the loop still waits on is the per-address evaluation between two rounds. Its first brick is in DescriptiveComplexity.Problems.Wide.DrawBack: the permanent marks read back at a register cell (the existential collapses by injectivity of DescriptiveComplexity.wmSeg), and with them the navigation by nameDescriptiveComplexity.Draw.Data.nameG_cell says what the guard sees, nameG_unique that it stops at one cell, not_nameG_of_not_reg that it never stops in the working area. The other half of that instantiation is the control's dictionary, DescriptiveComplexity.Problems.Wide.DrawCtl: which DescriptiveComplexity.Draw.Ctl slot plays which role – the loop element's coordinates, the inner fold's accumulators, a sub-fold's, the atoms' verdicts, the leaf-read and tag-witness flags, the gates' verdict – with the casts through the computed budgets, their distinctness, and the two operations every semantic parameter is built from (DescriptiveComplexity.Draw.Data.ctlBit/setCtl and their read-back equations) – together with the tuple enumeration the element loops run on: DescriptiveComplexity.Draw.IsMaxTup, DescriptiveComplexity.Draw.tupNext and DescriptiveComplexity.Draw.botTup are the functions behind the relation DescriptiveComplexity.TupSucc that DescriptiveComplexity.Draw.reflTransGen_of_tupLoop indexes its rounds by, and DescriptiveComplexity.Draw.Data.readLv/putLv are how a round's tuple is read out of the control and written back.

What a leaf of those loops actually reads is fixed in DescriptiveComplexity.Problems.Wide.DrawName: an encoded tuple is canonically padded, so it lives in a cell the marks name (DescriptiveComplexity.Draw.Data.encTup_isPad); the trip's guard – the name guard at computed coordinates, DescriptiveComplexity.Draw.Data.nameGF – holds at exactly that cell (encG_iff); and the register digit found there is one membership question of the block value, hence one bit of the assignment of the point the block holds (blk_encAsgTup_iff) or its tag test (blk_encTagTup_iff). That is the whole interface between the machine and DescriptiveComplexity.Draw.encPt.

And DescriptiveComplexity.Problems.Wide.DrawPad settles the arithmetic of the inner loop's levels: the VAL register has one block per level of the longest pack and its enumeration plays all of them, so the machine plays a prefix too long at both ends – below, the levels the matrix reads off the working address; above, the levels nothing reads. Neither matters, because a level whose matrix ignores it may be skipped over a nonempty domain (DescriptiveComplexity.Draw.altQuantFrom_skip), a prefix over more coordinates than its matrix reads plays as its restriction (altQuantFrom_pad), and a matrix may be changed anywhere the walk cannot reach (altQuantFrom_congr_mat).

With them, DescriptiveComplexity.Problems.Wide.DrawLeaf says what the inner loop computes. The dictionary is fixed there: level j of a variable's pack is inner block j of the register, the free levels reading the working address's outer blocks instead (DescriptiveComplexity.Draw.Data.levelVal), and the leaf is the gated matrix at that valuation (leafP – the encodings' gates belong to the leaf, not to the loop). DescriptiveComplexity.Draw.Data.altQuantFrom_leafP is the join: the prefix of the leaf over every block, played from level 0, is DescriptiveComplexity.StepDef.next at the points the working address encodes; and foldFrom_leafP_top reads that off the accumulators at the address the loop stops at, the inner top.

DescriptiveComplexity.Problems.Wide.DrawVerdict closes that circle at the machine: DescriptiveComplexity.Draw.Data.accVerdict_next says the machinery's exit bit at a variable's position is StepDef.next at the working address's points, every abstract input of the run layer's capstone discharged from the two facts a reduction's tape maintains – the address's outer blocks encode the argument tuple, and each stage track holds the dictionary. Its sibling accVerdict_out is the same reading at the output variable, where the answer is d.out itself at the stage the tracks hold: a sentence has no free level, so the prefix starts where the machine starts it (altQuantFrom_leafP_out, over DescriptiveComplexity.Draw.StepDef.out_iff_gateMat – the nullary next_iff_gateMat) and the verdict is taken at the empty address. That is the bit the accepting dispatch reads, so it is the whole of what a yes-answer of DescriptiveComplexity.StepDef.PFPHolds has to deliver once the stage is stable.

The enumeration both of those read a register through is DescriptiveComplexity.Problems.Wide.DrawValEnum: the VAL loop starts empty, increments, and stops at the Kin top – the set of the inner-block cells – so what it consumes is an initial segment of the binary-counter order, indexed by Fin (n + 1) for the instances the run theorems ask for (DescriptiveComplexity.Draw.Data.exists_valEnum, built by exists_wmChain from repeated DescriptiveComplexity.exists_wmPred). It delivers the five facts a semantic reading needs, the last of them the one the machine could not be trusted for on its own: every register of the chain holds inner cells alone. That is not a property of the counter but of the layout – the Kin blocks are a final segment of the tag order (DescriptiveComplexity.Draw.kinSeg), and a set at or below an upward-closed one is contained in it (DescriptiveComplexity.subset_of_wmSetLe).

DescriptiveComplexity.Problems.Wide.DrawSpineSem carries that along the whole spine: the mirror, the dictionary and the markers ride every position's write (spineRide), so after the spine each variable's new cell at the address holds one step of the iteration there (new_last_next) – or nothing, at an address encoding no tuple (new_last_of_false). Read in dictionary form (new_last_trackOf, new_last_trackOf_of_junk) and iterated along the addresses by DescriptiveComplexity.holds_of_wideRounds, that is sweep_new: a sweep rewrites the tracks of exactly the addresses it has passed. The same file carries the pack's transport (kindSemCast and its content lemmas): a position's semantic pack is typed at that position's state, but DescriptiveComplexity.Draw.Data.KindSem reads the state only through the levels' register sets, so one pack built at the address's entry state serves every position. That is what makes the per-position families constructible rather than merely stateable: spineNode recurses along the positions producing state, mirror invariant and control together, and its projections satisfy exactly the cover equations evalSpine_run asks for. One scale up the same file builds the sweep's own families (sweepSW/sweepFS, sweepSW_incr/sweepFS_incr): an iteration along the addresses, because a leg's writes are local to its cell but its control accumulates – with the order on the addresses installed locally, never as an ambient instance.

The branched family – the one a sweep runs, each position taking whichever of its three legs its own gates call for – asks for no pack at all: its semantic parameter is the conditioned family DescriptiveComplexity.Draw.Data.gatedSem inhabits, a pack at every gated position of every state and every address, built from DescriptiveComplexity.Draw.Data.isEnc_of_gatedAt because a gated position's argument blocks are encodings. Supplied at the top as fun w => dt.gatedSem hzo hlin mV, it leaves no semantic assumption about a position anywhere in the run layer. What the dictionary lemmas ask of a leg is correspondingly weakened to the projection they read (DescriptiveComplexity.Draw.Data.WritesNew: its variable's cell at the marker holds its verdict, every other cell rides), which a branched leg satisfies (legStB_new, spineStOfB_writesNew) while it is not literally a postVarSt of the position's entry state – its VAL loop may normalize the two scratch registers first.

The element loops of the atom subroutines have the same anchor one scale down, DescriptiveComplexity.Problems.Wide.DrawExp: an atom of the expansion holds of a tuple of points exactly when the prefix of DescriptiveComplexity.Draw.Data.expLeaf – the Boolean value of the defining sentence's matrix, its block atoms read off the argument points' assignments and its base atoms decided by guards – is played from level 0 (relMap_iff_altQuantFrom_expLeaf, and _pad for the loop the machine actually runs, over every loop-variable slot). The classifier it reads that matrix through is now stated at an arbitrary block (DescriptiveComplexity.Draw.BlkAtom in DescriptiveComplexity.Problems.Wide.DrawRepAtoms), so the same lemmas serve the replicated block of a defining sentence and the plain block of a domain sentence.

What a clocked program is bound by #

The EXPSPACE program above roams; the NEXPTIME one (DescriptiveComplexity.wideRegAccept_NEXPTIME_complete) runs against a clock, its file handed to it by a register channel, and the clock is what its design answers to. What follows is what that cost, i.e., the questions a construction that moves the file, the atom or the index has to answer again. They are constraints on the design rather than on the proof: each rules out the arrangement that would otherwise be the obvious one.

Time is bought with tags, so an exponentially long program is affordable. The drawn universe is Tag × Aᵈ, so the clock is 2 ^ (|Tag| · nᵈ) and |Tag| is the reduction's to choose: any 2 ^ (O(nᵈ))-step program fits, and one extra tag multiplies the budget by 2 ^ (nᵈ). What the clock rules out is the iteration – a partial fixed point may run through 2 ^ (2 ^ …) stages, and no choice of tags pays for that – and not the round trip. The EXPSPACE program's shape survives it: rounds, sweeps up and back, a mirror, a seek per atom, with the inner evaluation run once over the working region costing 2 ^ (2k · nᵈ), which fits at |Tag| = 2k + 2.

A wide machine cannot name its own elements, so it cannot lay a register file. A state's payload holds one element per control flag and one per slot inside a dd-tuple, so the control takes |A| ^ #flags values with #flags < dd, while the universe has |Tag| · |A| ^ dd elements (card_ctl_lt_card_univ, not_injective_ctl_name). A file that records addresses faithfully needs one register per element and names that separate them, and a sweep can only write a name it holds in its control; widening the dimension moves both sides together. A program's file therefore comes from the input channel or not at all, which is why the clocked machine is handed one (DescriptiveComplexity.Problems.Wide.RegChannel) and lays none.

The mark ladder is a space-only device, at every scale. wmSeg x is the address {y | y ≤ x}, and DescriptiveComplexity.WMSetLe reads the wmLe-least element as the most significant digit, so the mark of the j-th element sits at address 2 ^ m − 2 ^ (m − j − 1), with m the size of the drawn universe: the file is a geometric ruler lying entirely in the top half of the tape, at 1/2, 3/4, 7/8 … Reaching the stretch carrying its top t marks costs 2 ^ m − 2 ^ (t − 1) steps out of a budget below 2 ^ m, which leaves less than one traversal of that stretch, and adding tags scales both sides, so the reading is scale invariant. A clocked run may walk such a file once, and there is no second time; that, and not roaming, is what fails to transfer from the space-bounded programs.

A working region at the bottom of the tape is free. Put the surplus tags in the most significant blocks: the addresses whose high blocks are empty are an initial stretch of 2 ^ (k · nᵈ) cells, where the head already stands, while the clock stays 2 ^ ((k + j) · nᵈ). A seek across the region costs the region, so one seek per round is affordable, and so is a full sweep of the region per round.

A clocked program has exactly one landmark, and it is where its head starts. A rule sees the control and the cell under the head and nothing else, so no rule can tell the head its address: what a program can locate is the address it starts on, the ones a fixed number of tuple roll-overs away from it (the control counts a tuple with tupNext and knows it is exhausted by IsMaxTup), and the ones it has itself marked. Positively, a stretch a clocked program can walk is one whose length is a fixed number of tuple roll-overs – the evaluation's own walks, the working region and the certificate guess all are. A file indexed by universe elements is not, so the file is indexed by (block, tuple) pairs (DescriptiveComplexity.Wide.BlkIx, Option K × (Fin dd → A)) and the laying sweep is |K| + 1 runs. That is also exactly what a background reads at a register: the block one-hot goes through tagBlk alone and the name slots are the tuple, so nothing of the tag beyond its block is ever used.

A block-indexed file can still carry a seek, and which addresses a seek passes through is why. The tag order puts ctrl and sym in the most significant blocks and the arg blocks in the least, so the logical addresses – those whose non-argument blocks are empty – are an initial interval (wmSetLe_logicalTop, nonArg_downward), and every address a seek to a logical target passes through is logical; a file with a register per (block, tuple) therefore carries every bit such a seek reads or writes. The same fact makes the working region an initial stretch and gives it its size (wideRank_lt_two_pow_logical). The index sits at the full width dd and not at dd₀: a file at dd₀ would name exactly the canonically padded elements, enough for a copy loop that walks by name but not for a mirror, whose intermediate logical addresses mark argument elements of every tuple.

The file goes above the data, and the approach is what it costs. A stage atom seeks to a dictionary entry, an entry is a logical address, and what the atom is given is that every logical address lies below every register – so the file has to be laid above the whole logical region, which is not where a machine with one landmark would naturally put it. The program pays for that in its opening: the opening step plants the marker and moves right into an approach walk (NexPh.approachP), which writes nothing and stops wherever the program likes – one more nondeterministic choice, like the guess's stop, and for the same reason, nothing on the tape telling the head where it is. The base is where it stops, the file is laid from there, and the guess then sweeps the data region below the file, entered from the marker's own neighbor (reachesIn_openingRegion, openingRegion_le_two_pow). The arrangement a reader thinks of first – leave the file at the bottom and teach the atom to seek upward past it – moves the cost from the opening, which runs once, into the seek, which every atom runs.

Every fixed-point variable must have an argument, and the reduction pads the one that does not: a nullary variable's dictionary entry is the empty address, the marker's own cell, below every stretch the machine writes and the one address an encoding can never be. The guess's range, the atom's target and the track's own shape all come down to that, and 0 < d.B.arity discharges the three at once (NexKernel.withArg is the padding, and padding a Σ₁ relation with a dummy argument costs nothing).

How a guessed relation's atoms are served. DescriptiveComplexity.Problems.Wide.Blocks serves an atom on the leading blocks with one state bit, addresses sharing a prefix of blocks being a contiguous stretch; an occurrence on any other tuple is a union of stretches, and one bit no longer keeps it consistent. The answer taken is a seek per occurrence per address – what the EXPSPACE program already does for its stage store – rather than a normal form putting every occurrence on a prefix (unproved) or one guessed copy per occurrence checked against the others (the same problem again). That is why the clocked program keeps the EXPSPACE atom machinery instead of asking the control to hold the valuation.