An expression of C computing, in a single right-to-left pass over a
bitstring, the stack depth of the word read as the preorder spelling of a
term of RankedAlphabet.Binary.binRanked, together with the scan's
liveness verdict. The two are carried in one recursive value, told apart
by its head: while no node bit has been read below depth two the value is
the depth in unary offset by one, so its head is true; once one has
been, the value is [false], which the node step reproduces, that
value's two predecessors being empty. Each bit is read once.
The recursion is a boundedRec node, so admissibility requires a bound: the
scan's value is never longer than the recursion variable by more than one bit,
which the scanner's bound child expresses at growth one. That is the side
condition of bounded recursion on notation [Cobham1965], and discharging it is
what places the scan in C rather than merely in the syntax sig describes.
The one-test on the scan's predecessor is the recognizer, correct against the
Valid predicate of the encoding. Composed with
RankedAlphabet.valid_iff_exists_spell,
isTreeSem_eq_singleton_iff_exists_spell states that an expression of C
accepts exactly the spellings of terms.
isTreeSem_eq_ite pins its value on the rejecting branch as well: the two
iff statements alone do not imply it, since a recognizer returning
[false] rather than [] on a rejected word would satisfy both while
disagreeing with isTreeSem_eq_ite there, so the correctness the latter
states is a property of the function and not only of the accepted set.
isTree_smashFree places isTree in the subalgebra SmashFree names,
[ε, I, s₀, s₁, ∗; COMP, BRN]; with [Strahm2003] Theorem 1(2), deciding
RankedAlphabet.Valid at RankedAlphabet.Binary.binRanked is computable
simultaneously in polynomial time and linear space.
Main definitions
Cobham.oneAt, Cobham.falseAt — the one-bit strings at an arbitrary
arity.
Cobham.inc — prepending true, of arity one.
Cobham.predPred — the argument with two bits dropped, of arity one.
Cobham.combFalseStep, Cobham.combTrueStep — the leaf step and the node
step of the scan, of arity one.
Cobham.comb — the stack depth and the underflow verdict in one value, of
arity one.
Cobham.eqOneInner — whether the predecessor of the argument is empty, of
arity one.
Cobham.eqOne — whether a bitstring has length one, of arity one.
Cobham.isTree — the recognizer, of arity one.
Cobham.combSem, Cobham.eqOneSem, Cobham.isTreeSem — the meaning of
the scan, the length test and the recognizer at its arity, over which
every statement of the module is stated.
Every expression is given as a raw tree …Raw and as the expression … of C
carrying admissibility. The ascription …Of at the reduced arity is given
for the scan, the length test and the recognizer, matching the interface
BellantoniCook.comb, BellantoniCook.eqOne and BellantoniCook.isTree
present, and for an expression whose reduced arity a proof reads.
Main statements
Cobham.combSem_def — the scan's meaning is the scanner's, at the two
steps.
Cobham.combSem_nil, Cobham.combSem_cons_false,
Cobham.combSem_cons_true — the scan unfolded at each constructor of the
recursion variable, with the recursive value exposed.
Cobham.combSem_eq — the scan computes RankedAlphabet.Binary.depth in
unary, offset by one, while RankedAlphabet.Binary.ok holds, and [false]
once it has failed.
Cobham.length_combSem_le — the recursion bound scan asks for, which
comb, combOf and combSem_eq_eval each pass to the scanner.
Cobham.combSem_eq_eval, Cobham.isTreeSem_eq_eval — the meaning read at
the raw tree is the meaning the expression of C carries.
Cobham.eqOneSem_env — the one-test at an arbitrary environment is the
test at the canonical one.
Cobham.eqOneSem_eq — eqOne accepts exactly the bitstrings of length
one.
Cobham.isTreeSem_apply — one step of the recognizer: the one-test on
the scan's predecessor.
Cobham.isTreeSem_eq_ite — the recognizer's value on both branches:
[true] on a word binRanked's scan accepts and [] on every other.
Cobham.isTreeSem_eq_singleton_iff_valid — isTree accepts exactly the
words binRanked's scan accepts.
Cobham.isTreeSem_eq_singleton_iff_exists_spell — equivalently, exactly
the spellings of binRanked's terms.
Cobham.isTree_smashFree — the recognizer lies in the subalgebra
SmashFree names.
Implementation notes
Each raw tree is named apart from the expression built on it because instance
search finds Decidable (sig.WValid w) when w is a constant but not when it
is a literal WType.mk application, so decide discharges admissibility only
of a named tree. oneAtRaw and falseAtRaw carry a free arity, at which
decide does not apply; their admissibility is the pair of an
Unit ⊕ Fin m case analysis and the funext that the index condition asks
for. The admissibility of an expression embedding pred or cond reuses that
expression's own component rather than repeating its proof.
combSem is the meaning read at the raw tree rather than at comb.
Cobham.eval asks only for admissibility as a sig-tree, not for the
recursion bound, so the scan is characterized by combSem_eq before the
expression carrying that bound exists. The bound is then that characterization
together with RankedAlphabet.Binary.depth_le_length: the value is [false],
of length one, or the depth in unary offset by one, and the depth never
exceeds the word length, while the scanner's bound child, at growth one,
returns one bit more than the recursion variable. combSem is the scanner's
meaning at its arity, and combSem_eq_eval reads it back through C.eval, as
isTreeSem_eq_eval does for the recognizer.
That bound is a bound on the value combSem produces at each step, not a
bound on the cost of evaluating the expression that computes it: nothing in
this module measures a number of reduction steps or an amount of space
consumed while doing so. isTree_smashFree states only that isTree avoids
the smash generator; the polynomial-time, linear-space reading of that
membership is [Strahm2003] Theorem 1(2), cited and not reproved here.
cond and pred are boundedRec nodes in this algebra rather than
generators, so a step's meaning reduces only once the value it scrutinizes is
in constructor form: combSem_cons_false and combSem_cons_true are
therefore not definitional. Each is a corollary of scanSem_cons, proved by
rewriting to the step's own application at the recursive value, generalizing
that value, and matching on it. The node step's guard drops two bits through
two pred nodes, each of which peels a bit only at a literal, so the match
reaches the fourth constructor layer of the value.
combSem names the meaning at the reduced arity, so that rewriting under it
type-checks. A meaning taken through the Sigma projection instead has a type
headed by that projection rather than by an arrow, and rw under it fails as
not type-correct at implicit transparency.
eqOne and isTree are comp compositions of pred, cond and comb,
carrying no boundedRec node of their own, so each admissibility obligation
is discharged by the anonymous constructor pairing the node's own condition,
vacuous at a comp, with a case analysis over its children, reusing the
embedded subexpression's own RecBounded component rather than repeating its
proof. Unlike a primitive predecessor shape, pred here is itself a
boundedRec node (predRaw), so its value on the scan's result does not
reduce on a symbolic word: isTreeSem_apply is proved by rewriting to the
composition's own application, generalizing the scan's value, and matching
on it, rather than by rfl.
The meanings this module reads at a raw tree are taken through Cobham.semAt,
which names the composite of fst_eval with the tree's arity equation once
rather than spelling it at each site.
References
[Cobham1965]
[Strahm2003]
Tags
Cobham, bounded recursion on notation, binary tree, preorder, stack depth,
smash-free, polynomial time, linear space
@[`@[expose]` has no effect outside a `module` fileexpose]defoneAtRaw(n:ℕ):sig.toPFunctor.W:=WType.mk(.compn1)fund↦matchdwith|.inl()=>WType.mk(.succtrue)Fin.elim0|.inr_=>zeroAtRawn
The one-bit string [true] as an expression of arity n.
@[`@[expose]` has no effect outside a `module` fileexpose]defoneAt(n:ℕ):C:=⟨⟨oneAtRawn,⟨fund↦matchdwith|.inl()=>⟨func↦c.elim0,funextfunc↦c.elim0⟩|.inr_=>(zeroAtn).1.2,funextfund↦matchdwith|.inl()=>rfl|.inr_=>rfl⟩⟩,⟨trivial,fund↦matchdwith|.inl()=>⟨trivial,func↦c.elim0⟩|.inr_=>(zeroAtn).2⟩⟩
oneAt n at its declared arity.
@[`@[expose]` has no effect outside a `module` fileexpose]defoneAtOf(n:ℕ):COfn:=⟨oneAtn,rfl⟩
The one-bit string [false] at an arbitrary arity.
@[`@[expose]` has no effect outside a `module` fileexpose]deffalseAtRaw(n:ℕ):sig.toPFunctor.W:=WType.mk(.compn1)fund↦matchdwith|.inl()=>WType.mk(.succfalse)Fin.elim0|.inr_=>zeroAtRawn
The one-bit string [false] as an expression of arity n.
@[`@[expose]` has no effect outside a `module` fileexpose]deffalseAt(n:ℕ):C:=⟨⟨falseAtRawn,⟨fund↦matchdwith|.inl()=>⟨func↦c.elim0,funextfunc↦c.elim0⟩|.inr_=>(zeroAtn).1.2,funextfund↦matchdwith|.inl()=>rfl|.inr_=>rfl⟩⟩,⟨trivial,fund↦matchdwith|.inl()=>⟨trivial,func↦c.elim0⟩|.inr_=>(zeroAtn).2⟩⟩
falseAt n at its declared arity.
@[`@[expose]` has no effect outside a `module` fileexpose]deffalseAtOf(n:ℕ):COfn:=⟨falseAtn,rfl⟩
Prepend true to the sole argument.
@[`@[expose]` has no effect outside a `module` fileexpose]defincRaw:sig.toPFunctor.W:=WType.mk(.comp11)fund↦matchdwith|.inl()=>WType.mk(.succtrue)Fin.elim0|.inr_=>WType.mk(.proj10)Fin.elim0
Prepending true, as an expression of arity one.
@[`@[expose]` has no effect outside a `module` fileexpose]definc:C:=⟨⟨incRaw,⊢ sig.WValidincRawAll goals completed! 🐙⟩,⟨trivial,fund↦matchdwith|.inl()=>⟨trivial,func↦c.elim0⟩|.inr_=>⟨trivial,func↦c.elim0⟩⟩⟩
inc at its declared arity.
@[`@[expose]` has no effect outside a `module` fileexpose]defincOf:COf1:=⟨inc,rfl⟩
The sole argument with two bits dropped. It is empty exactly when the
argument is the failure flag, whose two predecessors truncate to the empty
bitstring, or a depth below two.
@[`@[expose]` has no effect outside a `module` fileexpose]defpredPredRaw:sig.toPFunctor.W:=WType.mk(.comp11)fund↦matchdwith|.inl()=>predRaw|.inr_=>WType.mk(.comp11)fune↦matchewith|.inl()=>predRaw|.inr_=>WType.mk(.proj10)Fin.elim0
Dropping two bits, as an expression of arity one.
@[`@[expose]` has no effect outside a `module` fileexpose]defpredPred:C:=⟨⟨predPredRaw,⊢ sig.WValidpredPredRawAll goals completed! 🐙⟩,⟨trivial,fund↦matchdwith|.inl()=>pred.1.2|.inr_=>⟨trivial,fune↦matchewith|.inl()=>pred.1.2|.inr_=>⟨trivial,func↦c.elim0⟩⟩⟩⟩
predPred at its declared arity.
@[`@[expose]` has no effect outside a `module` fileexpose]defpredPredOf:COf1:=⟨predPred,rfl⟩
The leaf step: push a level onto a live value, whose head is true, and
return the failure flag on a value that is empty or has head false. Of
arity one, the state being the sole argument a fold's step reads.
@[`@[expose]` has no effect outside a `module` fileexpose]defcombFalseStepRaw:sig.toPFunctor.W:=WType.mk(.comp14)fund↦matchdwith|.inl()=>condRaw|.inri=>![WType.mk(.proj10)Fin.elim0,falseAtRaw1,WType.mk(.comp11)(fune↦matchewith|.inl()=>incRaw|.inr_=>WType.mk(.proj10)Fin.elim0),falseAtRaw1]i
The leaf step as an expression of arity one.
@[`@[expose]` has no effect outside a `module` fileexpose]defcombFalseStep:C:=⟨⟨combFalseStepRaw,⊢ sig.WValidcombFalseStepRawAll goals completed! 🐙⟩,⟨trivial,fund↦matchdwith|.inl()=>cond.1.2|.inr0=>⟨trivial,func↦c.elim0⟩|.inr1=>(falseAt1).2|.inr2=>⟨trivial,fune↦matchewith|.inl()=>inc.2|.inr_=>⟨trivial,func↦c.elim0⟩⟩|.inr3=>(falseAt1).2⟩⟩
combFalseStep at its declared arity.
@[`@[expose]` has no effect outside a `module` fileexpose]defcombFalseStepOf:COf1:=⟨combFalseStep,rfl⟩
The node step: pop a level when at least two remain, and return the
failure flag otherwise. An existing failure propagates, its guard being
empty. Of arity one, as combFalseStep.
@[`@[expose]` has no effect outside a `module` fileexpose]defcombTrueStepRaw:sig.toPFunctor.W:=WType.mk(.comp14)fund↦matchdwith|.inl()=>condRaw|.inri=>![WType.mk(.comp11)(fune↦matchewith|.inl()=>predPredRaw|.inr_=>WType.mk(.proj10)Fin.elim0),falseAtRaw1,WType.mk(.comp11)(fune↦matchewith|.inl()=>predRaw|.inr_=>WType.mk(.proj10)Fin.elim0),WType.mk(.comp11)(fune↦matchewith|.inl()=>predRaw|.inr_=>WType.mk(.proj10)Fin.elim0)]i
The node step as an expression of arity one.
@[`@[expose]` has no effect outside a `module` fileexpose]defcombTrueStep:C:=⟨⟨combTrueStepRaw,⊢ sig.WValidcombTrueStepRawAll goals completed! 🐙⟩,⟨trivial,fund↦matchdwith|.inl()=>cond.1.2|.inr0=>⟨trivial,fune↦matchewith|.inl()=>predPred.2|.inr_=>⟨trivial,func↦c.elim0⟩⟩|.inr1=>(falseAt1).2|.inr2=>⟨trivial,fune↦matchewith|.inl()=>pred.1.2|.inr_=>⟨trivial,func↦c.elim0⟩⟩|.inr3=>⟨trivial,fune↦matchewith|.inl()=>pred.1.2|.inr_=>⟨trivial,func↦c.elim0⟩⟩⟩⟩
combTrueStep at its declared arity.
@[`@[expose]` has no effect outside a `module` fileexpose]defcombTrueStepOf:COf1:=⟨combTrueStep,rfl⟩
The raw tree of the scan, as a scanner: base [true], the empty bitstring
having depth zero and satisfying RankedAlphabet.Binary.ok; growth one, the
value being never longer than the recursion variable by more than one bit.
The scan's meaning at its arity, as the scanner's. Cobham.eval asks
only for admissibility as a sig-tree, so the scan is characterized before
the expression carrying its recursion bound exists.
The scan is the scanner at its two steps. Stated because a def carries
no equation lemma: the cons lemmas rewrite by it, and length_combSem_le
rewrites by it in reverse, its statement being the one scan asks for.
A node bit pops a level when at least two remain, and fails otherwise. The
guard is the value with two bits dropped, so a failure, whose two predecessors
are empty, propagates.
The scan computes the stack depth in unary, offset by one, while
RankedAlphabet.Binary.ok holds, and the absorbing value [false] once it
has failed.
theoremcombSem_eq(w:ListBool):combSem![w]=ifokwthenList.replicate(depthw+1)trueelse[false]:=byw:ListBool⊢ combSem![w]=ifokw=truethenList.replicate(depthw+1)trueelse[false]refineList.rec(motive:=funu↦combSem![u]=ifokuthenList.replicate(depthu+1)trueelse[false])rfl?_ww:ListBool⊢ ∀(head:Bool)(tail:ListBool),(combSem![tail]=ifoktail=truethenList.replicate(depthtail+1)trueelse[false])→combSem![head::tail]=ifok(head::tail)=truethenList.replicate(depth(head::tail)+1)trueelse[false]introbvihw:ListBoolb:Boolv:ListBoolih:combSem![v]=ifokv=truethenList.replicate(depthv+1)trueelse[false]⊢ combSem![b::v]=ifok(b::v)=truethenList.replicate(depth(b::v)+1)trueelse[false]caseshok:okvfalsew:ListBoolb:Boolv:ListBoolih:combSem![v]=ifokv=truethenList.replicate(depthv+1)trueelse[false]hok:okv=false⊢ combSem![b::v]=ifok(b::v)=truethenList.replicate(depth(b::v)+1)trueelse[false]truew:ListBoolb:Boolv:ListBoolih:combSem![v]=ifokv=truethenList.replicate(depthv+1)trueelse[false]hok:okv=true⊢ combSem![b::v]=ifok(b::v)=truethenList.replicate(depth(b::v)+1)trueelse[false]·falsew:ListBoolb:Boolv:ListBoolih:combSem![v]=ifokv=truethenList.replicate(depthv+1)trueelse[false]hok:okv=false⊢ combSem![b::v]=ifok(b::v)=truethenList.replicate(depth(b::v)+1)trueelse[false]havehv:combSem![v]=[false]:=byw:ListBool⊢ combSem![w]=ifokw=truethenList.replicate(depthw+1)trueelse[false]rw[ih,w:ListBoolb:Boolv:ListBoolih:combSem![v]=ifokv=truethenList.replicate(depthv+1)trueelse[false]hok:okv=false⊢ (ifokv=truethenList.replicate(depthv+1)trueelse[false])=[false]hokw:ListBoolb:Boolv:ListBoolih:combSem![v]=ifokv=truethenList.replicate(depthv+1)trueelse[false]hok:okv=false⊢ (iffalse=truethenList.replicate(depthv+1)trueelse[false])=[false]]w:ListBoolb:Boolv:ListBoolih:combSem![v]=ifokv=truethenList.replicate(depthv+1)trueelse[false]hok:okv=false⊢ (iffalse=truethenList.replicate(depthv+1)trueelse[false])=[false];rflfalsew:ListBoolb:Boolv:ListBoolih:combSem![v]=ifokv=truethenList.replicate(depthv+1)trueelse[false]hok:okv=falsehv:combSem![v]=[false]⊢ combSem![b::v]=ifok(b::v)=truethenList.replicate(depth(b::v)+1)trueelse[false]casesbfalse.falsew:ListBoolv:ListBoolih:combSem![v]=ifokv=truethenList.replicate(depthv+1)trueelse[false]hok:okv=falsehv:combSem![v]=[false]⊢ combSem![false::v]=ifok(false::v)=truethenList.replicate(depth(false::v)+1)trueelse[false]false.truew:ListBoolv:ListBoolih:combSem![v]=ifokv=truethenList.replicate(depthv+1)trueelse[false]hok:okv=falsehv:combSem![v]=[false]⊢ combSem![true::v]=ifok(true::v)=truethenList.replicate(depth(true::v)+1)trueelse[false]·false.falsew:ListBoolv:ListBoolih:combSem![v]=ifokv=truethenList.replicate(depthv+1)trueelse[false]hok:okv=falsehv:combSem![v]=[false]⊢ combSem![false::v]=ifok(false::v)=truethenList.replicate(depth(false::v)+1)trueelse[false]rw[combSem_cons_false,false.falsew:ListBoolv:ListBoolih:combSem![v]=ifokv=truethenList.replicate(depthv+1)trueelse[false]hok:okv=falsehv:combSem![v]=[false]⊢ (matchcombSem![v]with|[]=>[false]|true::tail=>true::combSem![v]|false::tail=>[false])=ifok(false::v)=truethenList.replicate(depth(false::v)+1)trueelse[false]hv,false.falsew:ListBoolv:ListBoolih:combSem![v]=ifokv=truethenList.replicate(depthv+1)trueelse[false]hok:okv=falsehv:combSem![v]=[false]⊢ (match[false]with|[]=>[false]|true::tail=>[true,false]|false::tail=>[false])=ifok(false::v)=truethenList.replicate(depth(false::v)+1)trueelse[false]ok_cons_false,false.falsew:ListBoolv:ListBoolih:combSem![v]=ifokv=truethenList.replicate(depthv+1)trueelse[false]hok:okv=falsehv:combSem![v]=[false]⊢ (match[false]with|[]=>[false]|true::tail=>[true,false]|false::tail=>[false])=ifokv=truethenList.replicate(depth(false::v)+1)trueelse[false]hokfalse.falsew:ListBoolv:ListBoolih:combSem![v]=ifokv=truethenList.replicate(depthv+1)trueelse[false]hok:okv=falsehv:combSem![v]=[false]⊢ (match[false]with|[]=>[false]|true::tail=>[true,false]|false::tail=>[false])=iffalse=truethenList.replicate(depth(false::v)+1)trueelse[false]]false.falsew:ListBoolv:ListBoolih:combSem![v]=ifokv=truethenList.replicate(depthv+1)trueelse[false]hok:okv=falsehv:combSem![v]=[false]⊢ (match[false]with|[]=>[false]|true::tail=>[true,false]|false::tail=>[false])=iffalse=truethenList.replicate(depth(false::v)+1)trueelse[false]rflAll goals completed! 🐙·false.truew:ListBoolv:ListBoolih:combSem![v]=ifokv=truethenList.replicate(depthv+1)trueelse[false]hok:okv=falsehv:combSem![v]=[false]⊢ combSem![true::v]=ifok(true::v)=truethenList.replicate(depth(true::v)+1)trueelse[false]rw[combSem_cons_true,false.truew:ListBoolv:ListBoolih:combSem![v]=ifokv=truethenList.replicate(depthv+1)trueelse[false]hok:okv=falsehv:combSem![v]=[false]⊢ (match(combSem![v]).tail.tailwith|[]=>[false]|true::tail=>(combSem![v]).tail|false::tail=>(combSem![v]).tail)=ifok(true::v)=truethenList.replicate(depth(true::v)+1)trueelse[false]hv,false.truew:ListBoolv:ListBoolih:combSem![v]=ifokv=truethenList.replicate(depthv+1)trueelse[false]hok:okv=falsehv:combSem![v]=[false]⊢ (match[false].tail.tailwith|[]=>[false]|true::tail=>[false].tail|false::tail=>[false].tail)=ifok(true::v)=truethenList.replicate(depth(true::v)+1)trueelse[false]ok_cons_true,false.truew:ListBoolv:ListBoolih:combSem![v]=ifokv=truethenList.replicate(depthv+1)trueelse[false]hok:okv=falsehv:combSem![v]=[false]⊢ (match[false].tail.tailwith|[]=>[false]|true::tail=>[false].tail|false::tail=>[false].tail)=if(okv&&decide(2≤depthv))=truethenList.replicate(depth(true::v)+1)trueelse[false]hokfalse.truew:ListBoolv:ListBoolih:combSem![v]=ifokv=truethenList.replicate(depthv+1)trueelse[false]hok:okv=falsehv:combSem![v]=[false]⊢ (match[false].tail.tailwith|[]=>[false]|true::tail=>[false].tail|false::tail=>[false].tail)=if(false&&decide(2≤depthv))=truethenList.replicate(depth(true::v)+1)trueelse[false]]false.truew:ListBoolv:ListBoolih:combSem![v]=ifokv=truethenList.replicate(depthv+1)trueelse[false]hok:okv=falsehv:combSem![v]=[false]⊢ (match[false].tail.tailwith|[]=>[false]|true::tail=>[false].tail|false::tail=>[false].tail)=if(false&&decide(2≤depthv))=truethenList.replicate(depth(true::v)+1)trueelse[false]rflAll goals completed! 🐙·truew:ListBoolb:Boolv:ListBoolih:combSem![v]=ifokv=truethenList.replicate(depthv+1)trueelse[false]hok:okv=true⊢ combSem![b::v]=ifok(b::v)=truethenList.replicate(depth(b::v)+1)trueelse[false]havehv:combSem![v]=List.replicate(depthv+1)true:=byw:ListBool⊢ combSem![w]=ifokw=truethenList.replicate(depthw+1)trueelse[false]rw[ih,w:ListBoolb:Boolv:ListBoolih:combSem![v]=ifokv=truethenList.replicate(depthv+1)trueelse[false]hok:okv=true⊢ (ifokv=truethenList.replicate(depthv+1)trueelse[false])=List.replicate(depthv+1)truehokw:ListBoolb:Boolv:ListBoolih:combSem![v]=ifokv=truethenList.replicate(depthv+1)trueelse[false]hok:okv=true⊢ (iftrue=truethenList.replicate(depthv+1)trueelse[false])=List.replicate(depthv+1)true]w:ListBoolb:Boolv:ListBoolih:combSem![v]=ifokv=truethenList.replicate(depthv+1)trueelse[false]hok:okv=true⊢ (iftrue=truethenList.replicate(depthv+1)trueelse[false])=List.replicate(depthv+1)true;rfltruew:ListBoolb:Boolv:ListBoolih:combSem![v]=ifokv=truethenList.replicate(depthv+1)trueelse[false]hok:okv=truehv:combSem![v]=List.replicate(depthv+1)true⊢ combSem![b::v]=ifok(b::v)=truethenList.replicate(depth(b::v)+1)trueelse[false]casesbtrue.falsew:ListBoolv:ListBoolih:combSem![v]=ifokv=truethenList.replicate(depthv+1)trueelse[false]hok:okv=truehv:combSem![v]=List.replicate(depthv+1)true⊢ combSem![false::v]=ifok(false::v)=truethenList.replicate(depth(false::v)+1)trueelse[false]true.truew:ListBoolv:ListBoolih:combSem![v]=ifokv=truethenList.replicate(depthv+1)trueelse[false]hok:okv=truehv:combSem![v]=List.replicate(depthv+1)true⊢ combSem![true::v]=ifok(true::v)=truethenList.replicate(depth(true::v)+1)trueelse[false]·true.falsew:ListBoolv:ListBoolih:combSem![v]=ifokv=truethenList.replicate(depthv+1)trueelse[false]hok:okv=truehv:combSem![v]=List.replicate(depthv+1)true⊢ combSem![false::v]=ifok(false::v)=truethenList.replicate(depth(false::v)+1)trueelse[false]rw[combSem_cons_false,true.falsew:ListBoolv:ListBoolih:combSem![v]=ifokv=truethenList.replicate(depthv+1)trueelse[false]hok:okv=truehv:combSem![v]=List.replicate(depthv+1)true⊢ (matchcombSem![v]with|[]=>[false]|true::tail=>true::combSem![v]|false::tail=>[false])=ifok(false::v)=truethenList.replicate(depth(false::v)+1)trueelse[false]hv,true.falsew:ListBoolv:ListBoolih:combSem![v]=ifokv=truethenList.replicate(depthv+1)trueelse[false]hok:okv=truehv:combSem![v]=List.replicate(depthv+1)true⊢ (matchList.replicate(depthv+1)truewith|[]=>[false]|true::tail=>true::List.replicate(depthv+1)true|false::tail=>[false])=ifok(false::v)=truethenList.replicate(depth(false::v)+1)trueelse[false]ok_cons_false,true.falsew:ListBoolv:ListBoolih:combSem![v]=ifokv=truethenList.replicate(depthv+1)trueelse[false]hok:okv=truehv:combSem![v]=List.replicate(depthv+1)true⊢ (matchList.replicate(depthv+1)truewith|[]=>[false]|true::tail=>true::List.replicate(depthv+1)true|false::tail=>[false])=ifokv=truethenList.replicate(depth(false::v)+1)trueelse[false]hok,true.falsew:ListBoolv:ListBoolih:combSem![v]=ifokv=truethenList.replicate(depthv+1)trueelse[false]hok:okv=truehv:combSem![v]=List.replicate(depthv+1)true⊢ (matchList.replicate(depthv+1)truewith|[]=>[false]|true::tail=>true::List.replicate(depthv+1)true|false::tail=>[false])=iftrue=truethenList.replicate(depth(false::v)+1)trueelse[false]depth_cons_false_of_okvhoktrue.falsew:ListBoolv:ListBoolih:combSem![v]=ifokv=truethenList.replicate(depthv+1)trueelse[false]hok:okv=truehv:combSem![v]=List.replicate(depthv+1)true⊢ (matchList.replicate(depthv+1)truewith|[]=>[false]|true::tail=>true::List.replicate(depthv+1)true|false::tail=>[false])=iftrue=truethenList.replicate(depthv+1+1)trueelse[false]]true.falsew:ListBoolv:ListBoolih:combSem![v]=ifokv=truethenList.replicate(depthv+1)trueelse[false]hok:okv=truehv:combSem![v]=List.replicate(depthv+1)true⊢ (matchList.replicate(depthv+1)truewith|[]=>[false]|true::tail=>true::List.replicate(depthv+1)true|false::tail=>[false])=iftrue=truethenList.replicate(depthv+1+1)trueelse[false]rflAll goals completed! 🐙·true.truew:ListBoolv:ListBoolih:combSem![v]=ifokv=truethenList.replicate(depthv+1)trueelse[false]hok:okv=truehv:combSem![v]=List.replicate(depthv+1)true⊢ combSem![true::v]=ifok(true::v)=truethenList.replicate(depth(true::v)+1)trueelse[false]rw[combSem_cons_true,true.truew:ListBoolv:ListBoolih:combSem![v]=ifokv=truethenList.replicate(depthv+1)trueelse[false]hok:okv=truehv:combSem![v]=List.replicate(depthv+1)true⊢ (match(combSem![v]).tail.tailwith|[]=>[false]|true::tail=>(combSem![v]).tail|false::tail=>(combSem![v]).tail)=ifok(true::v)=truethenList.replicate(depth(true::v)+1)trueelse[false]hv,true.truew:ListBoolv:ListBoolih:combSem![v]=ifokv=truethenList.replicate(depthv+1)trueelse[false]hok:okv=truehv:combSem![v]=List.replicate(depthv+1)true⊢ (match(List.replicate(depthv+1)true).tail.tailwith|[]=>[false]|true::tail=>(List.replicate(depthv+1)true).tail|false::tail=>(List.replicate(depthv+1)true).tail)=ifok(true::v)=truethenList.replicate(depth(true::v)+1)trueelse[false]ok_cons_true,true.truew:ListBoolv:ListBoolih:combSem![v]=ifokv=truethenList.replicate(depthv+1)trueelse[false]hok:okv=truehv:combSem![v]=List.replicate(depthv+1)true⊢ (match(List.replicate(depthv+1)true).tail.tailwith|[]=>[false]|true::tail=>(List.replicate(depthv+1)true).tail|false::tail=>(List.replicate(depthv+1)true).tail)=if(okv&&decide(2≤depthv))=truethenList.replicate(depth(true::v)+1)trueelse[false]hoktrue.truew:ListBoolv:ListBoolih:combSem![v]=ifokv=truethenList.replicate(depthv+1)trueelse[false]hok:okv=truehv:combSem![v]=List.replicate(depthv+1)true⊢ (match(List.replicate(depthv+1)true).tail.tailwith|[]=>[false]|true::tail=>(List.replicate(depthv+1)true).tail|false::tail=>(List.replicate(depthv+1)true).tail)=if(true&&decide(2≤depthv))=truethenList.replicate(depth(true::v)+1)trueelse[false]]true.truew:ListBoolv:ListBoolih:combSem![v]=ifokv=truethenList.replicate(depthv+1)trueelse[false]hok:okv=truehv:combSem![v]=List.replicate(depthv+1)true⊢ (match(List.replicate(depthv+1)true).tail.tailwith|[]=>[false]|true::tail=>(List.replicate(depthv+1)true).tail|false::tail=>(List.replicate(depthv+1)true).tail)=if(true&&decide(2≤depthv))=truethenList.replicate(depth(true::v)+1)trueelse[false]-- the guard's two predecessors reduce only on a numeral of at least that-- size, so the depth is split into constructor forms; the conditional-- depth lemma applies only in the third case, the first two closing on-- the failed branchhavehsplit:∀d:ℕ,d=0∨d=1∨∃m,d=m+2:=fund↦matchdwith|0=>Or.inlrfl|1=>Or.inr(Or.inlrfl)|(m+2)=>Or.inr(Or.inr⟨m,rfl⟩)true.truew:ListBoolv:ListBoolih:combSem![v]=ifokv=truethenList.replicate(depthv+1)trueelse[false]hok:okv=truehv:combSem![v]=List.replicate(depthv+1)truehsplit:∀(d:ℕ),d=0∨d=1∨∃m,d=m+2⊢ (match(List.replicate(depthv+1)true).tail.tailwith|[]=>[false]|true::tail=>(List.replicate(depthv+1)true).tail|false::tail=>(List.replicate(depthv+1)true).tail)=if(true&&decide(2≤depthv))=truethenList.replicate(depth(true::v)+1)trueelse[false]obtain(h0|h1|⟨m,hm⟩):=hsplit(depthv)true.true.inlw:ListBoolv:ListBoolih:combSem![v]=ifokv=truethenList.replicate(depthv+1)trueelse[false]hok:okv=truehv:combSem![v]=List.replicate(depthv+1)truehsplit:∀(d:ℕ),d=0∨d=1∨∃m,d=m+2h0:depthv=0⊢ (match(List.replicate(depthv+1)true).tail.tailwith|[]=>[false]|true::tail=>(List.replicate(depthv+1)true).tail|false::tail=>(List.replicate(depthv+1)true).tail)=if(true&&decide(2≤depthv))=truethenList.replicate(depth(true::v)+1)trueelse[false]true.true.inr.inlw:ListBoolv:ListBoolih:combSem![v]=ifokv=truethenList.replicate(depthv+1)trueelse[false]hok:okv=truehv:combSem![v]=List.replicate(depthv+1)truehsplit:∀(d:ℕ),d=0∨d=1∨∃m,d=m+2h1:depthv=1⊢ (match(List.replicate(depthv+1)true).tail.tailwith|[]=>[false]|true::tail=>(List.replicate(depthv+1)true).tail|false::tail=>(List.replicate(depthv+1)true).tail)=if(true&&decide(2≤depthv))=truethenList.replicate(depth(true::v)+1)trueelse[false]true.true.inr.inrw:ListBoolv:ListBoolih:combSem![v]=ifokv=truethenList.replicate(depthv+1)trueelse[false]hok:okv=truehv:combSem![v]=List.replicate(depthv+1)truehsplit:∀(d:ℕ),d=0∨d=1∨∃m,d=m+2m:ℕhm:depthv=m+2⊢ (match(List.replicate(depthv+1)true).tail.tailwith|[]=>[false]|true::tail=>(List.replicate(depthv+1)true).tail|false::tail=>(List.replicate(depthv+1)true).tail)=if(true&&decide(2≤depthv))=truethenList.replicate(depth(true::v)+1)trueelse[false]·true.true.inlw:ListBoolv:ListBoolih:combSem![v]=ifokv=truethenList.replicate(depthv+1)trueelse[false]hok:okv=truehv:combSem![v]=List.replicate(depthv+1)truehsplit:∀(d:ℕ),d=0∨d=1∨∃m,d=m+2h0:depthv=0⊢ (match(List.replicate(depthv+1)true).tail.tailwith|[]=>[false]|true::tail=>(List.replicate(depthv+1)true).tail|false::tail=>(List.replicate(depthv+1)true).tail)=if(true&&decide(2≤depthv))=truethenList.replicate(depth(true::v)+1)trueelse[false]rw[h0true.true.inlw:ListBoolv:ListBoolih:combSem![v]=ifokv=truethenList.replicate(depthv+1)trueelse[false]hok:okv=truehv:combSem![v]=List.replicate(depthv+1)truehsplit:∀(d:ℕ),d=0∨d=1∨∃m,d=m+2h0:depthv=0⊢ (match(List.replicate(0+1)true).tail.tailwith|[]=>[false]|true::tail=>(List.replicate(0+1)true).tail|false::tail=>(List.replicate(0+1)true).tail)=if(true&&decide(2≤0))=truethenList.replicate(depth(true::v)+1)trueelse[false]]true.true.inlw:ListBoolv:ListBoolih:combSem![v]=ifokv=truethenList.replicate(depthv+1)trueelse[false]hok:okv=truehv:combSem![v]=List.replicate(depthv+1)truehsplit:∀(d:ℕ),d=0∨d=1∨∃m,d=m+2h0:depthv=0⊢ (match(List.replicate(0+1)true).tail.tailwith|[]=>[false]|true::tail=>(List.replicate(0+1)true).tail|false::tail=>(List.replicate(0+1)true).tail)=if(true&&decide(2≤0))=truethenList.replicate(depth(true::v)+1)trueelse[false];rflAll goals completed! 🐙·true.true.inr.inlw:ListBoolv:ListBoolih:combSem![v]=ifokv=truethenList.replicate(depthv+1)trueelse[false]hok:okv=truehv:combSem![v]=List.replicate(depthv+1)truehsplit:∀(d:ℕ),d=0∨d=1∨∃m,d=m+2h1:depthv=1⊢ (match(List.replicate(depthv+1)true).tail.tailwith|[]=>[false]|true::tail=>(List.replicate(depthv+1)true).tail|false::tail=>(List.replicate(depthv+1)true).tail)=if(true&&decide(2≤depthv))=truethenList.replicate(depth(true::v)+1)trueelse[false]rw[h1true.true.inr.inlw:ListBoolv:ListBoolih:combSem![v]=ifokv=truethenList.replicate(depthv+1)trueelse[false]hok:okv=truehv:combSem![v]=List.replicate(depthv+1)truehsplit:∀(d:ℕ),d=0∨d=1∨∃m,d=m+2h1:depthv=1⊢ (match(List.replicate(1+1)true).tail.tailwith|[]=>[false]|true::tail=>(List.replicate(1+1)true).tail|false::tail=>(List.replicate(1+1)true).tail)=if(true&&decide(2≤1))=truethenList.replicate(depth(true::v)+1)trueelse[false]]true.true.inr.inlw:ListBoolv:ListBoolih:combSem![v]=ifokv=truethenList.replicate(depthv+1)trueelse[false]hok:okv=truehv:combSem![v]=List.replicate(depthv+1)truehsplit:∀(d:ℕ),d=0∨d=1∨∃m,d=m+2h1:depthv=1⊢ (match(List.replicate(1+1)true).tail.tailwith|[]=>[false]|true::tail=>(List.replicate(1+1)true).tail|false::tail=>(List.replicate(1+1)true).tail)=if(true&&decide(2≤1))=truethenList.replicate(depth(true::v)+1)trueelse[false];rflAll goals completed! 🐙·true.true.inr.inrw:ListBoolv:ListBoolih:combSem![v]=ifokv=truethenList.replicate(depthv+1)trueelse[false]hok:okv=truehv:combSem![v]=List.replicate(depthv+1)truehsplit:∀(d:ℕ),d=0∨d=1∨∃m,d=m+2m:ℕhm:depthv=m+2⊢ (match(List.replicate(depthv+1)true).tail.tailwith|[]=>[false]|true::tail=>(List.replicate(depthv+1)true).tail|false::tail=>(List.replicate(depthv+1)true).tail)=if(true&&decide(2≤depthv))=truethenList.replicate(depth(true::v)+1)trueelse[false]rw[depth_cons_true_of_ok_of_two_le_depthvhok(byw:ListBoolv:ListBoolih:combSem![v]=ifokv=truethenList.replicate(depthv+1)trueelse[false]hok:okv=truehv:combSem![v]=List.replicate(depthv+1)truehsplit:∀(d:ℕ),d=0∨d=1∨∃m,d=m+2m:ℕhm:depthv=m+2⊢ 2≤depthvomegaAll goals completed! 🐙),hmtrue.true.inr.inrw:ListBoolv:ListBoolih:combSem![v]=ifokv=truethenList.replicate(depthv+1)trueelse[false]hok:okv=truehv:combSem![v]=List.replicate(depthv+1)truehsplit:∀(d:ℕ),d=0∨d=1∨∃m,d=m+2m:ℕhm:depthv=m+2⊢ (match(List.replicate(m+2+1)true).tail.tailwith|[]=>[false]|true::tail=>(List.replicate(m+2+1)true).tail|false::tail=>(List.replicate(m+2+1)true).tail)=if(true&&decide(2≤m+2))=truethenList.replicate(m+2-1+1)trueelse[false]]true.true.inr.inrw:ListBoolv:ListBoolih:combSem![v]=ifokv=truethenList.replicate(depthv+1)trueelse[false]hok:okv=truehv:combSem![v]=List.replicate(depthv+1)truehsplit:∀(d:ℕ),d=0∨d=1∨∃m,d=m+2m:ℕhm:depthv=m+2⊢ (match(List.replicate(m+2+1)true).tail.tailwith|[]=>[false]|true::tail=>(List.replicate(m+2+1)true).tail|false::tail=>(List.replicate(m+2+1)true).tail)=if(true&&decide(2≤m+2))=truethenList.replicate(m+2-1+1)trueelse[false];rflAll goals completed! 🐙
The scan's value exceeds the recursion variable by at most one bit: it is
[false], of length one, or the depth in unary offset by one, and the depth
never exceeds the word length (RankedAlphabet.Binary.depth_le_length). This
is the recursion bound scan asks for, at the growth its bound child
carries.
The stack depth and the underflow verdict of a bitstring in one value, as
the scanner at the two steps, with length_combSem_le discharging its
recursion bound.
The meaning combSem reads at the raw tree is the meaning comb carries:
the statements about the scan are statements about the member of C whose
recursion bound comb discharges.
The inner conditional of eqOne: whether the predecessor of the argument
is empty.
@[`@[expose]` has no effect outside a `module` fileexpose]defeqOneInnerRaw:sig.toPFunctor.W:=WType.mk(.comp14)fund↦matchdwith|.inl()=>condRaw|.inri=>![WType.mk(.comp11)(fune↦matchewith|.inl()=>predRaw|.inr_=>WType.mk(.proj10)Fin.elim0),oneAtRaw1,zeroAtRaw1,zeroAtRaw1]i
The inner conditional as an expression of arity one.
@[`@[expose]` has no effect outside a `module` fileexpose]defeqOneInner:C:=⟨⟨eqOneInnerRaw,by⊢ sig.WValideqOneInnerRawdecideAll goals completed! 🐙⟩,⟨trivial,fund↦matchdwith|.inl()=>cond.1.2|.inr0=>⟨trivial,fune↦matchewith|.inl()=>pred.1.2|.inr_=>⟨trivial,func↦c.elim0⟩⟩|.inr1=>(oneAt1).2|.inr2=>(zeroAt1).2|.inr3=>(zeroAt1).2⟩⟩
eqOneInner at its declared arity.
@[`@[expose]` has no effect outside a `module` fileexpose]defeqOneInnerOf:COf1:=⟨eqOneInner,rfl⟩
The raw tree of the one-test: the empty bitstring is not one, and
otherwise the argument is one exactly when its predecessor is empty.
Whether a bitstring has length one, as an expression of arity one.
@[`@[expose]` has no effect outside a `module` fileexpose]defeqOne:C:=⟨⟨eqOneRaw,by⊢ sig.WValideqOneRawdecideAll goals completed! 🐙⟩,⟨trivial,fund↦matchdwith|.inl()=>cond.1.2|.inr0=>⟨trivial,func↦c.elim0⟩|.inr1=>(zeroAt1).2|.inr2=>eqOneInner.2|.inr3=>eqOneInner.2⟩⟩
eqOne at its declared arity, as combOf and isTreeOf.
@[`@[expose]` has no effect outside a `module` fileexpose]defeqOneOf:COf1:=⟨eqOne,rfl⟩
The one-test's meaning at its arity, taken at the raw tree rather than at
eqOne, as combSem.
@[`@[expose]` has no effect outside a `module` fileexpose]defeqOneSem:Sem1:=semAt1⟨eqOneRaw,by⊢ sig.WValideqOneRawdecideAll goals completed! 🐙⟩rfl
The one-test at an arbitrary environment is the test at the canonical
one.
The raw tree of the recognizer: the one-test on the scan's predecessor.
@[`@[expose]` has no effect outside a `module` fileexpose]defisTreeRaw:sig.toPFunctor.W:=WType.mk(.comp11)fund↦matchdwith|.inl()=>eqOneRaw|.inr_=>WType.mk(.comp11)fune↦matchewith|.inl()=>predRaw|.inr_=>combRaw
The recognizer: whether a bitstring is the preorder spelling of a binary
tree, as an expression of arity one.
@[`@[expose]` has no effect outside a `module` fileexpose]defisTree:C:=⟨⟨isTreeRaw,by⊢ sig.WValidisTreeRawdecideAll goals completed! 🐙⟩,⟨trivial,fund↦matchdwith|.inl()=>eqOne.2|.inr_=>⟨trivial,fune↦matchewith|.inl()=>pred.1.2|.inr_=>comb.2⟩⟩⟩
isTree at its declared arity.
@[`@[expose]` has no effect outside a `module` fileexpose]defisTreeOf:COf1:=⟨isTree,rfl⟩
The recognizer's meaning at its arity, taken at the raw tree rather than
at isTree, as combSem.
@[`@[expose]` has no effect outside a `module` fileexpose]defisTreeSem:Sem1:=semAt1⟨isTreeRaw,by⊢ sig.WValidisTreeRawdecideAll goals completed! 🐙⟩rfl
The meaning isTreeSem reads at the raw tree is the meaning isTree
carries, as combSem_eq_eval for the scan: the correctness statements below
are statements about the member of C that isTree_smashFree concerns.
One step of the recognizer: the one-test on the scan's predecessor. The
scan's value is [false] on failure, whose predecessor is empty, and
otherwise the depth in unary offset by one, whose predecessor has length the
depth.
The recognizer lies in the smash-free subalgebra. With
[Strahm2003] Theorem 1(2)'s left-to-right inclusion, the decision of
RankedAlphabet.Valid at the two-symbol alphabet is computable
simultaneously in polynomial time and linear space.