Imports
/- Copyright (c) 2026 Terence Rokop. All rights reserved. Released under Apache 2.0 license as described in the file LICENSE. Authors: Terence Rokop -/ module public import Geb.Mathlib.Computability.BellantoniCook.Basic public import Geb.Mathlib.Data.PFunctor.Slice.Decidable public import Geb.Mathlib.Data.Tree.Ranked.Binary

A tree recognizer in the Bellantoni-Cook class

Three expressions of B deciding whether a bitstring is the preorder spelling of a binary tree, and their correctness 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 B accepts exactly the spellings of binRanked's terms. BellantoniCook.BC reformulates [BellantoniCook1992]'s class; by [HeraudNowak2011] Theorems 1 and 2, which relate B to Cobham's class in both directions, composed with Cobham's theorem identifying Cobham's class with the polynomial-time functions, B coincides with the polynomial-time functions. That composition is used and not proved here, so the membership test lies in that class without a separate complexity argument.

The recognizer is a single right-to-left scan rather than a recursive descent. A descent would parse the second subtree from a remainder the first call computes, which sits in safe position, and recursion on a safe argument is what the class forbids.

Main definitions

    BellantoniCook.zeroAtRaw, BellantoniCook.oneAtRaw — the empty bitstring and the one-bit string [true] at an arbitrary arity.

    BellantoniCook.falseAtRaw — the one-bit string [false] at an arbitrary arity.

    BellantoniCook.comb — the stack depth and the underflow verdict in a single value, of arity (1, 0).

    BellantoniCook.eqOne — whether a bitstring has length one, of arity (0, 1).

    BellantoniCook.isTree — the recognizer, of arity (1, 0).

    BellantoniCook.combSem, BellantoniCook.eqOneSem and BellantoniCook.isTreeSem — the meaning of each of the three at its arity, over which every statement of the module is stated.

Main statements

    BellantoniCook.combSem_eq — the scan computes RankedAlphabet.Binary.depth in unary, offset by one, while RankedAlphabet.Binary.ok holds, and [false] once it has failed.

    BellantoniCook.eqOneSem_eqeqOne accepts exactly the bitstrings of length one.

    BellantoniCook.isTreeSem_eq_singleton_iff_validisTree accepts exactly the words binRanked's scan accepts.

    BellantoniCook.isTreeSem_eq_singleton_iff_exists_spell — equivalently, exactly the spellings of binRanked's terms.

    BellantoniCook.isTreeSem_eq_ite — the recognizer as the indicator of binRanked's scan.

Implementation notes

The scan carries the stack depth and the underflow verdict 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.

Each unfolding lemma is stated per constructor with the recursive value exposed on the right. Sem is a function type, so evalRec recurses at a function motive and every eliminator in the chain sits there; eliminators at function motives reduce only when their scrutinee is a constructor, so a symbolic-bit or fold-shaped statement is not definitional.

Every unfolding lemma closes by rfl across the module boundary, and so depends on the @[expose] attributes Basic.lean carries on Direction, rc, q, sig, compChildren, BC, evalRec, evalValue, evalStep and BC.eval. Removing any of them leaves those lemmas stuck; the failure is silent at the language server and appears at lake build.

combSem, eqOneSem and isTreeSem name each meaning at its arity, so that the arity pair is reduced and 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.

References

    [BellantoniCook1992]

    [HeraudNowak2011]

Tags

Bellantoni-Cook, polytime, implicit computational complexity, safe recursion, binary tree, preorder, recognizer

namespace BellantoniCookopen RankedAlphabet.Binarypublic section

The empty bitstring at an arbitrary arity.

@[`@[expose]` has no effect outside a `module` fileexpose] def zeroAtRaw (n s : ) : sig.toPFunctor.W := WType.mk (.comp n s 0 0) (compChildren (WType.mk .zero Fin.elim0) Fin.elim0 Fin.elim0)

The one-bit string [true] at an arbitrary arity.

@[`@[expose]` has no effect outside a `module` fileexpose] def oneAtRaw (n s : ) : sig.toPFunctor.W := WType.mk (.comp n s 0 1) (compChildren (WType.mk (.succ true) Fin.elim0) Fin.elim0 ![zeroAtRaw n s])

