Documentation

LeanPool.PureNock.Verb

Verbs and local transitions #

Def:verb–selection (main.tex:1034–1112); D/OP (1055–1076); Def:NockProgram (1090–1098); operators (1514–1626); Nock (1639–1661).

inductive Nock.Action :

Def:verb (main.tex:1034–1040). Alphabet X := ⟨?,=,/,#,−⟩; actions from X ∪ {*,⊥}.

Instances For
    @[instance_reducible]
    Equations
    @[instance_reducible]
    Equations

    Is an action the null element ⊥?

    Equations
    Instances For

      Is an action one of the operators in X (as opposed to ⊥ or *)?

      Equations
      Instances For
        inductive Nock.Verb :

        Def:verb (main.tex:1034–1040). verb := (actions, noun) ∈ (X ∪ {*,⊥})^{λ−1} × N^λ(F); terminal iff actions all ⊥.

        Instances For
          Equations
          • One or more equations did not get rendered due to their size.
          Instances For
            @[instance_reducible]
            Equations
            def Nock.instDecidableEqVerb.decEq (x✝ x✝¹ : Verb) :
            Decidable (x✝ = x✝¹)
            Equations
            Instances For

              The underlying noun (snd of the verb pair): forget the action labels.

              Equations
              Instances For

                Number of leaves λ of the verb's noun.

                Equations
                Instances For

                  type (main.tex:1045): is the underlying noun a cell?

                  Equations
                  Instances For

                    Root action, if the verb is a cell (none at a leaf — leaves carry no action).

                    Equations
                    Instances For

                      Is the root action a pending *?

                      Equations
                      Instances For

                        Does the root node carry a pending (non-⊥) action? * or any operator counts; a leaf or a ⊥-node does not.

                        Equations
                        Instances For

                          Def:verb (main.tex:1039). verb is (fully) executed or in terminal state if its actions array consists only of ⊥.

                          Equations
                          Instances For

                            Selection (main.tex:1103–1112) #

                            Selection (main.tex:1103–1112). map := DFS; index of each internal node is the order a DFS from the root first explores it, excluding leaves.

                            Equations
                            Instances For

                              All (index, subverb) pairs of internal nodes, in DFS pre-order.

                              Equations
                              Instances For

                                Find the verb at an index in a list of enumerated internal nodes.

                                Equations
                                Instances For
                                  def Nock.Verb.map (i : Nat) (v : Verb) :

                                  Selection (main.tex:1103–1112). map := DFS: returns the verb at internal-node index i ∈ [λ−1].

                                  Equations
                                  Instances For

                                    Greatest index of a pending verb in an enumerated list of internal nodes.

                                    Equations
                                    Instances For

                                      Selection (main.tex:1103–1112). getIndex^Λ(F) = argmax_{map(i,F) ∈ NockProgram^Λ}(map(i,F)); F₁ >_F F₂ ⇔ i₁ > i₂.

                                      Equations
                                      Instances For
                                        def Nock.Verb.replaceAux (i : Nat) (new : Verb) :
                                        Verb → Nat → Nat × Verb

                                        Rebuild v, replacing the internal node at DFS index i by new.

                                        Equations
                                        Instances For
                                          def Nock.Verb.replaceAt (i : Nat) (v new : Verb) :

                                          Splice: replace the subverb at DFS index i with new.

                                          Equations
                                          Instances For

                                            Computable opcode domain D (main.tex:1055–1083) #

                                            type(i) = atom ∧ i ∈ [11], or type(i) = cell (⇒ the cons opcode).

                                            Equations
                                            Instances For

                                              Algorithm:Opcode_Updates_verb domain D (main.tex:1055–1058, 1078–1083). D := {v := (a,n) | n := [n₁,[i,n₂]], (i∈[11]) ∪ (type(i)=cell), a₁=⟨*⟩, ∀j≠1 aⱼ=⟨⊥⟩}; (1) v := *[n₁,[i,n₂]]; (2) n₁,[i,n₂] terminal; (3) i atom in [11] or cell.

                                              Equations
                                              Instances For

                                                A node ready for an operator-application step: it carries an operator from X and both of its argument subtrees are already in terminal state (note 2b). These are the operator redexes that the paper's App A transition algorithm elides.

                                                Equations
                                                Instances For

                                                  The full domain of the transition function next: opcode redexes (inOpcodeDomain, = the paper's D) together with ready operator nodes (opReady). See note 2c; Trace.domain (Lem:domain) concludes membership here.

                                                  Equations
                                                  Instances For

                                                    Opcode local rewrite (main.tex:1060–1076) #

                                                    Algorithm:Opcode_Updates_verb (main.tex:1060–1076). OP₀: *[n₁,[0,n₂]] → /(n₂,n₁); OP₁ → n₂; OP₂ → *[*[n₁,h],*[n₁,t]]; OP₃ → -[3,*[n₁,n₂]]; OP₄ → -[4,*[n₁,n₂]]; OP₅ → =(*[n₁,h],*[n₁,t]); OP₆ → *[n₁,*[t,[0,*[[2,3],[0,*[n₁,[4,[4,h]]]]]]]]; OP₇ → *[*[n₁,h],t]; OP₈ → *[[*[n₁,h],n₁],t]; OP₉ → *[*[n₁,t],2,[[0,1],0,h]]; OP₁₀ → #[hh,*[n₁,th],*[n₁,t]]; cons: *[n₁,[i,n₂]] → [*[n₁,i],*[n₁,n₂]].

                                                    Equations
                                                    Instances For

                                                      Operator-application steps (Algorithm:Noun_Operators / Unroll_Operator) #

                                                      Convert a plain noun into a terminal verb (all actions ⊥).

                                                      Equations
                                                      Instances For

                                                        Local rewrite (main.tex:1060–1076, 1514–1626) #

                                                        Algorithm:Noun_Operators / Unroll_Operator (main.tex:1514–1626). Local rewrite: * via opcodes, or =, /, #, - (-[3,·]=?, -[4,·]=+) on terminal args.

                                                        Equations
                                                        Instances For

                                                          One Nock step. Locate the pending redex of largest DFS index via getIndex/map; if it lies in the transition domain D (opcode redex or ready operator), apply the local rewrite (reduce) and splice the result back; otherwise crash (none). next v = none also when v is terminal (no pending action). Being a Lean function, next is deterministic — the concrete realization of the paper's "* is a deterministic mapping between program states".

                                                          Equations
                                                          • One or more equations did not get rendered due to their size.
                                                          Instances For

                                                            Executable paper interpreter — iterate next to a result (note 2, PLAN §2) #

                                                            def Nock.Verb.program (subject formula : Noun) :

                                                            Def:NockProgram (main.tex:1090–1098). F = *[subject, formula] with subject, formula terminal; NockProgram^Λ := {F | λ ≤ Λ}.

                                                            Equations
                                                            Instances For

                                                              Extract the observable output of a stuck verb: its underlying noun if it is in terminal state (a valid completion, main.tex:1123), else none (a crash / invalid completion, main.tex:1124).

                                                              Equations
                                                              Instances For

                                                                Fuel-indexed iteration of next from v to a terminal/⊥ state, returning the result noun (none on crash or fuel exhaustion). Nock is Turing-complete, so fuel is required for totality; none conflates a genuine crash with fuel exhaustion, exactly as evalN does.

                                                                Equations
                                                                Instances For
                                                                  def Nock.Verb.runProgram (fuel : Nat) (subject formula : Noun) :

                                                                  Run a Nock program *[subject, formula] through the paper's small-step interpreter.

                                                                  Equations
                                                                  Instances For

                                                                    Strictness of the DFS order (main.tex:1107) #

                                                                    theorem Nock.Verb.enum_ge_start (v : Verb) (c : Nat) :
                                                                    c ≤ (v.enum c).fst

                                                                    The DFS counter never decreases: (enum v c).1 ≥ c.

                                                                    theorem Nock.Verb.enum_index_range (v : Verb) (c : Nat) (p : Nat × Verb) :
                                                                    p ∈ (v.enum c).snd → c ≤ p.fst ∧ p.fst < (v.enum c).fst

                                                                    Every internal-node index produced by enum v c lies in the half-open counter range [c, (enum v c).1). Distinct nodes therefore receive distinct indices: the DFS map enforces a strict ordering on subtrees (main.tex:1107).

                                                                    DFS indices are distinct (main.tex:1107) #

                                                                    theorem Nock.Verb.findAt_append (i : Nat) (L1 L2 : List (Nat × Verb)) :
                                                                    findAt i (L1 ++ L2) = match findAt i L1 with | some v => some v | none => findAt i L2

                                                                    findAt over an append: the left list wins if it has a match.

                                                                    theorem Nock.Verb.findAt_eq_none {i : Nat} {L : List (Nat × Verb)} :
                                                                    (∀ (p : Nat × Verb), p ∈ L → p.fst ≠ i) → findAt i L = none

                                                                    If no pair in L carries index i, then findAt i L = none.

                                                                    theorem Nock.Verb.findAt_some_mem {i : Nat} {v : Verb} {L : List (Nat × Verb)} :
                                                                    findAt i L = some v → (i, v) ∈ L

                                                                    findAt i L = some v witnesses membership (i, v) ∈ L.

                                                                    theorem Nock.Verb.map_of_mem_nodes {a : Verb} {i : Nat} {v : Verb} (h : (i, v) ∈ a.nodes) :
                                                                    map i a = some v

                                                                    map retrieves the unique node at an index. If (i, v) is one of the DFS internal-node pairs of a, then map i a = some v. (Uses DFS distinctness, enum_findAt.)

                                                                    theorem Nock.Verb.mem_nodes_of_map {a : Verb} {i : Nat} {v : Verb} (h : map i a = some v) :

                                                                    Membership of the retrieved node: map i a = some v ⇒ (i, v) ∈ nodes a.

                                                                    getIndex = numeric argmax of pending indices (spec of maximumPendingIndex) #

                                                                    Strict redex-selection order (main.tex:1105-1109, 1156) #

                                                                    structure Nock.Verb.StrictSelect (lt : Nat → Nat → Prop) :

                                                                    A strict selection order on internal-node indices: a strict total order (the paper's "strict ordering", main.tex:1107). Irreflexive + transitive ⇒ asymmetric; total (connectedness) is what forbids ties, hence forces a unique maximum.

                                                                    • irrefl (i : Nat) : ¬lt i i
                                                                    • trans {i j k : Nat} : lt i j → lt j k → lt i k
                                                                    • total {i j : Nat} : i ≠ j → lt i j ∨ lt j i
                                                                    Instances For

                                                                      i is a pending internal-node index of a: map i a is a node with a pending (non-⊥) action.

                                                                      Equations
                                                                      Instances For
                                                                        def Nock.Verb.IsMaxPending (lt : Nat → Nat → Prop) (a : Verb) (i : Nat) :

                                                                        i is a maximal pending index of a under the order lt: a pending index that no other pending index exceeds. This is the paper's argmax characterization of getIndex.

                                                                        Equations
                                                                        Instances For
                                                                          def Nock.Verb.SelStep (lt : Nat → Nat → Prop) (a b : Verb) :

                                                                          An abstract redex-selection step: pick a maximal pending index i under lt, and if the selected subverb is in the transition domain, apply the local rewrite and splice it back. With no strictness assumption this relation can be multi-valued (several maximal redexes); SelStep.det shows a strict order collapses it to a function.

                                                                          Equations
                                                                          • One or more equations did not get rendered due to their size.
                                                                          Instances For
                                                                            theorem Nock.Verb.SelStep.det {lt : Nat → Nat → Prop} (hs : StrictSelect lt) {a b b' : Verb} (h : SelStep lt a b) (h' : SelStep lt a b') :
                                                                            b = b'

                                                                            Determinism from strictness. If lt is a strict total order, a redex-selection step is deterministic: hs.total forces the two selected indices to coincide; the rest is functionality of map/reduce/replaceAt.

                                                                            DFS instantiation: the concrete order is strict, and next realizes SelStep #

                                                                            @[reducible, inline]
                                                                            abbrev Nock.Verb.dfsLt :
                                                                            Nat → Nat → Prop

                                                                            The concrete DFS order on pre-order indices is the usual strict order on Nat.

                                                                            Equations
                                                                            Instances For

                                                                              The DFS index order is a strict total order. This is why map = DFS "enforces a strict ordering on subtrees" (main.tex:1107): distinct internal nodes get distinct Nat indices (enum_index_range/map_of_mem_nodes), and Nat.lt is a strict total order.

                                                                              Pending-index membership, in list form. The ← direction uses DFS distinctness (map_of_mem_nodes): a pending node in the nodes list is retrieved by map on its (unique) index.

                                                                              getIndex is exactly the DFS argmax: getIndex a = some i ↔ i is the maximal pending index under dfsLt. (Combines the maximumPendingIndex spec with DFS distinctness.)

                                                                              next faithfully realizes the strict DFS selection step. This is the bridge that makes deterministic_Trace an instance of the paper's conditional theorem: the concrete interpreter's step is SelStep for the (strict) DFS order.

                                                                              Non-strict selection witness (main.tex:2325) #

                                                                              The empty order — not total, hence not a StrictSelect. Every index is vacuously maximal under it.

                                                                              Equations
                                                                              Instances For

                                                                                A verb with two independent, equally-maximal redexes: two copies of *[0, [1, 5]] (each an OP₁ redex reducing to 5), spliced under a ⊥ root.

                                                                                Equations
                                                                                • One or more equations did not get rendered due to their size.
                                                                                Instances For

                                                                                  Non-vacuity of strictness. Under a non-strict order, SelStep is not a function: it relates twoRedex to two distinct successors. Contrast SelStep.det, which uses StrictSelect.total to collapse exactly this ambiguity.

                                                                                  Terminal verbs cannot step (main.tex:1039, 1122) #

                                                                                  theorem Nock.Verb.enum_nonpending_of_terminal (v : Verb) :
                                                                                  v.isTerminal = true → ∀ (c : Nat) (p : Nat × Verb), p ∈ (v.enum c).snd → p.snd.isPending = false

                                                                                  Every internal node produced by enum of a terminal verb is non-pending.

                                                                                  getIndex of a terminal verb is none: no internal node carries a pending action.

                                                                                  A terminal verb cannot take a Nock step.

                                                                                  Converses: no pending redex ⇒ terminal (main.tex:1122) #

                                                                                  theorem Nock.Verb.terminal_of_enum_nonpending (v : Verb) (c : Nat) :
                                                                                  (∀ (p : Nat × Verb), p ∈ (v.enum c).snd → p.snd.isPending = false) → v.isTerminal = true

                                                                                  Converse of enum_nonpending_of_terminal. If every internal node enumerated from v is non-pending, then v is terminal.

                                                                                  theorem Nock.Verb.enum_subtree_mem (v : Verb) (c i : Nat) (sub : Verb) :
                                                                                  (i, sub) ∈ (v.enum c).snd → ∀ (p : Nat × Verb), p ∈ (sub.enum i).snd → p ∈ (v.enum c).snd

                                                                                  Subtree enumeration embeds. If sub is enumerated at index i within v (counter c), then every internal node of sub's own enumeration (counter i) also appears in v's enumeration. This is what lets a pending node inside the selected redex be seen as a pending index of the whole verb.

                                                                                  theorem Nock.Verb.children_terminal_of_getIndex {v : Verb} {i : Nat} {a : Action} {l r : Verb} (hidx : v.getIndex = some i) (hmap : map i v = some (node a l r)) :

                                                                                  The selected redex has terminal children. If getIndex v = some i picks the argmax pending node map i v = node a l r, then l and r are terminal: any pending node below them would have a strictly larger DFS index (enum_index_range + enum_subtree_mem), contradicting maximality (getIndex_eq_some_iff). This is the shape inDomain/reduce need at the redex.

                                                                                  NockVMROM without OP₁₀ (main.tex:1160) #

                                                                                  The ROM local rewrite: identical to reduce except every part of OP₁₀ (edit, # — main.tex:1071,1587) is rejected (none = crash), removing the ability to write to memory. Two things are excluded, exactly the two halves of OP₁₀ in our two-step encoding (note 2b): (i) the OP₁₀ opcode redex *[n₁,[10,n₂]] (i = 10), and (ii) the edit operator node it produces (#, the actual memory write). No other opcode produces edit, so this removes OP₁₀ and nothing else.

                                                                                  Equations
                                                                                  Instances For

                                                                                    One NockVMROM step: exactly next, but using reduceROM for the local rewrite, so a selected OP₁₀ redex (or a stray edit node) crashes. Every non-crashing ROM step is a genuine Nock step (next_of_nextROM).

                                                                                    Equations
                                                                                    • One or more equations did not get rendered due to their size.
                                                                                    Instances For

                                                                                      A terminal verb cannot take a ROM step either.

                                                                                      reduceROM refines reduce: whenever the ROM rewrite succeeds, the full Nock rewrite agrees (they differ only on OP₁₀, where reduceROM returns none).

                                                                                      theorem Nock.Verb.next_of_nextROM {v w : Verb} (h : v.nextROM = some w) :
                                                                                      v.next = some w

                                                                                      Every ROM transition is a Nock transition. nextROM is a restriction of next (OP₁₀ removed): if nextROM v = some w then next v = some w. This is the verb-level sense in which NockVMROM is NockVM without OP₁₀.

                                                                                      Two-verb transition checker Nock (main.tex:1639–1661) #

                                                                                      def Nock.Verb.NockCheck (Ti : Verb) (Tnext : Option Verb) :

                                                                                      Algorithm:Transition_Function (main.tex:1639–1661). Nock(Tᵢ,Tᵢ₊₁): Fᵢ ← map(Tᵢ,getIndex(Tᵢ)); frame Tᵢ\Fᵢ = Tᵢ₊₁\Fᵢ₊₁; accept (0) iff Fᵢ₊₁ = OP:Fᵢ / cons:Fᵢ, or Fᵢ₊₁=⊥ when out of domain.

                                                                                      Equations
                                                                                      • One or more equations did not get rendered due to their size.
                                                                                      Instances For

                                                                                        Ti crashes. Ti selects a pending redex (getIndex Ti ≠ none, so Ti is not terminal, main.tex:1039) but that redex is out of the transition domain / does not reduce, so its only consistent successor is ⊥ (main.tex:1644,1650). Equivalently next Ti = none together with a pending redex.

                                                                                        Equations
                                                                                        Instances For
                                                                                          theorem Nock.Verb.map_some_of_getIndex {a : Verb} {i : Nat} (h : a.getIndex = some i) :
                                                                                          ∃ (sub : Verb), map i a = some sub

                                                                                          getIndex a = some i names an actual internal node: map i a succeeds. (The argmax is achieved at a pending node, which map retrieves by DFS distinctness.)

                                                                                          NockCheck ↔ forward semantics + crash. The two-verb checker accepts (a, b) (returns true = the paper's 0) iff b is a genuine one-step successor of a (next a = some v, i.e. Step a v) OR a crashes and b = ⊥ (b = none). This is a genuine biconditional: NockCheck is 1-1 with next (on non-⊥ successors) together with the crash branch — the checker Nock(Tᵢ,Tᵢ₊₁)=0 and the forward map coincide exactly.

                                                                                          Frame-invariance gate (main.tex:1642) #

                                                                                          def Nock.Verb.FrameAgree (i : Nat) (Ti Tj : Verb) :

                                                                                          Frame agreement at index i: Tj is Ti with the subverb at DFS index i replaced by some Fj — so Ti and Tj share the same frame (context) outside i. This is the map-complement equality Ti \ Fᵢ = Tj \ Fⱼ (main.tex:1642).

                                                                                          Equations
                                                                                          Instances For

                                                                                            Accepted steps pass the frame gate (main.tex:1642). If NockCheck accepts a non-⊥ successor b of a, then b agrees with a outside the selected index: FrameAgree. (The genuine-step branch of NockCheck is exactly the frame-preserving splice.)

                                                                                            Verifiable crash — a three-way outcome (value / crash / timeout) #

                                                                                            run/runProgram return Option Noun, collapsing a genuine crash (a stuck, non-terminal ⊥ state, main.tex:1124) and fuel exhaustion into the same none. eval refines that: it mirrors run's fuel structure exactly, but at a halt (next v = none) it reports value (a terminal completion) or crash (a checked ⊥) instead of some/none; only a genuinely-steppable state can timeout. A crash thus becomes a positive, kernel-checkable outcome, not merely the absence of a value.

                                                                                            Result of running a verb to a normal form.

                                                                                            Instances For
                                                                                              Equations
                                                                                              Instances For

                                                                                                The halting outcome of a stopped verb (next v = none): its noun if terminal (a valid completion), else a crash (an invalid completion, main.tex:1124).

                                                                                                Equations
                                                                                                Instances For

                                                                                                  A non-terminal halt is a crash.

                                                                                                  Fuel-indexed evaluation distinguishing a crash from fuel exhaustion. Structurally identical to run, so eval and run agree on values at the same fuel (eval_value_iff_run); the crash branch turns run's conflated none into a positive crash.

                                                                                                  Equations
                                                                                                  Instances For
                                                                                                    def Nock.Verb.evalProgram (fuel : Nat) (subject formula : Noun) :

                                                                                                    Run a Nock program *[subject, formula], reporting value / crash / timeout.

                                                                                                    Equations
                                                                                                    Instances For
                                                                                                      theorem Nock.Verb.eval_succ (n : Nat) (v : Verb) :
                                                                                                      eval (n + 1) v = match v.next with | some v' => eval n v' | none => v.haltOutcome

                                                                                                      One-step unfolding of eval (definitional), to avoid over-unfolding nested eval calls.

                                                                                                      theorem Nock.Verb.eval_value_iff_run {n : Nat} {v : Verb} {r : Noun} :

                                                                                                      Values are preserved exactly. eval yields value r at fuel n iff the Option-valued run yields some r at the same fuel — successful evaluation is unchanged.

                                                                                                      theorem Nock.Verb.eval_crash_mono {n : Nat} {v : Verb} (h : eval n v = Outcome.crash) :

                                                                                                      Crash is stable one step on: if eval reports crash at fuel n, it reports crash at n + 1. (The general "any larger fuel" form is eval_crash_mono_le.)

                                                                                                      theorem Nock.Verb.eval_crash_mono_le {n m : Nat} {v : Verb} (hnm : n ≤ m) (h : eval n v = Outcome.crash) :

                                                                                                      Crash is permanent (so a single successful eval certifies it at every fuel): once eval reports crash at fuel n, it reports crash at every m ≥ n.