The one-bit string [false] at an arbitrary arity.

@[`@[expose]` has no effect outside a `module` fileexpose] def falseAtRaw (n s : ) : sig.toPFunctor.W := WType.mk (.comp n s 0 1) (compChildren (WType.mk (.succ false) Fin.elim0) Fin.elim0 ![zeroAtRaw n s])

Prepend true to the recursive value.

@[`@[expose]` has no effect outside a `module` fileexpose] def incRaw : sig.toPFunctor.W := WType.mk (.comp 1 1 0 1) (compChildren (WType.mk (.succ true) Fin.elim0) Fin.elim0 ![WType.mk (.proj 1 1 1) Fin.elim0])

Drop the low bit of the recursive value.

@[`@[expose]` has no effect outside a `module` fileexpose] def decRaw : sig.toPFunctor.W := WType.mk (.comp 1 1 0 1) (compChildren (WType.mk .pred Fin.elim0) Fin.elim0 ![WType.mk (.proj 1 1 1) Fin.elim0])

The guard of the node step: the recursive value with two bits dropped. It is empty exactly when the value 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] def predPredRaw : sig.toPFunctor.W := WType.mk (.comp 1 1 0 1) (compChildren (WType.mk .pred Fin.elim0) Fin.elim0 ![decRaw])

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.

@[`@[expose]` has no effect outside a `module` fileexpose] def combFalseStepRaw : sig.toPFunctor.W := WType.mk (.comp 1 1 0 4) (compChildren (WType.mk .cond Fin.elim0) Fin.elim0 ![WType.mk (.proj 1 1 1) Fin.elim0, falseAtRaw 1 1, incRaw, falseAtRaw 1 1])

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.

@[`@[expose]` has no effect outside a `module` fileexpose] def combTrueStepRaw : sig.toPFunctor.W := WType.mk (.comp 1 1 0 4) (compChildren (WType.mk .cond Fin.elim0) Fin.elim0 ![predPredRaw, falseAtRaw 1 1, decRaw, decRaw])

The raw tree of the scan. The base is [true], the empty bitstring having depth zero and satisfying RankedAlphabet.Binary.ok.

@[`@[expose]` has no effect outside a `module` fileexpose] def combRaw : sig.toPFunctor.W := WType.mk (.safeRec 0 0) ![oneAtRaw 0 0, combFalseStepRaw, combTrueStepRaw]

The stack depth and the underflow verdict of a bitstring in one value: the depth in unary, offset by one so that a live value is non-empty with head true, and [false] once a node bit has been read below depth two.

@[`@[expose]` has no effect outside a `module` fileexpose] def comb : BC := combRaw, sig.WValid combRaw All goals completed! 🐙

The inner conditional of eqOne: whether the predecessor of the argument is empty. The even branch is unreachable only under this module's own use, where the argument is always a unary numeral; the expression and its characterization are stated for an arbitrary bitstring, over which the branch is reached.

@[`@[expose]` has no effect outside a `module` fileexpose] def eqOneInnerRaw : sig.toPFunctor.W := WType.mk (.comp 0 1 0 4) (compChildren (WType.mk .cond Fin.elim0) Fin.elim0 ![WType.mk (.comp 0 1 0 1) (compChildren (WType.mk .pred Fin.elim0) Fin.elim0 ![WType.mk (.proj 0 1 0) Fin.elim0]), oneAtRaw 0 1, zeroAtRaw 0 1, zeroAtRaw 0 1])

The raw tree of the one-test: empty is not one, and otherwise the argument is one exactly when its predecessor is empty.

@[`@[expose]` has no effect outside a `module` fileexpose] def eqOneRaw : sig.toPFunctor.W := WType.mk (.comp 0 1 0 4) (compChildren (WType.mk .cond Fin.elim0) Fin.elim0 ![WType.mk (.proj 0 1 0) Fin.elim0, zeroAtRaw 0 1, eqOneInnerRaw, eqOneInnerRaw])

Whether a bitstring has length one, returning [true] or [].

@[`@[expose]` has no effect outside a `module` fileexpose] def eqOne : BC := eqOneRaw, sig.WValid eqOneRaw All goals completed! 🐙

The raw tree of the recognizer: the scan's predecessor has length one.

@[`@[expose]` has no effect outside a `module` fileexpose] def isTreeRaw : sig.toPFunctor.W := WType.mk (.comp 1 0 0 1) (compChildren eqOneRaw Fin.elim0 ![WType.mk (.comp 1 0 0 1) (compChildren (WType.mk .pred Fin.elim0) Fin.elim0 ![combRaw])])

The recognizer: whether a bitstring is the preorder spelling of a binary tree. The output is [true] or [], so correctness is an equation rather than a disequation.

@[`@[expose]` has no effect outside a `module` fileexpose] def isTree : BC := isTreeRaw, sig.WValid isTreeRaw All goals completed! 🐙

comb at its declared arity. Elaborating this is the assertion that BC.arity comb is (1, 0).

@[`@[expose]` has no effect outside a `module` fileexpose] def combOf : BCOf 1 0 := comb, rfl

eqOne at its declared arity.

@[`@[expose]` has no effect outside a `module` fileexpose] def eqOneOf : BCOf 0 1 := eqOne, rfl

isTree at its declared arity.

@[`@[expose]` has no effect outside a `module` fileexpose] def isTreeOf : BCOf 1 0 := isTree, rfl

The scan's meaning at its arity, ascribed so that the arity pair is reduced and rewriting under it type-checks.

@[`@[expose]` has no effect outside a `module` fileexpose] def combSem : (Fin 1 List Bool) (Fin 0 List Bool) List Bool := (BC.eval comb).2

The one-test's meaning at its arity, ascribed likewise.

@[`@[expose]` has no effect outside a `module` fileexpose] def eqOneSem : (Fin 0 List Bool) (Fin 1 List Bool) List Bool := (BC.eval eqOne).2

The recognizer's meaning at its arity, ascribed likewise.

@[`@[expose]` has no effect outside a `module` fileexpose] def isTreeSem : (Fin 1 List Bool) (Fin 0 List Bool) List Bool := (BC.eval isTree).2

The scan's value on the empty bitstring: depth zero, offset by one.

theorem combSem_nil : combSem ![[]] ![] = [true] := rfl

A leaf bit pushes a level onto a live value, and is absorbed by a failure.

theorem combSem_cons_false (v : List Bool) : combSem ![false :: v] ![] = (match combSem ![v] ![] with | [] => [false] | true :: _ => true :: combSem ![v] ![] | false :: _ => [false]) := rfl

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.

theorem combSem_cons_true (v : List Bool) : combSem ![true :: v] ![] = (match (combSem ![v] ![]).tail.tail with | [] => [false] | true :: _ => (combSem ![v] ![]).tail | false :: _ => (combSem ![v] ![]).tail) := rfl

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.

theorem combSem_eq (w : List Bool) : combSem ![w] ![] = if ok w then List.replicate (depth w + 1) true else [false] := w:List BoolcombSem ![w] ![] = if ok w = true then List.replicate (depth w + 1) true else [false] w:List Bool (head : Bool) (tail : List Bool), (combSem ![tail] ![] = if ok tail = true then List.replicate (depth tail + 1) true else [false]) combSem ![head :: tail] ![] = if ok (head :: tail) = true then List.replicate (depth (head :: tail) + 1) true else [false] w:List Boolb:Boolv:List Boolih:combSem ![v] ![] = if ok v = true then List.replicate (depth v + 1) true else [false]combSem ![b :: v] ![] = if ok (b :: v) = true then List.replicate (depth (b :: v) + 1) true else [false] w:List Boolb:Boolv:List Boolih:combSem ![v] ![] = if ok v = true then List.replicate (depth v + 1) true else [false]hok:ok v = falsecombSem ![b :: v] ![] = if ok (b :: v) = true then List.replicate (depth (b :: v) + 1) true else [false]w:List Boolb:Boolv:List Boolih:combSem ![v] ![] = if ok v = true then List.replicate (depth v + 1) true else [false]hok:ok v = truecombSem ![b :: v] ![] = if ok (b :: v) = true then List.replicate (depth (b :: v) + 1) true else [false] w:List Boolb:Boolv:List Boolih:combSem ![v] ![] = if ok v = true then List.replicate (depth v + 1) true else [false]hok:ok v = falsecombSem ![b :: v] ![] = if ok (b :: v) = true then List.replicate (depth (b :: v) + 1) true else [false] w:List Boolb:Boolv:List Boolih:combSem ![v] ![] = if ok v = true then List.replicate (depth v + 1) true else [false]hok:ok v = falsehv:combSem ![v] ![] = [false]combSem ![b :: v] ![] = if ok (b :: v) = true then List.replicate (depth (b :: v) + 1) true else [false] w:List Boolv:List Boolih:combSem ![v] ![] = if ok v = true then List.replicate (depth v + 1) true else [false]hok:ok v = falsehv:combSem ![v] ![] = [false]combSem ![false :: v] ![] = if ok (false :: v) = true then List.replicate (depth (false :: v) + 1) true else [false]w:List Boolv:List Boolih:combSem ![v] ![] = if ok v = true then List.replicate (depth v + 1) true else [false]hok:ok v = falsehv:combSem ![v] ![] = [false]combSem ![true :: v] ![] = if ok (true :: v) = true then List.replicate (depth (true :: v) + 1) true else [false] w:List Boolv:List Boolih:combSem ![v] ![] = if ok v = true then List.replicate (depth v + 1) true else [false]hok:ok v = falsehv:combSem ![v] ![] = [false]combSem ![false :: v] ![] = if ok (false :: v) = true then List.replicate (depth (false :: v) + 1) true else [false] w:List Boolv:List Boolih:combSem ![v] ![] = if ok v = true then List.replicate (depth v + 1) true else [false]hok:ok v = falsehv:combSem ![v] ![] = [false](match [false] with | [] => [false] | true :: tail => [true, false] | false :: tail => [false]) = if false = true then List.replicate (depth (false :: v) + 1) true else [false]; All goals completed! 🐙 w:List Boolv:List Boolih:combSem ![v] ![] = if ok v = true then List.replicate (depth v + 1) true else [false]hok:ok v = falsehv:combSem ![v] ![] = [false]combSem ![true :: v] ![] = if ok (true :: v) = true then List.replicate (depth (true :: v) + 1) true else [false] w:List Boolv:List Boolih:combSem ![v] ![] = if ok v = true then List.replicate (depth v + 1) true else [false]hok:ok v = falsehv:combSem ![v] ![] = [false](match [false].tail.tail with | [] => [false] | true :: tail => [false].tail | false :: tail => [false].tail) = if (false && decide (2 depth v)) = true then List.replicate (depth (true :: v) + 1) true else [false]; All goals completed! 🐙 w:List Boolb:Boolv:List Boolih:combSem ![v] ![] = if ok v = true then List.replicate (depth v + 1) true else [false]hok:ok v = truecombSem ![b :: v] ![] = if ok (b :: v) = true then List.replicate (depth (b :: v) + 1) true else [false] w:List Boolb:Boolv:List Boolih:combSem ![v] ![] = if ok v = true then List.replicate (depth v + 1) true else [false]hok:ok v = truehv:combSem ![v] ![] = List.replicate (depth v + 1) truecombSem ![b :: v] ![] = if ok (b :: v) = true then List.replicate (depth (b :: v) + 1) true else [false] w:List Boolv:List Boolih:combSem ![v] ![] = if ok v = true then List.replicate (depth v + 1) true else [false]hok:ok v = truehv:combSem ![v] ![] = List.replicate (depth v + 1) truecombSem ![false :: v] ![] = if ok (false :: v) = true then List.replicate (depth (false :: v) + 1) true else [false]w:List Boolv:List Boolih:combSem ![v] ![] = if ok v = true then List.replicate (depth v + 1) true else [false]hok:ok v = truehv:combSem ![v] ![] = List.replicate (depth v + 1) truecombSem ![true :: v] ![] = if ok (true :: v) = true then List.replicate (depth (true :: v) + 1) true else [false] w:List Boolv:List Boolih:combSem ![v] ![] = if ok v = true then List.replicate (depth v + 1) true else [false]hok:ok v = truehv:combSem ![v] ![] = List.replicate (depth v + 1) truecombSem ![false :: v] ![] = if ok (false :: v) = true then List.replicate (depth (false :: v) + 1) true else [false] w:List Boolv:List Boolih:combSem ![v] ![] = if ok v = true then List.replicate (depth v + 1) true else [false]hok:ok v = truehv:combSem ![v] ![] = List.replicate (depth v + 1) true(match List.replicate (depth v + 1) true with | [] => [false] | true :: tail => true :: List.replicate (depth v + 1) true | false :: tail => [false]) = if true = true then List.replicate (depth v + 1 + 1) true else [false] All goals completed! 🐙 w:List Boolv:List Boolih:combSem ![v] ![] = if ok v = true then List.replicate (depth v + 1) true else [false]hok:ok v = truehv:combSem ![v] ![] = List.replicate (depth v + 1) truecombSem ![true :: v] ![] = if ok (true :: v) = true then List.replicate (depth (true :: v) + 1) true else [false] w:List Boolv:List Boolih:combSem ![v] ![] = if ok v = true then List.replicate (depth v + 1) true else [false]hok:ok v = truehv:combSem ![v] ![] = List.replicate (depth v + 1) true(match (List.replicate (depth v + 1) true).tail.tail with | [] => [false] | true :: tail => (List.replicate (depth v + 1) true).tail | false :: tail => (List.replicate (depth v + 1) true).tail) = if (true && decide (2 depth v)) = true then List.replicate (depth (true :: v) + 1) true else [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 branch w:List Boolv:List Boolih:combSem ![v] ![] = if ok v = true then List.replicate (depth v + 1) true else [false]hok:ok v = truehv:combSem ![v] ![] = List.replicate (depth v + 1) truehsplit: (d : ), d = 0 d = 1 m, d = m + 2(match (List.replicate (depth v + 1) true).tail.tail with | [] => [false] | true :: tail => (List.replicate (depth v + 1) true).tail | false :: tail => (List.replicate (depth v + 1) true).tail) = if (true && decide (2 depth v)) = true then List.replicate (depth (true :: v) + 1) true else [false] w:List Boolv:List Boolih:combSem ![v] ![] = if ok v = true then List.replicate (depth v + 1) true else [false]hok:ok v = truehv:combSem ![v] ![] = List.replicate (depth v + 1) truehsplit: (d : ), d = 0 d = 1 m, d = m + 2h0:depth v = 0(match (List.replicate (depth v + 1) true).tail.tail with | [] => [false] | true :: tail => (List.replicate (depth v + 1) true).tail | false :: tail => (List.replicate (depth v + 1) true).tail) = if (true && decide (2 depth v)) = true then List.replicate (depth (true :: v) + 1) true else [false]w:List Boolv:List Boolih:combSem ![v] ![] = if ok v = true then List.replicate (depth v + 1) true else [false]hok:ok v = truehv:combSem ![v] ![] = List.replicate (depth v + 1) truehsplit: (d : ), d = 0 d = 1 m, d = m + 2h1:depth v = 1(match (List.replicate (depth v + 1) true).tail.tail with | [] => [false] | true :: tail => (List.replicate (depth v + 1) true).tail | false :: tail => (List.replicate (depth v + 1) true).tail) = if (true && decide (2 depth v)) = true then List.replicate (depth (true :: v) + 1) true else [false]w:List Boolv:List Boolih:combSem ![v] ![] = if ok v = true then List.replicate (depth v + 1) true else [false]hok:ok v = truehv:combSem ![v] ![] = List.replicate (depth v + 1) truehsplit: (d : ), d = 0 d = 1 m, d = m + 2m:hm:depth v = m + 2(match (List.replicate (depth v + 1) true).tail.tail with | [] => [false] | true :: tail => (List.replicate (depth v + 1) true).tail | false :: tail => (List.replicate (depth v + 1) true).tail) = if (true && decide (2 depth v)) = true then List.replicate (depth (true :: v) + 1) true else [false] w:List Boolv:List Boolih:combSem ![v] ![] = if ok v = true then List.replicate (depth v + 1) true else [false]hok:ok v = truehv:combSem ![v] ![] = List.replicate (depth v + 1) truehsplit: (d : ), d = 0 d = 1 m, d = m + 2h0:depth v = 0(match (List.replicate (depth v + 1) true).tail.tail with | [] => [false] | true :: tail => (List.replicate (depth v + 1) true).tail | false :: tail => (List.replicate (depth v + 1) true).tail) = if (true && decide (2 depth v)) = true then List.replicate (depth (true :: v) + 1) true else [false] w:List Boolv:List Boolih:combSem ![v] ![] = if ok v = true then List.replicate (depth v + 1) true else [false]hok:ok v = truehv:combSem ![v] ![] = List.replicate (depth v + 1) truehsplit: (d : ), d = 0 d = 1 m, d = m + 2h0:depth v = 0(match (List.replicate (0 + 1) true).tail.tail with | [] => [false] | true :: tail => (List.replicate (0 + 1) true).tail | false :: tail => (List.replicate (0 + 1) true).tail) = if (true && decide (2 0)) = true then List.replicate (depth (true :: v) + 1) true else [false]; All goals completed! 🐙 w:List Boolv:List Boolih:combSem ![v] ![] = if ok v = true then List.replicate (depth v + 1) true else [false]hok:ok v = truehv:combSem ![v] ![] = List.replicate (depth v + 1) truehsplit: (d : ), d = 0 d = 1 m, d = m + 2h1:depth v = 1(match (List.replicate (depth v + 1) true).tail.tail with | [] => [false] | true :: tail => (List.replicate (depth v + 1) true).tail | false :: tail => (List.replicate (depth v + 1) true).tail) = if (true && decide (2 depth v)) = true then List.replicate (depth (true :: v) + 1) true else [false] w:List Boolv:List Boolih:combSem ![v] ![] = if ok v = true then List.replicate (depth v + 1) true else [false]hok:ok v = truehv:combSem ![v] ![] = List.replicate (depth v + 1) truehsplit: (d : ), d = 0 d = 1 m, d = m + 2h1:depth v = 1(match (List.replicate (1 + 1) true).tail.tail with | [] => [false] | true :: tail => (List.replicate (1 + 1) true).tail | false :: tail => (List.replicate (1 + 1) true).tail) = if (true && decide (2 1)) = true then List.replicate (depth (true :: v) + 1) true else [false]; All goals completed! 🐙 w:List Boolv:List Boolih:combSem ![v] ![] = if ok v = true then List.replicate (depth v + 1) true else [false]hok:ok v = truehv:combSem ![v] ![] = List.replicate (depth v + 1) truehsplit: (d : ), d = 0 d = 1 m, d = m + 2m:hm:depth v = m + 2(match (List.replicate (depth v + 1) true).tail.tail with | [] => [false] | true :: tail => (List.replicate (depth v + 1) true).tail | false :: tail => (List.replicate (depth v + 1) true).tail) = if (true && decide (2 depth v)) = true then List.replicate (depth (true :: v) + 1) true else [false] w:List Boolv:List Boolih:combSem ![v] ![] = if ok v = true then List.replicate (depth v + 1) true else [false]hok:ok v = truehv:combSem ![v] ![] = List.replicate (depth v + 1) truehsplit: (d : ), d = 0 d = 1 m, d = m + 2m:hm:depth v = m + 2(match (List.replicate (m + 2 + 1) true).tail.tail with | [] => [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)) = true then List.replicate (m + 2 - 1 + 1) true else [false]; All goals completed! 🐙

The one-test at an arbitrary environment is the test at the canonical one.

theorem eqOneSem_env (f : Fin 0 List Bool) (g : Fin 1 List Bool) : eqOneSem f g = eqOneSem ![] ![g 0] := f:Fin 0 List Boolg:Fin 1 List BooleqOneSem f g = eqOneSem ![] ![g 0] f:Fin 0 List Boolg:Fin 1 List Boolhf:f = ![]eqOneSem f g = eqOneSem ![] ![g 0] f:Fin 0 List Boolg:Fin 1 List Boolhf:f = ![]hg:g = ![g 0]eqOneSem f g = eqOneSem ![] ![g 0] conv_lhs => f:Fin 0 List Boolg:Fin 1 List Boolhf:f = ![]hg:g = ![g 0]| eqOneSem ![] ![g 0]

The one-test accepts exactly the bitstrings of length one. It is not a recursion, so its three cases are decided by matching.

theorem eqOneSem_eq (u : List Bool) : eqOneSem ![] ![u] = if u.length = 1 then [true] else [] := u:List BooleqOneSem ![] ![u] = if u.length = 1 then [true] else [] match u with u:List BooleqOneSem ![] ![[]] = if [].length = 1 then [true] else [] All goals completed! 🐙 u:List Boolb:BooleqOneSem ![] ![[b]] = if [b].length = 1 then [true] else [] u:List BooleqOneSem ![] ![[false]] = if [false].length = 1 then [true] else []u:List BooleqOneSem ![] ![[true]] = if [true].length = 1 then [true] else [] u:List BooleqOneSem ![] ![[false]] = if [false].length = 1 then [true] else []u:List BooleqOneSem ![] ![[true]] = if [true].length = 1 then [true] else [] All goals completed! 🐙 u:List Boolb:Boolc:Boolv:List BooleqOneSem ![] ![b :: c :: v] = if (b :: c :: v).length = 1 then [true] else [] u:List Boolc:Boolv:List BooleqOneSem ![] ![false :: c :: v] = if (false :: c :: v).length = 1 then [true] else []u:List Boolc:Boolv:List BooleqOneSem ![] ![true :: c :: v] = if (true :: c :: v).length = 1 then [true] else [] u:List Boolc:Boolv:List BooleqOneSem ![] ![false :: c :: v] = if (false :: c :: v).length = 1 then [true] else []u:List Boolc:Boolv:List BooleqOneSem ![] ![true :: c :: v] = if (true :: c :: v).length = 1 then [true] else [] u:List Boolv:List BooleqOneSem ![] ![true :: false :: v] = if (true :: false :: v).length = 1 then [true] else []u:List Boolv:List BooleqOneSem ![] ![true :: true :: v] = if (true :: true :: v).length = 1 then [true] else [] u:List Boolv:List BooleqOneSem ![] ![false :: false :: v] = if (false :: false :: v).length = 1 then [true] else []u:List Boolv:List BooleqOneSem ![] ![false :: true :: v] = if (false :: true :: v).length = 1 then [true] else []u:List Boolv:List BooleqOneSem ![] ![true :: false :: v] = if (true :: false :: v).length = 1 then [true] else []u:List Boolv:List BooleqOneSem ![] ![true :: true :: v] = if (true :: true :: v).length = 1 then [true] else [] (u:List Boolv:List Bool[] = if (true :: true :: v).length = 1 then [true] else [] All goals completed! 🐙)

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.

theorem isTreeSem_apply (w : List Bool) : isTreeSem ![w] ![] = eqOneSem (fun _ []) (fun _ (combSem ![w] ![]).tail) := rfl

The recognizer accepts exactly the words binRanked's scan accepts.

theorem isTreeSem_eq_singleton_iff_valid (w : List Bool) : isTreeSem ![w] ![] = [true] binRanked.Valid w := w:List BoolisTreeSem ![w] ![] = [true] binRanked.Valid w w:List BooleqOneSem ![] ![(combSem ![w] ![]).tail] = [true] binRanked.Valid w w:List Bool(if (if ok w = true then List.replicate (depth w + 1) true else [false]).tail.length = 1 then [true] else []) = [true] binRanked.Valid w w:List Boolh:ok w = true(if (if ok w = true then List.replicate (depth w + 1) true else [false]).tail.length = 1 then [true] else []) = [true] binRanked.Valid ww:List Boolh:¬ok w = true(if (if ok w = true then List.replicate (depth w + 1) true else [false]).tail.length = 1 then [true] else []) = [true] binRanked.Valid w w:List Boolh:ok w = true(if (if ok w = true then List.replicate (depth w + 1) true else [false]).tail.length = 1 then [true] else []) = [true] binRanked.Valid w w:List Boolh:ok w = true(if (List.replicate (depth w + 1) true).tail.length = 1 then [true] else []) = [true] binRanked.Valid w w:List Boolh:ok w = true(if depth w = 1 then [true] else []) = [true] binRanked.Valid w w:List Boolh:ok w = truehd:depth w = 1(if depth w = 1 then [true] else []) = [true] binRanked.Valid ww:List Boolh:ok w = truehd:¬depth w = 1(if depth w = 1 then [true] else []) = [true] binRanked.Valid w w:List Boolh:ok w = truehd:depth w = 1(if depth w = 1 then [true] else []) = [true] binRanked.Valid w w:List Boolh:ok w = truehd:depth w = 1[true] = [true] binRanked.Valid w All goals completed! 🐙 w:List Boolh:ok w = truehd:¬depth w = 1(if depth w = 1 then [true] else []) = [true] binRanked.Valid w w:List Boolh:ok w = truehd:¬depth w = 1[] = [true] binRanked.Valid w refine fun hw absurd hw (w:List Boolh:ok w = truehd:¬depth w = 1hw:[] = [true]¬[] = [true] All goals completed! 🐙), ?_ w:List Boolh:ok w = truehd:¬depth w = 1hv:binRanked.Valid w[] = [true] All goals completed! 🐙 w:List Boolh:¬ok w = true(if (if ok w = true then List.replicate (depth w + 1) true else [false]).tail.length = 1 then [true] else []) = [true] binRanked.Valid w w:List Boolh:¬ok w = true[] = [true] binRanked.Valid w refine fun hw absurd hw (w:List Boolh:¬ok w = truehw:[] = [true]¬[] = [true] All goals completed! 🐙), ?_ w:List Boolh:¬ok w = truehv:binRanked.Valid w[] = [true] All goals completed! 🐙

The recognizer accepts exactly the preorder spellings of binRanked's terms.

theorem isTreeSem_eq_singleton_iff_exists_spell (w : List Bool) : isTreeSem ![w] ![] = [true] t, binRanked.spell t = w := (isTreeSem_eq_singleton_iff_valid w).trans (binRanked.valid_iff_exists_spell w)

The recognizer is the indicator of binRanked's scan: [true] on a spelling and [] on anything else. isTreeSem_eq_singleton_iff_valid pins the value only where it accepts.

theorem isTreeSem_eq_ite (w : List Bool) : isTreeSem ![w] ![] = if binRanked.Valid w then [true] else [] := w:List BoolisTreeSem ![w] ![] = if binRanked.Valid w then [true] else [] w:List Bool(if (if ok w = true then List.replicate (depth w + 1) true else [false]).tail.length = 1 then [true] else []) = if binRanked.Valid w then [true] else [] w:List Boolh:ok w = true(if (if ok w = true then List.replicate (depth w + 1) true else [false]).tail.length = 1 then [true] else []) = if binRanked.Valid w then [true] else []w:List Boolh:¬ok w = true(if (if ok w = true then List.replicate (depth w + 1) true else [false]).tail.length = 1 then [true] else []) = if binRanked.Valid w then [true] else [] w:List Boolh:ok w = true(if (if ok w = true then List.replicate (depth w + 1) true else [false]).tail.length = 1 then [true] else []) = if binRanked.Valid w then [true] else [] w:List Boolh:ok w = true(if (List.replicate (depth w + 1) true).tail.length = 1 then [true] else []) = if binRanked.Valid w then [true] else [] w:List Boolh:ok w = true(if depth w = 1 then [true] else []) = if binRanked.Valid w then [true] else [] w:List Boolh:ok w = truehd:depth w = 1(if depth w = 1 then [true] else []) = if binRanked.Valid w then [true] else []w:List Boolh:ok w = truehd:¬depth w = 1(if depth w = 1 then [true] else []) = if binRanked.Valid w then [true] else [] w:List Boolh:ok w = truehd:depth w = 1(if depth w = 1 then [true] else []) = if binRanked.Valid w then [true] else [] All goals completed! 🐙 w:List Boolh:ok w = truehd:¬depth w = 1(if depth w = 1 then [true] else []) = if binRanked.Valid w then [true] else [] All goals completed! 🐙 w:List Boolh:¬ok w = true(if (if ok w = true then List.replicate (depth w + 1) true else [false]).tail.length = 1 then [true] else []) = if binRanked.Valid w then [true] else [] All goals completed! 🐙
endend BellantoniCook