8. Theory Design and Implementation
-
LaPToP.TheoryDesign.DataStackTheory[complete] -
LaPToP.TheoryDesign.DataStackTheory.construction[complete] -
LaPToP.TheoryDesign.DataStackTheory.construction_pred[complete] -
LaPToP.TheoryDesign.DataStackTheory.induction_bunch[complete] -
LaPToP.TheoryDesign.DataStackTheory.eq_empty_or_push[complete] -
LaPToP.TheoryDesign.DataStackTheory.push_inj_of_lifo[complete] -
LaPToP.TheoryDesign.WeakStackTheory[complete] -
LaPToP.TheoryDesign.DataStackTheory.toWeak[complete] -
LaPToP.TheoryDesign.unitStack[complete] -
LaPToP.TheoryDesign.unitStack_push_eq_empty[complete]
"We introduce the syntax \mathit{stack}, \mathit{empty}, \mathit{push},
\mathit{pop}, and \mathit{top}." The axioms: \mathit{empty} : \mathit{stack},
\mathit{push} : \mathit{stack} \to X \to \mathit{stack}, \mathit{pop} : \mathit{stack} \to \mathit{stack},
\mathit{top} : \mathit{stack} \to X; construction
\mathit{empty}, \mathit{push}\ \mathit{stack}\ X : \mathit{stack} (equivalently
P\,\mathit{empty} \land (\forall s : \mathit{stack} \cdot \forall x : X \cdot P\,s \Rightarrow P(\mathit{push}\ s\ x)) \Leftarrow \forall s : \mathit{stack} \cdot P\,s);
induction \mathit{empty}, \mathit{push}\ B\ X : B \Rightarrow \mathit{stack} : B (equivalently
P\,\mathit{empty} \land (\forall s : \mathit{stack} \cdot \forall x : X \cdot P\,s \Rightarrow P(\mathit{push}\ s\ x)) \Rightarrow \forall s : \mathit{stack} \cdot P\,s),
"to exclude anything else from being a stack"; "to say that the constructors
always construct different stacks", \mathit{push}\ s\ x \neq \mathit{empty} and
\mathit{push}\ s\ x = \mathit{push}\ t\ y = (s = t \land x = y); and "last in, first
out": \mathit{pop}(\mathit{push}\ s\ x) = s, \mathit{top}(\mathit{push}\ s\ x) = x. A theory
is a Lean structure DataStackTheory X — a carrier type (the bunch
\mathit{stack}, taken as a type so that the operations are total on it), the
four operations, and the axioms as fields; construction is automatic for a
type, and both predicate forms are proved. Consequences: every stack is
\mathit{empty} or a \mathit{push}, and the LIFO axioms alone make
\mathit{push} injective. "According to the axioms we have so far" — before the
last four — "it is possible that all stacks are equal": the one-element carrier
satisfies the weak axioms, so \mathit{push}\ s\ x \neq \mathit{empty} is independent of
them. Uses Definition 2.1, Definition 3.1 and
Theorem 7.2.
Lean code for Definition8.1●10 declarations
Associated Lean declarations
-
LaPToP.TheoryDesign.DataStackTheory[complete]
-
LaPToP.TheoryDesign.DataStackTheory.construction[complete]
-
LaPToP.TheoryDesign.DataStackTheory.construction_pred[complete]
-
LaPToP.TheoryDesign.DataStackTheory.induction_bunch[complete]
-
LaPToP.TheoryDesign.DataStackTheory.eq_empty_or_push[complete]
-
LaPToP.TheoryDesign.DataStackTheory.push_inj_of_lifo[complete]
-
LaPToP.TheoryDesign.WeakStackTheory[complete]
-
LaPToP.TheoryDesign.DataStackTheory.toWeak[complete]
-
LaPToP.TheoryDesign.unitStack[complete]
-
LaPToP.TheoryDesign.unitStack_push_eq_empty[complete]
-
LaPToP.TheoryDesign.DataStackTheory[complete] -
LaPToP.TheoryDesign.DataStackTheory.construction[complete] -
LaPToP.TheoryDesign.DataStackTheory.construction_pred[complete] -
LaPToP.TheoryDesign.DataStackTheory.induction_bunch[complete] -
LaPToP.TheoryDesign.DataStackTheory.eq_empty_or_push[complete] -
LaPToP.TheoryDesign.DataStackTheory.push_inj_of_lifo[complete] -
LaPToP.TheoryDesign.WeakStackTheory[complete] -
LaPToP.TheoryDesign.DataStackTheory.toWeak[complete] -
LaPToP.TheoryDesign.unitStack[complete] -
LaPToP.TheoryDesign.unitStack_push_eq_empty[complete]
-
structuredefined in LaPToP/TheoryDesign/Stack.leancomplete
structure LaPToP.TheoryDesign.DataStackTheory.{u, v} (X : Type u) : Type (max u (v + 1))
structure LaPToP.TheoryDesign.DataStackTheory.{u, v} (X : Type u) : Type (max u (v + 1))
A *data-stack theory* over items `X` (aPToP §7.0.0): the syntax `stack`, `empty`, `push`, `pop`, `top` together with the data-stack axioms.
Fields
Stack : Type v
`stack`, "a bunch consisting of all stacks of items of type `X`".
empty : self.Stack
`empty: stack`, "a stack containing no items".
push : self.Stack → X → self.Stack
`push: stack→X→stack`, "the stack containing the same items plus the one new item".
pop : self.Stack → self.Stack
`pop: stack→stack`, "the stack minus the newest remaining item".
top : self.Stack → X
`top: stack→X`, "the newest remaining item".
induction : ∀ (P : self.Stack → Prop), P self.empty → (∀ (s : self.Stack) (x : X), P s → P (self.push s x)) → ∀ (s : self.Stack), P s
Induction: `P empty ∧ (∀s: stack· ∀x: X· P s ⇒ P (push s x)) ⇒ ∀s: stack· P s` — "to exclude anything else from being a stack".
push_ne_empty : ∀ (s : self.Stack) (x : X), self.push s x ≠ self.empty
`push s x ⧧ empty`: "the constructors always construct different stacks".
push_inj : ∀ (s t : self.Stack) (x y : X), self.push s x = self.push t y ↔ s = t ∧ x = y
`push s x = push t y = s=t ∧ x=y`.
pop_push : ∀ (s : self.Stack) (x : X), self.pop (self.push s x) = s
`pop (push s x) = s` ("last in, first out").top_push : ∀ (s : self.Stack) (x : X), self.top (self.push s x) = x
`top (push s x) = x` ("last in, first out"). -
theoremdefined in LaPToP/TheoryDesign/Stack.leancomplete
theorem LaPToP.TheoryDesign.DataStackTheory.construction.{u, u_1} {X : Type u} (T : LaPToP.TheoryDesign.DataStackTheory X) (s : T.Stack) (x : X) : T.push s x ∈ Set.univ
theorem LaPToP.TheoryDesign.DataStackTheory.construction.{u, u_1} {X : Type u} (T : LaPToP.TheoryDesign.DataStackTheory X) (s : T.Stack) (x : X) : T.push s x ∈ Set.univ
The construction axiom `empty, push stack X: stack`: automatic, since the carrier is a type.
-
theoremdefined in LaPToP/TheoryDesign/Stack.leancomplete
theorem LaPToP.TheoryDesign.DataStackTheory.construction_pred.{u, u_1} {X : Type u} (T : LaPToP.TheoryDesign.DataStackTheory X) (P : T.Stack → Prop) (h : ∀ (s : T.Stack), P s) : P T.empty ∧ ∀ (s : T.Stack) (x : X), P s → P (T.push s x)
theorem LaPToP.TheoryDesign.DataStackTheory.construction_pred.{u, u_1} {X : Type u} (T : LaPToP.TheoryDesign.DataStackTheory X) (P : T.Stack → Prop) (h : ∀ (s : T.Stack), P s) : P T.empty ∧ ∀ (s : T.Stack) (x : X), P s → P (T.push s x)
The predicate form of construction: `P empty ∧ (∀s: stack· ∀x: X· P s ⇒ P (push s x)) ⇐ ∀s: stack· P s`.
-
theoremdefined in LaPToP/TheoryDesign/Stack.leancomplete
theorem LaPToP.TheoryDesign.DataStackTheory.induction_bunch.{u, u_1} {X : Type u} (T : LaPToP.TheoryDesign.DataStackTheory X) (B : LaPToP.BasicTheories.Bunch T.Stack) (h0 : T.empty ∈ B) (hs : ∀ s ∈ B, ∀ (x : X), T.push s x ∈ B) : Set.univ ⊆ B
theorem LaPToP.TheoryDesign.DataStackTheory.induction_bunch.{u, u_1} {X : Type u} (T : LaPToP.TheoryDesign.DataStackTheory X) (B : LaPToP.BasicTheories.Bunch T.Stack) (h0 : T.empty ∈ B) (hs : ∀ s ∈ B, ∀ (x : X), T.push s x ∈ B) : Set.univ ⊆ B
The bunch form of induction: `empty, push B X: B ⇒ stack: B`.
-
theoremdefined in LaPToP/TheoryDesign/Stack.leancomplete
theorem LaPToP.TheoryDesign.DataStackTheory.eq_empty_or_push.{u, u_1} {X : Type u} (T : LaPToP.TheoryDesign.DataStackTheory X) (s : T.Stack) : s = T.empty ∨ ∃ t x, s = T.push t x
theorem LaPToP.TheoryDesign.DataStackTheory.eq_empty_or_push.{u, u_1} {X : Type u} (T : LaPToP.TheoryDesign.DataStackTheory X) (s : T.Stack) : s = T.empty ∨ ∃ t x, s = T.push t x
Every stack is `empty` or a `push`.
-
theoremdefined in LaPToP/TheoryDesign/Stack.leancomplete
theorem LaPToP.TheoryDesign.DataStackTheory.push_inj_of_lifo.{u, u_1} {X : Type u} (T : LaPToP.TheoryDesign.DataStackTheory X) (s t : T.Stack) (x y : X) (h : T.push s x = T.push t y) : s = t ∧ x = y
theorem LaPToP.TheoryDesign.DataStackTheory.push_inj_of_lifo.{u, u_1} {X : Type u} (T : LaPToP.TheoryDesign.DataStackTheory X) (s t : T.Stack) (x y : X) (h : T.push s x = T.push t y) : s = t ∧ x = y
`push` is injective in both arguments — a consequence of the LIFO axioms alone (`pop` and `top` recover the arguments), so the second "different stacks" axiom is derivable from them.
-
structuredefined in LaPToP/TheoryDesign/Stack.leancomplete
structure LaPToP.TheoryDesign.WeakStackTheory.{u, v} (X : Type u) : Type (max u (v + 1))
structure LaPToP.TheoryDesign.WeakStackTheory.{u, v} (X : Type u) : Type (max u (v + 1))
The first six axioms of data-stack theory: typing, construction (automatic) and induction.
Fields
Stack : Type v
The carrier.
empty : self.Stack
`empty`.
push : self.Stack → X → self.Stack
`push`.
pop : self.Stack → self.Stack
`pop`.
top : self.Stack → X
`top`.
induction : ∀ (P : self.Stack → Prop), P self.empty → (∀ (s : self.Stack) (x : X), P s → P (self.push s x)) → ∀ (s : self.Stack), P s
Induction.
-
defdefined in LaPToP/TheoryDesign/Stack.leancomplete
def LaPToP.TheoryDesign.DataStackTheory.toWeak.{u, u_1} {X : Type u} (T : LaPToP.TheoryDesign.DataStackTheory X) : LaPToP.TheoryDesign.WeakStackTheory X
def LaPToP.TheoryDesign.DataStackTheory.toWeak.{u, u_1} {X : Type u} (T : LaPToP.TheoryDesign.DataStackTheory X) : LaPToP.TheoryDesign.WeakStackTheory X
Every data-stack theory is in particular a weak one.
-
defdefined in LaPToP/TheoryDesign/Stack.leancomplete
def LaPToP.TheoryDesign.unitStack.{u} (X : Type u) [Inhabited X] : LaPToP.TheoryDesign.WeakStackTheory X
def LaPToP.TheoryDesign.unitStack.{u} (X : Type u) [Inhabited X] : LaPToP.TheoryDesign.WeakStackTheory X
The one-element model of the weak axioms, in which all stacks are equal.
-
theoremdefined in LaPToP/TheoryDesign/Stack.leancomplete
theorem LaPToP.TheoryDesign.unitStack_push_eq_empty.{u} (X : Type u) [Inhabited X] (s : (LaPToP.TheoryDesign.unitStack X).Stack) (x : X) : (LaPToP.TheoryDesign.unitStack X).push s x = (LaPToP.TheoryDesign.unitStack X).empty
theorem LaPToP.TheoryDesign.unitStack_push_eq_empty.{u} (X : Type u) [Inhabited X] (s : (LaPToP.TheoryDesign.unitStack X).Stack) (x : X) : (LaPToP.TheoryDesign.unitStack X).push s x = (LaPToP.TheoryDesign.unitStack X).empty
In the one-element model `push s x = empty`: the "different stacks" axiom `push s x ⧧ empty` is not a consequence of the weak axioms.
-
LaPToP.TheoryDesign.ListStack.empty[complete] -
LaPToP.TheoryDesign.ListStack.push[complete] -
LaPToP.TheoryDesign.ListStack.pop[complete] -
LaPToP.TheoryDesign.ListStack.top[complete] -
LaPToP.TheoryDesign.ListStack.push_contents[complete] -
LaPToP.TheoryDesign.ListStack.push_ne_empty[complete] -
LaPToP.TheoryDesign.ListStack.induction[complete] -
LaPToP.TheoryDesign.ListStack.pop_push[complete] -
LaPToP.TheoryDesign.ListStack.top_push[complete] -
LaPToP.TheoryDesign.ListStack.push_inj[complete] -
LaPToP.TheoryDesign.ListStack.theory[complete]
"Suppose that lists and functions are implemented. Then we can implement a
stack of integers by the following definitions: \mathit{stack} = [*\mathit{int}],
\mathit{empty} = [\mathit{nil}], \mathit{push} = \langle s : \mathit{stack} \cdot \langle x : \mathit{int} \cdot s ;; [x] \rangle\rangle,
\mathit{pop} = \langle s : \mathit{stack} \cdot \mathbf{if}\ s = \mathit{empty}\ \mathbf{then}\ \mathit{empty}\ \mathbf{else}\ s\,[0;..\# s - 1] \rangle,
\mathit{top} = \langle s : \mathit{stack} \cdot \mathbf{if}\ s = \mathit{empty}\ \mathbf{then}\ 0\ \mathbf{else}\ s\,(\# s - 1) \rangle.
To prove that a theory is implemented, we prove (the axioms of the theory)
\Leftarrow (the definitions of the implementation). ... According to a
distributive law, this can be done one axiom at a time." The book's worked
calculation is \mathit{top}(\mathit{push}\ s\ x) = x; here every axiom is proved and the
implementation is a term of type DataStackTheory ℤ — the induction axiom by
induction on lists from the right. "Since we implemented it using list and
function theory, we know that if list and function theory are consistent, so
is stack theory." Uses Definition 8.1, Definition 4.9
and Theorem 4.10.
Lean code for Theorem8.2●11 declarations
Associated Lean declarations
-
LaPToP.TheoryDesign.ListStack.empty[complete]
-
LaPToP.TheoryDesign.ListStack.push[complete]
-
LaPToP.TheoryDesign.ListStack.pop[complete]
-
LaPToP.TheoryDesign.ListStack.top[complete]
-
LaPToP.TheoryDesign.ListStack.push_contents[complete]
-
LaPToP.TheoryDesign.ListStack.push_ne_empty[complete]
-
LaPToP.TheoryDesign.ListStack.induction[complete]
-
LaPToP.TheoryDesign.ListStack.pop_push[complete]
-
LaPToP.TheoryDesign.ListStack.top_push[complete]
-
LaPToP.TheoryDesign.ListStack.push_inj[complete]
-
LaPToP.TheoryDesign.ListStack.theory[complete]
-
LaPToP.TheoryDesign.ListStack.empty[complete] -
LaPToP.TheoryDesign.ListStack.push[complete] -
LaPToP.TheoryDesign.ListStack.pop[complete] -
LaPToP.TheoryDesign.ListStack.top[complete] -
LaPToP.TheoryDesign.ListStack.push_contents[complete] -
LaPToP.TheoryDesign.ListStack.push_ne_empty[complete] -
LaPToP.TheoryDesign.ListStack.induction[complete] -
LaPToP.TheoryDesign.ListStack.pop_push[complete] -
LaPToP.TheoryDesign.ListStack.top_push[complete] -
LaPToP.TheoryDesign.ListStack.push_inj[complete] -
LaPToP.TheoryDesign.ListStack.theory[complete]
-
defdefined in LaPToP/TheoryDesign/Stack.leancomplete
def LaPToP.TheoryDesign.ListStack.empty : LaPToP.DataStructures.HList ℤ
def LaPToP.TheoryDesign.ListStack.empty : LaPToP.DataStructures.HList ℤ
`empty = [nil]`.
-
defdefined in LaPToP/TheoryDesign/Stack.leancomplete
def LaPToP.TheoryDesign.ListStack.push (s : LaPToP.DataStructures.HList ℤ) (x : ℤ) : LaPToP.DataStructures.HList ℤ
def LaPToP.TheoryDesign.ListStack.push (s : LaPToP.DataStructures.HList ℤ) (x : ℤ) : LaPToP.DataStructures.HList ℤ
`push s x = s;;[x]`.
-
defdefined in LaPToP/TheoryDesign/Stack.leancomplete
def LaPToP.TheoryDesign.ListStack.pop (s : LaPToP.DataStructures.HList ℤ) : LaPToP.DataStructures.HList ℤ
def LaPToP.TheoryDesign.ListStack.pop (s : LaPToP.DataStructures.HList ℤ) : LaPToP.DataStructures.HList ℤ
`pop s = if s=empty then empty else s [0;..#s–1]`.
-
defdefined in LaPToP/TheoryDesign/Stack.leancomplete
def LaPToP.TheoryDesign.ListStack.top (s : LaPToP.DataStructures.HList ℤ) : ℤ
def LaPToP.TheoryDesign.ListStack.top (s : LaPToP.DataStructures.HList ℤ) : ℤ
`top s = if s=empty then 0 else s (#s–1)`.
-
theoremdefined in LaPToP/TheoryDesign/Stack.leancomplete
theorem LaPToP.TheoryDesign.ListStack.push_contents (s : LaPToP.DataStructures.HList ℤ) (x : ℤ) : (LaPToP.TheoryDesign.ListStack.push s x).contents = s.contents ++ [x]
theorem LaPToP.TheoryDesign.ListStack.push_contents (s : LaPToP.DataStructures.HList ℤ) (x : ℤ) : (LaPToP.TheoryDesign.ListStack.push s x).contents = s.contents ++ [x]
`push s x = ⟨s.contents ++ [x]⟩`.
-
theoremdefined in LaPToP/TheoryDesign/Stack.leancomplete
theorem LaPToP.TheoryDesign.ListStack.push_ne_empty (s : LaPToP.DataStructures.HList ℤ) (x : ℤ) : LaPToP.TheoryDesign.ListStack.push s x ≠ LaPToP.TheoryDesign.ListStack.empty
theorem LaPToP.TheoryDesign.ListStack.push_ne_empty (s : LaPToP.DataStructures.HList ℤ) (x : ℤ) : LaPToP.TheoryDesign.ListStack.push s x ≠ LaPToP.TheoryDesign.ListStack.empty
`push s x ⧧ empty`.
-
theoremdefined in LaPToP/TheoryDesign/Stack.leancomplete
theorem LaPToP.TheoryDesign.ListStack.induction (P : LaPToP.DataStructures.HList ℤ → Prop) (h0 : P LaPToP.TheoryDesign.ListStack.empty) (hs : ∀ (s : LaPToP.DataStructures.HList ℤ) (x : ℤ), P s → P (LaPToP.TheoryDesign.ListStack.push s x)) (s : LaPToP.DataStructures.HList ℤ) : P s
theorem LaPToP.TheoryDesign.ListStack.induction (P : LaPToP.DataStructures.HList ℤ → Prop) (h0 : P LaPToP.TheoryDesign.ListStack.empty) (hs : ∀ (s : LaPToP.DataStructures.HList ℤ) (x : ℤ), P s → P (LaPToP.TheoryDesign.ListStack.push s x)) (s : LaPToP.DataStructures.HList ℤ) : P s
Induction for lists viewed as stacks: from the right.
-
theoremdefined in LaPToP/TheoryDesign/Stack.leancomplete
theorem LaPToP.TheoryDesign.ListStack.pop_push (s : LaPToP.DataStructures.HList ℤ) (x : ℤ) : LaPToP.TheoryDesign.ListStack.pop (LaPToP.TheoryDesign.ListStack.push s x) = s
theorem LaPToP.TheoryDesign.ListStack.pop_push (s : LaPToP.DataStructures.HList ℤ) (x : ℤ) : LaPToP.TheoryDesign.ListStack.pop (LaPToP.TheoryDesign.ListStack.push s x) = s
`pop (push s x) = s`: "index the list".
-
theoremdefined in LaPToP/TheoryDesign/Stack.leancomplete
theorem LaPToP.TheoryDesign.ListStack.top_push (s : LaPToP.DataStructures.HList ℤ) (x : ℤ) : LaPToP.TheoryDesign.ListStack.top (LaPToP.TheoryDesign.ListStack.push s x) = x
theorem LaPToP.TheoryDesign.ListStack.top_push (s : LaPToP.DataStructures.HList ℤ) (x : ℤ) : LaPToP.TheoryDesign.ListStack.top (LaPToP.TheoryDesign.ListStack.push s x) = x
`top (push s x) = x`, the book's worked calculation.
-
theoremdefined in LaPToP/TheoryDesign/Stack.leancomplete
theorem LaPToP.TheoryDesign.ListStack.push_inj (s t : LaPToP.DataStructures.HList ℤ) (x y : ℤ) : LaPToP.TheoryDesign.ListStack.push s x = LaPToP.TheoryDesign.ListStack.push t y ↔ s = t ∧ x = y
theorem LaPToP.TheoryDesign.ListStack.push_inj (s t : LaPToP.DataStructures.HList ℤ) (x y : ℤ) : LaPToP.TheoryDesign.ListStack.push s x = LaPToP.TheoryDesign.ListStack.push t y ↔ s = t ∧ x = y
`push s x = push t y = s=t ∧ x=y`.
-
defdefined in LaPToP/TheoryDesign/Stack.leancomplete
def LaPToP.TheoryDesign.ListStack.theory : LaPToP.TheoryDesign.DataStackTheory ℤ
def LaPToP.TheoryDesign.ListStack.theory : LaPToP.TheoryDesign.DataStackTheory ℤ
"The definitions must satisfy the axioms": lists implement data-stack theory.
-
LaPToP.TheoryDesign.ListStack.pop_empty[complete] -
LaPToP.TheoryDesign.ListStack.top_empty[complete] -
LaPToP.TheoryDesign.ListStack'.pop[complete] -
LaPToP.TheoryDesign.ListStack'.top[complete] -
LaPToP.TheoryDesign.ListStack'.theory[complete] -
LaPToP.TheoryDesign.ListStack'.pop_empty_ne[complete] -
LaPToP.TheoryDesign.ListStack'.top_empty_ne[complete] -
LaPToP.TheoryDesign.pop_empty_unclassified[complete] -
LaPToP.TheoryDesign.top_empty_unclassified[complete]
"Is stack theory complete? To show that a binary expression is unclassified,
we must implement stacks twice, making the expression a theorem in one
implementation, and an antitheorem in the other. The expressions
\mathit{pop}\ \mathit{empty} = \mathit{empty} and \mathit{top}\ \mathit{empty} = 0 are theorems
in our implementation, but we can alter the implementation as follows —
\mathit{pop} = \langle s \cdot \mathbf{if}\ s = \mathit{empty}\ \mathbf{then}\ \mathit{push}\ \mathit{empty}\ 0\ \mathbf{else}\ \ldots \rangle,
\mathit{top} = \langle s \cdot \mathbf{if}\ s = \mathit{empty}\ \mathbf{then}\ 1\ \mathbf{else}\ \ldots \rangle —
to make them antitheorems. So stack theory is incomplete." Both
implementations are terms of type DataStackTheory ℤ, and neither
\mathit{pop}\ \mathit{empty} = \mathit{empty} nor its negation holds in every model.
"The stack user must not use \mathit{pop}\ \mathit{empty} = \mathit{empty} even though the
stack implementer has provided it; if the user wants it, it should be added to
the theory." Uses Theorem 8.2.
Lean code for Theorem8.3●9 declarations
Associated Lean declarations
-
LaPToP.TheoryDesign.ListStack.pop_empty[complete]
-
LaPToP.TheoryDesign.ListStack.top_empty[complete]
-
LaPToP.TheoryDesign.ListStack'.pop[complete]
-
LaPToP.TheoryDesign.ListStack'.top[complete]
-
LaPToP.TheoryDesign.ListStack'.theory[complete]
-
LaPToP.TheoryDesign.ListStack'.pop_empty_ne[complete]
-
LaPToP.TheoryDesign.ListStack'.top_empty_ne[complete]
-
LaPToP.TheoryDesign.pop_empty_unclassified[complete]
-
LaPToP.TheoryDesign.top_empty_unclassified[complete]
-
LaPToP.TheoryDesign.ListStack.pop_empty[complete] -
LaPToP.TheoryDesign.ListStack.top_empty[complete] -
LaPToP.TheoryDesign.ListStack'.pop[complete] -
LaPToP.TheoryDesign.ListStack'.top[complete] -
LaPToP.TheoryDesign.ListStack'.theory[complete] -
LaPToP.TheoryDesign.ListStack'.pop_empty_ne[complete] -
LaPToP.TheoryDesign.ListStack'.top_empty_ne[complete] -
LaPToP.TheoryDesign.pop_empty_unclassified[complete] -
LaPToP.TheoryDesign.top_empty_unclassified[complete]
-
theoremdefined in LaPToP/TheoryDesign/Stack.leancomplete
theorem LaPToP.TheoryDesign.ListStack.pop_empty : LaPToP.TheoryDesign.ListStack.pop LaPToP.TheoryDesign.ListStack.empty = LaPToP.TheoryDesign.ListStack.empty
theorem LaPToP.TheoryDesign.ListStack.pop_empty : LaPToP.TheoryDesign.ListStack.pop LaPToP.TheoryDesign.ListStack.empty = LaPToP.TheoryDesign.ListStack.empty
`pop empty = empty` is a theorem of this implementation ...
-
theoremdefined in LaPToP/TheoryDesign/Stack.leancomplete
theorem LaPToP.TheoryDesign.ListStack.top_empty : LaPToP.TheoryDesign.ListStack.top LaPToP.TheoryDesign.ListStack.empty = 0
theorem LaPToP.TheoryDesign.ListStack.top_empty : LaPToP.TheoryDesign.ListStack.top LaPToP.TheoryDesign.ListStack.empty = 0
... and so is `top empty = 0`.
-
defdefined in LaPToP/TheoryDesign/Stack.leancomplete
def LaPToP.TheoryDesign.ListStack'.pop (s : LaPToP.DataStructures.HList ℤ) : LaPToP.DataStructures.HList ℤ
def LaPToP.TheoryDesign.ListStack'.pop (s : LaPToP.DataStructures.HList ℤ) : LaPToP.DataStructures.HList ℤ
The alternative `pop = ⟨s: stack· if s=empty then push empty 0 else s [0;..#s–1]⟩`.
-
defdefined in LaPToP/TheoryDesign/Stack.leancomplete
def LaPToP.TheoryDesign.ListStack'.top (s : LaPToP.DataStructures.HList ℤ) : ℤ
def LaPToP.TheoryDesign.ListStack'.top (s : LaPToP.DataStructures.HList ℤ) : ℤ
The alternative `top = ⟨s: stack· if s=empty then 1 else s (#s–1)⟩`.
-
defdefined in LaPToP/TheoryDesign/Stack.leancomplete
def LaPToP.TheoryDesign.ListStack'.theory : LaPToP.TheoryDesign.DataStackTheory ℤ
def LaPToP.TheoryDesign.ListStack'.theory : LaPToP.TheoryDesign.DataStackTheory ℤ
The alternative implementation also satisfies the axioms.
-
theoremdefined in LaPToP/TheoryDesign/Stack.leancomplete
theorem LaPToP.TheoryDesign.ListStack'.pop_empty_ne : LaPToP.TheoryDesign.ListStack'.pop LaPToP.TheoryDesign.ListStack.empty ≠ LaPToP.TheoryDesign.ListStack.empty
theorem LaPToP.TheoryDesign.ListStack'.pop_empty_ne : LaPToP.TheoryDesign.ListStack'.pop LaPToP.TheoryDesign.ListStack.empty ≠ LaPToP.TheoryDesign.ListStack.empty
In the alternative implementation `pop empty ⧧ empty` ...
-
theoremdefined in LaPToP/TheoryDesign/Stack.leancomplete
theorem LaPToP.TheoryDesign.ListStack'.top_empty_ne : LaPToP.TheoryDesign.ListStack'.top LaPToP.TheoryDesign.ListStack.empty ≠ 0
theorem LaPToP.TheoryDesign.ListStack'.top_empty_ne : LaPToP.TheoryDesign.ListStack'.top LaPToP.TheoryDesign.ListStack.empty ≠ 0
... and `top empty ⧧ 0`.
-
theoremdefined in LaPToP/TheoryDesign/Stack.leancomplete
theorem LaPToP.TheoryDesign.pop_empty_unclassified : (¬∀ (T : LaPToP.TheoryDesign.DataStackTheory ℤ), T.pop T.empty = T.empty) ∧ ¬∀ (T : LaPToP.TheoryDesign.DataStackTheory ℤ), T.pop T.empty ≠ T.empty
theorem LaPToP.TheoryDesign.pop_empty_unclassified : (¬∀ (T : LaPToP.TheoryDesign.DataStackTheory ℤ), T.pop T.empty = T.empty) ∧ ¬∀ (T : LaPToP.TheoryDesign.DataStackTheory ℤ), T.pop T.empty ≠ T.empty
"So stack theory is incomplete": `pop empty = empty` is neither a theorem nor an antitheorem of data-stack theory — it holds in one model and fails in another.
-
theoremdefined in LaPToP/TheoryDesign/Stack.leancomplete
theorem LaPToP.TheoryDesign.top_empty_unclassified : (¬∀ (T : LaPToP.TheoryDesign.DataStackTheory ℤ), T.top T.empty = 0) ∧ ¬∀ (T : LaPToP.TheoryDesign.DataStackTheory ℤ), T.top T.empty ≠ 0
theorem LaPToP.TheoryDesign.top_empty_unclassified : (¬∀ (T : LaPToP.TheoryDesign.DataStackTheory ℤ), T.top T.empty = 0) ∧ ¬∀ (T : LaPToP.TheoryDesign.DataStackTheory ℤ), T.top T.empty ≠ 0
Likewise for `top empty = 0`.
"In the data-stack theory just presented, we have axioms \mathit{empty} : \mathit{stack}
and \mathit{pop} : \mathit{stack} \to \mathit{stack}; from them we can prove
\mathit{pop}\ \mathit{empty} : \mathit{stack}. ... An implementer is obliged to give a
stack for \mathit{pop}\ \mathit{empty}, though it does not matter which one. If we never
want to pop an empty stack, then the theory is too strong. ... For most
purposes, it is sufficient to be able to push items onto a stack, pop items
off, and look at the top item. ... Our simpler data-stack theory introduces the
names \mathit{stack}, \mathit{push}, \mathit{pop}, and \mathit{top} with the following
four axioms: \mathit{stack} \neq \mathit{null}, \mathit{push}\ s\ x : \mathit{stack},
\mathit{pop}(\mathit{push}\ s\ x) = s, \mathit{top}(\mathit{push}\ s\ x) = x." The design
remarks are made concrete: every data-stack theory is a simple one, the list
implementation is a model, and there is a model with no empty stack at all —
infinite stacks \mathit{nat} \to X, in which every stack is a \mathit{push} ("we
never need an empty stack, nor to test if a stack is empty"). "As an
engineering activity, theory design is the art of excluding all unwanted
implementations while allowing all the others." Uses Definition 8.1
and Theorem 8.2.
Lean code for Definition8.4●5 declarations
Associated Lean declarations
-
structuredefined in LaPToP/TheoryDesign/SimpleStack.leancomplete
structure LaPToP.TheoryDesign.SimpleStackTheory.{u, v} (X : Type u) : Type (max u (v + 1))
structure LaPToP.TheoryDesign.SimpleStackTheory.{u, v} (X : Type u) : Type (max u (v + 1))
The *simple data-stack theory* (aPToP §7.0.2): `stack ⧧ null`, `push s x: stack`, `pop (push s x) = s`, `top (push s x) = x`.
Fields
Stack : Type v
`stack`.
nonempty : Nonempty self.Stack
`stack ⧧ null`, "so that we can still declare variables of type stack".
push : self.Stack → X → self.Stack
`push s x: stack`.
pop : self.Stack → self.Stack
`pop`; the book drops `pop: stack→stack` so that `pop empty` need not be provided.
top : self.Stack → X
`top`; likewise `top: stack→X` is dropped.
pop_push : ∀ (s : self.Stack) (x : X), self.pop (self.push s x) = s
`pop (push s x) = s`.
top_push : ∀ (s : self.Stack) (x : X), self.top (self.push s x) = x
`top (push s x) = x`.
-
defdefined in LaPToP/TheoryDesign/SimpleStack.leancomplete
def LaPToP.TheoryDesign.SimpleStackTheory.ofDataStack.{u, u_1} {X : Type u} (T : LaPToP.TheoryDesign.DataStackTheory X) : LaPToP.TheoryDesign.SimpleStackTheory X
def LaPToP.TheoryDesign.SimpleStackTheory.ofDataStack.{u, u_1} {X : Type u} (T : LaPToP.TheoryDesign.DataStackTheory X) : LaPToP.TheoryDesign.SimpleStackTheory X
Every data-stack theory is a simple data-stack theory: the simple theory is weaker.
-
defdefined in LaPToP/TheoryDesign/SimpleStack.leancomplete
def LaPToP.TheoryDesign.SimpleStackTheory.listModel : LaPToP.TheoryDesign.SimpleStackTheory ℤ
def LaPToP.TheoryDesign.SimpleStackTheory.listModel : LaPToP.TheoryDesign.SimpleStackTheory ℤ
The list implementation is a model of the simple theory.
-
defdefined in LaPToP/TheoryDesign/SimpleStack.leancomplete
def LaPToP.TheoryDesign.SimpleStackTheory.streamModel.{u} (X : Type u) [Inhabited X] : LaPToP.TheoryDesign.SimpleStackTheory X
def LaPToP.TheoryDesign.SimpleStackTheory.streamModel.{u} (X : Type u) [Inhabited X] : LaPToP.TheoryDesign.SimpleStackTheory X
The stream model: stacks are infinite sequences `ℕ → X`; `push` prepends, `pop` drops the head, `top` is the head.
-
theoremdefined in LaPToP/TheoryDesign/SimpleStack.leancomplete
theorem LaPToP.TheoryDesign.SimpleStackTheory.streamModel_every_push.{u} (X : Type u) [Inhabited X] (e : (LaPToP.TheoryDesign.SimpleStackTheory.streamModel X).Stack) : ∃ s x, (LaPToP.TheoryDesign.SimpleStackTheory.streamModel X).push s x = e
theorem LaPToP.TheoryDesign.SimpleStackTheory.streamModel_every_push.{u} (X : Type u) [Inhabited X] (e : (LaPToP.TheoryDesign.SimpleStackTheory.streamModel X).Stack) : ∃ s x, (LaPToP.TheoryDesign.SimpleStackTheory.streamModel X).push s x = e
In the stream model every stack is a `push`: there is no empty stack, so the strong axiom `push s x ⧧ empty` could not hold for any choice of `empty`. "As long as we are given some tree [stack], we can build" what we need.
-
LaPToP.TheoryDesign.DataQueueTheory[complete] -
LaPToP.TheoryDesign.DataQueueTheory.eq_emptyq_or_join[complete] -
LaPToP.TheoryDesign.DataQueueTheory.front_foldl[complete] -
LaPToP.TheoryDesign.DataQueueTheory.front_joins[complete] -
LaPToP.TheoryDesign.ListQueue.emptyq[complete] -
LaPToP.TheoryDesign.ListQueue.join[complete] -
LaPToP.TheoryDesign.ListQueue.leave[complete] -
LaPToP.TheoryDesign.ListQueue.front[complete] -
LaPToP.TheoryDesign.ListQueue.join_ne_emptyq[complete] -
LaPToP.TheoryDesign.ListQueue.theory[complete]
"The queue data structure, also known as a buffer ... is the structure with the
motto: the first one in is the first one out. We introduce the syntax
\mathit{queue}, \mathit{emptyq}, \mathit{join}, \mathit{leave}, and \mathit{front}."
Axioms: \mathit{emptyq} : \mathit{queue}, \mathit{join}\ q\ x : \mathit{queue};
\mathit{join}\ q\ x \neq \mathit{emptyq}, \mathit{join}\ q\ x = \mathit{join}\ r\ y = (q = r \land x = y);
queue induction \mathit{emptyq}, \mathit{join}\ B\ X : B \Rightarrow \mathit{queue} : B; and
"first in, first out": \mathit{leave}(\mathit{join}\ \mathit{emptyq}\ x) = \mathit{emptyq},
q \neq \mathit{emptyq} \Rightarrow \mathit{leave}(\mathit{join}\ q\ x) = \mathit{join}(\mathit{leave}\ q)\ x,
\mathit{front}(\mathit{join}\ \mathit{emptyq}\ x) = x,
q \neq \mathit{emptyq} \Rightarrow \mathit{front}(\mathit{join}\ q\ x) = \mathit{front}\ q. The typing
axioms q \neq \mathit{emptyq} \Rightarrow \mathit{leave}\ q : \mathit{queue} and
q \neq \mathit{emptyq} \Rightarrow \mathit{front}\ q : X "can now be proved" (automatic for a
carrier type). Derived: every queue is \mathit{emptyq} or a \mathit{join}, and the
item joined to the empty queue stays at the front whatever is joined afterwards.
"Data-queue implementation raises no new issues, so we leave it as Exercise
426": lists with \mathit{join}\ q\ x = q ;; [x], \mathit{leave}\ q = q\,[1;..\# q],
\mathit{front}\ q = q\,0 are a DataQueueTheory ℤ. Uses Definition 8.1
and Theorem 4.10.
Lean code for Definition8.5●10 declarations
Associated Lean declarations
-
LaPToP.TheoryDesign.DataQueueTheory[complete]
-
LaPToP.TheoryDesign.DataQueueTheory.eq_emptyq_or_join[complete]
-
LaPToP.TheoryDesign.DataQueueTheory.front_foldl[complete]
-
LaPToP.TheoryDesign.DataQueueTheory.front_joins[complete]
-
LaPToP.TheoryDesign.ListQueue.emptyq[complete]
-
LaPToP.TheoryDesign.ListQueue.join[complete]
-
LaPToP.TheoryDesign.ListQueue.leave[complete]
-
LaPToP.TheoryDesign.ListQueue.front[complete]
-
LaPToP.TheoryDesign.ListQueue.join_ne_emptyq[complete]
-
LaPToP.TheoryDesign.ListQueue.theory[complete]
-
LaPToP.TheoryDesign.DataQueueTheory[complete] -
LaPToP.TheoryDesign.DataQueueTheory.eq_emptyq_or_join[complete] -
LaPToP.TheoryDesign.DataQueueTheory.front_foldl[complete] -
LaPToP.TheoryDesign.DataQueueTheory.front_joins[complete] -
LaPToP.TheoryDesign.ListQueue.emptyq[complete] -
LaPToP.TheoryDesign.ListQueue.join[complete] -
LaPToP.TheoryDesign.ListQueue.leave[complete] -
LaPToP.TheoryDesign.ListQueue.front[complete] -
LaPToP.TheoryDesign.ListQueue.join_ne_emptyq[complete] -
LaPToP.TheoryDesign.ListQueue.theory[complete]
-
structuredefined in LaPToP/TheoryDesign/Queue.leancomplete
structure LaPToP.TheoryDesign.DataQueueTheory.{u, v} (X : Type u) : Type (max u (v + 1))
structure LaPToP.TheoryDesign.DataQueueTheory.{u, v} (X : Type u) : Type (max u (v + 1))
A *data-queue theory* over items `X` (aPToP §7.0.3).
Fields
Queue : Type v
`queue`, "a bunch consisting of all queues of items of type `X`".
emptyq : self.Queue
`emptyq: queue`, "a queue containing no items".
join : self.Queue → X → self.Queue
`join: queue→X→queue`, "the queue containing the same items plus the one new item".
leave : self.Queue → self.Queue
`leave`, "the queue minus the oldest remaining item".
front : self.Queue → X
`front`, "the oldest remaining item".
induction : ∀ (P : self.Queue → Prop), P self.emptyq → (∀ (q : self.Queue) (x : X), P q → P (self.join q x)) → ∀ (q : self.Queue), P q
Queue induction: `emptyq, join B X: B ⇒ queue: B`.
join_ne_emptyq : ∀ (q : self.Queue) (x : X), self.join q x ≠ self.emptyq
`join q x ⧧ emptyq`.
join_inj : ∀ (q r : self.Queue) (x y : X), self.join q x = self.join r y ↔ q = r ∧ x = y
`join q x = join r y = q=r ∧ x=y`.
leave_join_emptyq : ∀ (x : X), self.leave (self.join self.emptyq x) = self.emptyq
`leave (join emptyq x) = emptyq`.
leave_join : ∀ (q : self.Queue) (x : X), q ≠ self.emptyq → self.leave (self.join q x) = self.join (self.leave q) x
`q⧧emptyq ⇒ leave (join q x) = join (leave q) x`.
front_join_emptyq : ∀ (x : X), self.front (self.join self.emptyq x) = x
`front (join emptyq x) = x`.
front_join : ∀ (q : self.Queue) (x : X), q ≠ self.emptyq → self.front (self.join q x) = self.front q
`q⧧emptyq ⇒ front (join q x) = front q`.
-
theoremdefined in LaPToP/TheoryDesign/Queue.leancomplete
theorem LaPToP.TheoryDesign.DataQueueTheory.eq_emptyq_or_join.{u, u_1} {X : Type u} (T : LaPToP.TheoryDesign.DataQueueTheory X) (q : T.Queue) : q = T.emptyq ∨ ∃ r x, q = T.join r x
theorem LaPToP.TheoryDesign.DataQueueTheory.eq_emptyq_or_join.{u, u_1} {X : Type u} (T : LaPToP.TheoryDesign.DataQueueTheory X) (q : T.Queue) : q = T.emptyq ∨ ∃ r x, q = T.join r x
Every queue is `emptyq` or a `join`.
-
theoremdefined in LaPToP/TheoryDesign/Queue.leancomplete
theorem LaPToP.TheoryDesign.DataQueueTheory.front_foldl.{u, u_1} {X : Type u} (T : LaPToP.TheoryDesign.DataQueueTheory X) (l : List X) (q : T.Queue) (hq : q ≠ T.emptyq) : T.front (List.foldl T.join q l) = T.front q
theorem LaPToP.TheoryDesign.DataQueueTheory.front_foldl.{u, u_1} {X : Type u} (T : LaPToP.TheoryDesign.DataQueueTheory X) (l : List X) (q : T.Queue) (hq : q ≠ T.emptyq) : T.front (List.foldl T.join q l) = T.front q
Joining items to a nonempty queue does not change its front: the FIFO character, iterated.
-
theoremdefined in LaPToP/TheoryDesign/Queue.leancomplete
theorem LaPToP.TheoryDesign.DataQueueTheory.front_joins.{u, u_1} {X : Type u} (T : LaPToP.TheoryDesign.DataQueueTheory X) (x : X) (l : List X) : T.front (List.foldl T.join (T.join T.emptyq x) l) = x
theorem LaPToP.TheoryDesign.DataQueueTheory.front_joins.{u, u_1} {X : Type u} (T : LaPToP.TheoryDesign.DataQueueTheory X) (x : X) (l : List X) : T.front (List.foldl T.join (T.join T.emptyq x) l) = x
"The first one in is the first one out": the item joined to the empty queue stays at the front whatever is joined afterwards.
-
defdefined in LaPToP/TheoryDesign/Queue.leancomplete
def LaPToP.TheoryDesign.ListQueue.emptyq : LaPToP.DataStructures.HList ℤ
def LaPToP.TheoryDesign.ListQueue.emptyq : LaPToP.DataStructures.HList ℤ
`emptyq = [nil]`.
-
defdefined in LaPToP/TheoryDesign/Queue.leancomplete
def LaPToP.TheoryDesign.ListQueue.join (q : LaPToP.DataStructures.HList ℤ) (x : ℤ) : LaPToP.DataStructures.HList ℤ
def LaPToP.TheoryDesign.ListQueue.join (q : LaPToP.DataStructures.HList ℤ) (x : ℤ) : LaPToP.DataStructures.HList ℤ
`join q x = q;;[x]`: the new item goes to the back.
-
defdefined in LaPToP/TheoryDesign/Queue.leancomplete
def LaPToP.TheoryDesign.ListQueue.leave (q : LaPToP.DataStructures.HList ℤ) : LaPToP.DataStructures.HList ℤ
def LaPToP.TheoryDesign.ListQueue.leave (q : LaPToP.DataStructures.HList ℤ) : LaPToP.DataStructures.HList ℤ
`leave q = q [1;..#q]`: drop the front item (`leave emptyq = emptyq`).
-
defdefined in LaPToP/TheoryDesign/Queue.leancomplete
def LaPToP.TheoryDesign.ListQueue.front (q : LaPToP.DataStructures.HList ℤ) : ℤ
def LaPToP.TheoryDesign.ListQueue.front (q : LaPToP.DataStructures.HList ℤ) : ℤ
`front q = q 0` (`front emptyq = 0`).
-
theoremdefined in LaPToP/TheoryDesign/Queue.leancomplete
theorem LaPToP.TheoryDesign.ListQueue.join_ne_emptyq (q : LaPToP.DataStructures.HList ℤ) (x : ℤ) : LaPToP.TheoryDesign.ListQueue.join q x ≠ LaPToP.TheoryDesign.ListQueue.emptyq
theorem LaPToP.TheoryDesign.ListQueue.join_ne_emptyq (q : LaPToP.DataStructures.HList ℤ) (x : ℤ) : LaPToP.TheoryDesign.ListQueue.join q x ≠ LaPToP.TheoryDesign.ListQueue.emptyq
`join q x ⧧ emptyq`.
-
defdefined in LaPToP/TheoryDesign/Queue.leancomplete
def LaPToP.TheoryDesign.ListQueue.theory : LaPToP.TheoryDesign.DataQueueTheory ℤ
def LaPToP.TheoryDesign.ListQueue.theory : LaPToP.TheoryDesign.DataQueueTheory ℤ
Lists implement data-queue theory.
-
LaPToP.TheoryDesign.DataTreeTheory[complete] -
LaPToP.TheoryDesign.SimpleTreeTheory[complete] -
LaPToP.TheoryDesign.DataTreeTheory.eq_emptree_or_graft[complete] -
LaPToP.TheoryDesign.DataTreeTheory.graft_inj_of_selectors[complete] -
LaPToP.TheoryDesign.DataTreeTheory.toSimple[complete] -
LaPToP.TheoryDesign.BinTree[complete] -
LaPToP.TheoryDesign.BinTree.left[complete] -
LaPToP.TheoryDesign.BinTree.right[complete] -
LaPToP.TheoryDesign.BinTree.root[complete] -
LaPToP.TheoryDesign.BinTree.theory[complete] -
LaPToP.TheoryDesign.BinTree.example₁[complete] -
LaPToP.TheoryDesign.BinTree.example₁_roots[complete]
"We introduce the syntax \mathit{tree}, \mathit{emptree}, \mathit{graft}, \mathit{left},
\mathit{right}, \mathit{root}. For the purpose of studying trees, we want a strong
theory": \mathit{emptree} : \mathit{tree}, \mathit{graft} : \mathit{tree} \to X \to \mathit{tree} \to \mathit{tree},
induction \mathit{emptree}, \mathit{graft}\ B\ X\ B : B \Rightarrow \mathit{tree} : B,
\mathit{graft}\ t\ x\ u \neq \mathit{emptree},
\mathit{graft}\ t\ x\ u = \mathit{graft}\ v\ y\ w = (t = v \land x = y \land u = w),
\mathit{left}(\mathit{graft}\ t\ x\ u) = t, \mathit{root}(\mathit{graft}\ t\ x\ u) = x,
\mathit{right}(\mathit{graft}\ t\ x\ u) = u. "For most programming purposes, the following
simpler, weaker theory is sufficient": \mathit{tree} \neq \mathit{null},
\mathit{graft}\ t\ x\ u : \mathit{tree} and the three selector axioms. Derived: every tree
is \mathit{emptree} or a \mathit{graft}; the selectors alone make \mathit{graft}
injective. The book's implementation by nested lists
(\mathit{graft}\ t\ x\ u = [t; x; u], \mathit{left}\ t = t\,0, \mathit{root}\ t = t\,1,
\mathit{right}\ t = t\,2) mixes lists and items and is not expressible with the
homogeneous lists of Definition 4.9; the implementation here is the
inductive type of finite binary trees — the recursive data definition
\mathit{tree} = \mathit{emptree}, \mathit{graft}\ \mathit{tree}\ X\ \mathit{tree} as a datatype (cf.
Definition 7.5) — with the book's example tree
[[[\mathit{nil}]; 2; [[\mathit{nil}]; 5; [\mathit{nil}]]]; 3; [[\mathit{nil}]; 7; [\mathit{nil}]]]. Uses
Definition 8.1.
Lean code for Definition8.6●12 declarations
Associated Lean declarations
-
LaPToP.TheoryDesign.DataTreeTheory[complete]
-
LaPToP.TheoryDesign.SimpleTreeTheory[complete]
-
LaPToP.TheoryDesign.DataTreeTheory.eq_emptree_or_graft[complete]
-
LaPToP.TheoryDesign.DataTreeTheory.graft_inj_of_selectors[complete]
-
LaPToP.TheoryDesign.DataTreeTheory.toSimple[complete]
-
LaPToP.TheoryDesign.BinTree[complete]
-
LaPToP.TheoryDesign.BinTree.left[complete]
-
LaPToP.TheoryDesign.BinTree.right[complete]
-
LaPToP.TheoryDesign.BinTree.root[complete]
-
LaPToP.TheoryDesign.BinTree.theory[complete]
-
LaPToP.TheoryDesign.BinTree.example₁[complete]
-
LaPToP.TheoryDesign.BinTree.example₁_roots[complete]
-
LaPToP.TheoryDesign.DataTreeTheory[complete] -
LaPToP.TheoryDesign.SimpleTreeTheory[complete] -
LaPToP.TheoryDesign.DataTreeTheory.eq_emptree_or_graft[complete] -
LaPToP.TheoryDesign.DataTreeTheory.graft_inj_of_selectors[complete] -
LaPToP.TheoryDesign.DataTreeTheory.toSimple[complete] -
LaPToP.TheoryDesign.BinTree[complete] -
LaPToP.TheoryDesign.BinTree.left[complete] -
LaPToP.TheoryDesign.BinTree.right[complete] -
LaPToP.TheoryDesign.BinTree.root[complete] -
LaPToP.TheoryDesign.BinTree.theory[complete] -
LaPToP.TheoryDesign.BinTree.example₁[complete] -
LaPToP.TheoryDesign.BinTree.example₁_roots[complete]
-
structuredefined in LaPToP/TheoryDesign/Tree.leancomplete
structure LaPToP.TheoryDesign.DataTreeTheory.{u, v} (X : Type u) : Type (max u (v + 1))
structure LaPToP.TheoryDesign.DataTreeTheory.{u, v} (X : Type u) : Type (max u (v + 1))
A *data-tree theory* over items `X` (aPToP §7.0.4), "a strong theory".
Fields
Tree : Type v
`tree`, "a bunch consisting of all finite binary trees of items of type `X`".
emptree : self.Tree
`emptree: tree`, "a tree containing no items".
graft : self.Tree → X → self.Tree → self.Tree
`graft: tree→X→tree→tree`, "the tree with the item at the root and the two given trees as left and right subtree".
left : self.Tree → self.Tree
`left`, the left subtree.
right : self.Tree → self.Tree
`right`, the right subtree.
root : self.Tree → X
`root`, the root item.
induction : ∀ (P : self.Tree → Prop), P self.emptree → (∀ (t : self.Tree) (x : X) (u : self.Tree), P t → P u → P (self.graft t x u)) → ∀ (t : self.Tree), P t
Tree induction: `emptree, graft B X B: B ⇒ tree: B`.
graft_ne_emptree : ∀ (t : self.Tree) (x : X) (u : self.Tree), self.graft t x u ≠ self.emptree
`graft t x u ⧧ emptree`.
graft_inj : ∀ (t : self.Tree) (x : X) (u v : self.Tree) (y : X) (w : self.Tree), self.graft t x u = self.graft v y w ↔ t = v ∧ x = y ∧ u = w
`graft t x u = graft v y w = t=v ∧ x=y ∧ u=w`.
left_graft : ∀ (t : self.Tree) (x : X) (u : self.Tree), self.left (self.graft t x u) = t
`left (graft t x u) = t`.
root_graft : ∀ (t : self.Tree) (x : X) (u : self.Tree), self.root (self.graft t x u) = x
`root (graft t x u) = x`.
right_graft : ∀ (t : self.Tree) (x : X) (u : self.Tree), self.right (self.graft t x u) = u
`right (graft t x u) = u`.
-
structuredefined in LaPToP/TheoryDesign/Tree.leancomplete
structure LaPToP.TheoryDesign.SimpleTreeTheory.{u, v} (X : Type u) : Type (max u (v + 1))
structure LaPToP.TheoryDesign.SimpleTreeTheory.{u, v} (X : Type u) : Type (max u (v + 1))
The "simpler, weaker" data-tree theory: `tree ⧧ null`, `graft t x u: tree`, and the three selector axioms — "we don't really need to be given an empty tree ... and we probably don't need tree induction".
Fields
Tree : Type v
`tree`.
nonempty : Nonempty self.Tree
`tree ⧧ null`.
graft : self.Tree → X → self.Tree → self.Tree
`graft`.
left : self.Tree → self.Tree
`left`.
right : self.Tree → self.Tree
`right`.
root : self.Tree → X
`root`.
left_graft : ∀ (t : self.Tree) (x : X) (u : self.Tree), self.left (self.graft t x u) = t
`left (graft t x u) = t`.
root_graft : ∀ (t : self.Tree) (x : X) (u : self.Tree), self.root (self.graft t x u) = x
`root (graft t x u) = x`.
right_graft : ∀ (t : self.Tree) (x : X) (u : self.Tree), self.right (self.graft t x u) = u
`right (graft t x u) = u`.
-
theoremdefined in LaPToP/TheoryDesign/Tree.leancomplete
theorem LaPToP.TheoryDesign.DataTreeTheory.eq_emptree_or_graft.{u, u_1} {X : Type u} (T : LaPToP.TheoryDesign.DataTreeTheory X) (t : T.Tree) : t = T.emptree ∨ ∃ l x r, t = T.graft l x r
theorem LaPToP.TheoryDesign.DataTreeTheory.eq_emptree_or_graft.{u, u_1} {X : Type u} (T : LaPToP.TheoryDesign.DataTreeTheory X) (t : T.Tree) : t = T.emptree ∨ ∃ l x r, t = T.graft l x r
Every tree is `emptree` or a `graft`.
-
theoremdefined in LaPToP/TheoryDesign/Tree.leancomplete
theorem LaPToP.TheoryDesign.DataTreeTheory.graft_inj_of_selectors.{u, u_1} {X : Type u} (T : LaPToP.TheoryDesign.DataTreeTheory X) (t u v w : T.Tree) (x y : X) (h : T.graft t x u = T.graft v y w) : t = v ∧ x = y ∧ u = w
theorem LaPToP.TheoryDesign.DataTreeTheory.graft_inj_of_selectors.{u, u_1} {X : Type u} (T : LaPToP.TheoryDesign.DataTreeTheory X) (t u v w : T.Tree) (x y : X) (h : T.graft t x u = T.graft v y w) : t = v ∧ x = y ∧ u = w
The selector axioms alone make `graft` injective, so the second "distinct trees" axiom is derivable from them.
-
defdefined in LaPToP/TheoryDesign/Tree.leancomplete
def LaPToP.TheoryDesign.DataTreeTheory.toSimple.{u, u_1} {X : Type u} (T : LaPToP.TheoryDesign.DataTreeTheory X) : LaPToP.TheoryDesign.SimpleTreeTheory X
def LaPToP.TheoryDesign.DataTreeTheory.toSimple.{u, u_1} {X : Type u} (T : LaPToP.TheoryDesign.DataTreeTheory X) : LaPToP.TheoryDesign.SimpleTreeTheory X
Every data-tree theory is a simple one.
-
inductivedefined in LaPToP/TheoryDesign/Tree.leancomplete
inductive LaPToP.TheoryDesign.BinTree.{u} (X : Type u) : Type u
inductive LaPToP.TheoryDesign.BinTree.{u} (X : Type u) : Type u
Finite binary trees of items of type `X`: the recursive data definition `tree = emptree, graft tree X tree` as a datatype.
Constructors
LaPToP.TheoryDesign.BinTree.emptree.{u} {X : Type u} : LaPToP.TheoryDesign.BinTree X
`emptree`.
LaPToP.TheoryDesign.BinTree.graft.{u} {X : Type u} (l : LaPToP.TheoryDesign.BinTree X) (x : X) (r : LaPToP.TheoryDesign.BinTree X) : LaPToP.TheoryDesign.BinTree X
`graft t x u`.
-
defdefined in LaPToP/TheoryDesign/Tree.leancomplete
def LaPToP.TheoryDesign.BinTree.left.{u} {X : Type u} : LaPToP.TheoryDesign.BinTree X → LaPToP.TheoryDesign.BinTree X
def LaPToP.TheoryDesign.BinTree.left.{u} {X : Type u} : LaPToP.TheoryDesign.BinTree X → LaPToP.TheoryDesign.BinTree X
`left`; on `emptree` the theory says nothing, and we return `emptree`.
-
defdefined in LaPToP/TheoryDesign/Tree.leancomplete
def LaPToP.TheoryDesign.BinTree.right.{u} {X : Type u} : LaPToP.TheoryDesign.BinTree X → LaPToP.TheoryDesign.BinTree X
def LaPToP.TheoryDesign.BinTree.right.{u} {X : Type u} : LaPToP.TheoryDesign.BinTree X → LaPToP.TheoryDesign.BinTree X
`right`; on `emptree` we return `emptree`.
-
defdefined in LaPToP/TheoryDesign/Tree.leancomplete
def LaPToP.TheoryDesign.BinTree.root.{u} {X : Type u} [Inhabited X] : LaPToP.TheoryDesign.BinTree X → X
def LaPToP.TheoryDesign.BinTree.root.{u} {X : Type u} [Inhabited X] : LaPToP.TheoryDesign.BinTree X → X
`root`; on `emptree` we return the default item.
-
defdefined in LaPToP/TheoryDesign/Tree.leancomplete
def LaPToP.TheoryDesign.BinTree.theory.{u} (X : Type u) [Inhabited X] : LaPToP.TheoryDesign.DataTreeTheory X
def LaPToP.TheoryDesign.BinTree.theory.{u} (X : Type u) [Inhabited X] : LaPToP.TheoryDesign.DataTreeTheory X
Binary trees implement data-tree theory.
-
defdefined in LaPToP/TheoryDesign/Tree.leancomplete
def LaPToP.TheoryDesign.BinTree.example₁ : LaPToP.TheoryDesign.BinTree ℤ
def LaPToP.TheoryDesign.BinTree.example₁ : LaPToP.TheoryDesign.BinTree ℤ
The book's example tree `[[[nil]; 2; [[nil]; 5; [nil]]]; 3; [[nil]; 7; [nil]]]`.
-
theoremdefined in LaPToP/TheoryDesign/Tree.leancomplete
theorem LaPToP.TheoryDesign.BinTree.example₁_roots : LaPToP.TheoryDesign.BinTree.example₁.root = 3 ∧ LaPToP.TheoryDesign.BinTree.example₁.left.root = 2
theorem LaPToP.TheoryDesign.BinTree.example₁_roots : LaPToP.TheoryDesign.BinTree.example₁.root = 3 ∧ LaPToP.TheoryDesign.BinTree.example₁.left.root = 2
Its root is `3` and the root of its left subtree is `2`.
-
LaPToP.TheoryDesign.ProgramStackTheory[complete] -
LaPToP.TheoryDesign.refinesOfEq[complete] -
LaPToP.TheoryDesign.ProgramStackTheory.push_pop_seq[complete] -
LaPToP.TheoryDesign.ProgramStackTheory.balanced[complete] -
LaPToP.TheoryDesign.ProgramStackTheory.ok_refines_balanced[complete] -
LaPToP.TheoryDesign.ProgramStackTheory.ok_refines_push_push_pop_pop[complete] -
LaPToP.TheoryDesign.ProgramStackTheory.refines_balanced_seq[complete] -
LaPToP.TheoryDesign.ProgramStackTheory.top_push_push_push_pop_pop[complete] -
LaPToP.TheoryDesign.ProgramStackTheory.top_push_balanced[complete]
"Users and implementers of a data structure can freely see and change their
own variables, but they cannot freely see or change each other's variables.
... If we need only one stack ... we can obtain an economy of expression and
of execution by leaving it implicit." "The simplest version of program-stack
theory introduces three names: \mathit{push} (a procedure with parameter of
type X), \mathit{pop} (a program), and \mathit{top} (of type X). ... The
following two axioms are sufficient: \mathit{top}' = x \Leftarrow \mathit{push}\ x,
\mathit{ok} \Leftarrow \mathit{push}\ x.\ \mathit{pop}." A program theory is a structure
over a state type with \mathit{push} a parametrized specification, \mathit{pop} a
specification and \mathit{top} a state variable, the axioms being refinements.
"The second axiom says that a pop undoes a push. In fact, it says that any
natural number of pushes are undone by the same number of pops:
\mathit{ok} \Leftarrow \mathit{push}\ x.\ \mathit{pop} = \mathit{push}\ x.\ \mathit{ok}.\ \mathit{pop} \Leftarrow \mathit{push}\ x.\ \mathit{push}\ y.\ \mathit{pop}.\ \mathit{pop}
... We can prove things like \mathit{top}' = x \Leftarrow \mathit{push}\ x.\ \mathit{push}\ y.\ \mathit{push}\ z.\ \mathit{pop}.\ \mathit{pop},
which say that when we push something onto the stack, we find it there later
at the appropriate time." Both are proved, the first for any number of
push–pop pairs. Uses Definition 8.4,
Definition 5.2 and Theorem 5.12.
Lean code for Definition8.7●9 declarations
Associated Lean declarations
-
LaPToP.TheoryDesign.ProgramStackTheory[complete]
-
LaPToP.TheoryDesign.refinesOfEq[complete]
-
LaPToP.TheoryDesign.ProgramStackTheory.push_pop_seq[complete]
-
LaPToP.TheoryDesign.ProgramStackTheory.balanced[complete]
-
LaPToP.TheoryDesign.ProgramStackTheory.ok_refines_balanced[complete]
-
LaPToP.TheoryDesign.ProgramStackTheory.ok_refines_push_push_pop_pop[complete]
-
LaPToP.TheoryDesign.ProgramStackTheory.refines_balanced_seq[complete]
-
LaPToP.TheoryDesign.ProgramStackTheory.top_push_push_push_pop_pop[complete]
-
LaPToP.TheoryDesign.ProgramStackTheory.top_push_balanced[complete]
-
LaPToP.TheoryDesign.ProgramStackTheory[complete] -
LaPToP.TheoryDesign.refinesOfEq[complete] -
LaPToP.TheoryDesign.ProgramStackTheory.push_pop_seq[complete] -
LaPToP.TheoryDesign.ProgramStackTheory.balanced[complete] -
LaPToP.TheoryDesign.ProgramStackTheory.ok_refines_balanced[complete] -
LaPToP.TheoryDesign.ProgramStackTheory.ok_refines_push_push_pop_pop[complete] -
LaPToP.TheoryDesign.ProgramStackTheory.refines_balanced_seq[complete] -
LaPToP.TheoryDesign.ProgramStackTheory.top_push_push_push_pop_pop[complete] -
LaPToP.TheoryDesign.ProgramStackTheory.top_push_balanced[complete]
-
structuredefined in LaPToP/TheoryDesign/ProgramStack.leancomplete
structure LaPToP.TheoryDesign.ProgramStackTheory.{u, v} (X : Type u) (σ : Type v) : Type (max u v)
structure LaPToP.TheoryDesign.ProgramStackTheory.{u, v} (X : Type u) (σ : Type v) : Type (max u v)
*Program-stack theory* (aPToP §7.1.0): `push` (a procedure with a parameter), `pop` (a program), `top` (a variable), with `top′=x ⇐ push x` and `ok ⇐ push x. pop`.
Fields
push : X → LaPToP.ProgramTheory.Spec σ
`push x`, "a procedure with parameter of type `X`".
pop : LaPToP.ProgramTheory.Spec σ
`pop`, "a program".
top : σ → X
`top`, a state variable "of type `X`".
top_push : ∀ (x : X), LaPToP.ProgramTheory.Spec.Refines (fun x_1 s' => self.top s' = x) (self.push x)
`top′=x ⇐ push x`.
push_pop : ∀ (x : X), LaPToP.ProgramTheory.Spec.ok.Refines ((self.push x).seq self.pop)
`ok ⇐ push x. pop`: "a pop undoes a push".
-
theoremdefined in LaPToP/TheoryDesign/ProgramStack.leancomplete
theorem LaPToP.TheoryDesign.refinesOfEq.{v} {σ : Type v} {P Q : LaPToP.ProgramTheory.Spec σ} (h : P = Q) : P.Refines Q
theorem LaPToP.TheoryDesign.refinesOfEq.{v} {σ : Type v} {P Q : LaPToP.ProgramTheory.Spec σ} (h : P = Q) : P.Refines Q
A specification refines an equal one.
-
theoremdefined in LaPToP/TheoryDesign/ProgramStack.leancomplete
theorem LaPToP.TheoryDesign.ProgramStackTheory.push_pop_seq.{u, v} {X : Type u} {σ : Type v} (T : LaPToP.TheoryDesign.ProgramStackTheory X σ) (x : X) (P : LaPToP.ProgramTheory.Spec σ) : P.Refines ((T.push x).seq (T.pop.seq P))
theorem LaPToP.TheoryDesign.ProgramStackTheory.push_pop_seq.{u, v} {X : Type u} {σ : Type v} (T : LaPToP.TheoryDesign.ProgramStackTheory X σ) (x : X) (P : LaPToP.ProgramTheory.Spec σ) : P.Refines ((T.push x).seq (T.pop.seq P))
`P ⇐ push x. pop. P`: a push-pop pair before any specification is harmless.
-
defdefined in LaPToP/TheoryDesign/ProgramStack.leancomplete
def LaPToP.TheoryDesign.ProgramStackTheory.balanced.{u, v} {X : Type u} {σ : Type v} (T : LaPToP.TheoryDesign.ProgramStackTheory X σ) : List X → LaPToP.ProgramTheory.Spec σ
def LaPToP.TheoryDesign.ProgramStackTheory.balanced.{u, v} {X : Type u} {σ : Type v} (T : LaPToP.TheoryDesign.ProgramStackTheory X σ) : List X → LaPToP.ProgramTheory.Spec σ
`push x₁. (push x₂. (… (push xₙ. ok. pop) …). pop). pop`: `n` pushes followed by `n` pops.
-
theoremdefined in LaPToP/TheoryDesign/ProgramStack.leancomplete
theorem LaPToP.TheoryDesign.ProgramStackTheory.ok_refines_balanced.{u, v} {X : Type u} {σ : Type v} (T : LaPToP.TheoryDesign.ProgramStackTheory X σ) (xs : List X) : LaPToP.ProgramTheory.Spec.ok.Refines (T.balanced xs)
theorem LaPToP.TheoryDesign.ProgramStackTheory.ok_refines_balanced.{u, v} {X : Type u} {σ : Type v} (T : LaPToP.TheoryDesign.ProgramStackTheory X σ) (xs : List X) : LaPToP.ProgramTheory.Spec.ok.Refines (T.balanced xs)
"Any natural number of pushes are undone by the same number of pops": `ok ⇐ balanced xs`.
-
theoremdefined in LaPToP/TheoryDesign/ProgramStack.leancomplete
theorem LaPToP.TheoryDesign.ProgramStackTheory.ok_refines_push_push_pop_pop.{u, v} {X : Type u} {σ : Type v} (T : LaPToP.TheoryDesign.ProgramStackTheory X σ) (x y : X) : LaPToP.ProgramTheory.Spec.ok.Refines ((T.push x).seq ((T.push y).seq (T.pop.seq T.pop)))
theorem LaPToP.TheoryDesign.ProgramStackTheory.ok_refines_push_push_pop_pop.{u, v} {X : Type u} {σ : Type v} (T : LaPToP.TheoryDesign.ProgramStackTheory X σ) (x y : X) : LaPToP.ProgramTheory.Spec.ok.Refines ((T.push x).seq ((T.push y).seq (T.pop.seq T.pop)))
The book's calculation: `ok ⇐ push x. pop = push x. ok. pop ⇐ push x. push y. pop. pop`.
-
theoremdefined in LaPToP/TheoryDesign/ProgramStack.leancomplete
theorem LaPToP.TheoryDesign.ProgramStackTheory.refines_balanced_seq.{u, v} {X : Type u} {σ : Type v} (T : LaPToP.TheoryDesign.ProgramStackTheory X σ) (xs : List X) (P : LaPToP.ProgramTheory.Spec σ) : P.Refines ((T.balanced xs).seq P)
theorem LaPToP.TheoryDesign.ProgramStackTheory.refines_balanced_seq.{u, v} {X : Type u} {σ : Type v} (T : LaPToP.TheoryDesign.ProgramStackTheory X σ) (xs : List X) (P : LaPToP.ProgramTheory.Spec σ) : P.Refines ((T.balanced xs).seq P)
A balanced block before a specification is harmless: `P ⇐ balanced xs. P`.
-
theoremdefined in LaPToP/TheoryDesign/ProgramStack.leancomplete
theorem LaPToP.TheoryDesign.ProgramStackTheory.top_push_push_push_pop_pop.{u, v} {X : Type u} {σ : Type v} (T : LaPToP.TheoryDesign.ProgramStackTheory X σ) (x y z : X) : LaPToP.ProgramTheory.Spec.Refines (fun x_1 s' => T.top s' = x) ((T.push x).seq ((T.push y).seq ((T.push z).seq (T.pop.seq T.pop))))
theorem LaPToP.TheoryDesign.ProgramStackTheory.top_push_push_push_pop_pop.{u, v} {X : Type u} {σ : Type v} (T : LaPToP.TheoryDesign.ProgramStackTheory X σ) (x y z : X) : LaPToP.ProgramTheory.Spec.Refines (fun x_1 s' => T.top s' = x) ((T.push x).seq ((T.push y).seq ((T.push z).seq (T.pop.seq T.pop))))
"When we push something onto the stack, we find it there later at the appropriate time": `top′=x ⇐ push x. push y. push z. pop. pop`.
-
theoremdefined in LaPToP/TheoryDesign/ProgramStack.leancomplete
theorem LaPToP.TheoryDesign.ProgramStackTheory.top_push_balanced.{u, v} {X : Type u} {σ : Type v} (T : LaPToP.TheoryDesign.ProgramStackTheory X σ) (x : X) (xs : List X) : LaPToP.ProgramTheory.Spec.Refines (fun x_1 s' => T.top s' = x) ((T.push x).seq (T.balanced xs))
theorem LaPToP.TheoryDesign.ProgramStackTheory.top_push_balanced.{u, v} {X : Type u} {σ : Type v} (T : LaPToP.TheoryDesign.ProgramStackTheory X σ) (x : X) (xs : List X) : LaPToP.ProgramTheory.Spec.Refines (fun x_1 s' => T.top s' = x) ((T.push x).seq (T.balanced xs))
Any push is eventually visible: `top′=x ⇐ push x. balanced xs`.
-
LaPToP.TheoryDesign.PS[complete] -
LaPToP.TheoryDesign.ListProgramStack.push[complete] -
LaPToP.TheoryDesign.ListProgramStack.pop[complete] -
LaPToP.TheoryDesign.ListProgramStack.top[complete] -
LaPToP.TheoryDesign.ListProgramStack.top_push[complete] -
LaPToP.TheoryDesign.ListProgramStack.push_pop[complete] -
LaPToP.TheoryDesign.ListProgramStack.theory[complete]
"To implement program-stack theory, we introduce an implementer's variable
s : [*X] and define \mathit{push} = \langle x : X \cdot s := s ;; [x] \rangle,
\mathit{pop} = s := s\,[0;..\# s - 1], \mathit{top} = s\,(\# s - 1). And, of course, we must
show that these definitions satisfy the axioms. We'll do the first axiom
(\mathit{top}' = x \Leftarrow \mathit{push}\ x) = (s'(\# s' - 1) = x \Leftarrow s := s ;; [x]) = \top,
and leave the other as Exercise 429." Both axioms are proved (the second by
(s ;; [x])[0;..\# s] = s), so the list definitions form a
ProgramStackTheory. The implementer's state consists of the variable s
alone; user variables, which the stack operations leave unchanged, would be
added as a product (cf. Definition 6.9). Uses
Definition 8.7 and Theorem 4.10.
Lean code for Theorem8.8●7 declarations
Associated Lean declarations
-
LaPToP.TheoryDesign.PS[complete]
-
LaPToP.TheoryDesign.ListProgramStack.push[complete]
-
LaPToP.TheoryDesign.ListProgramStack.pop[complete]
-
LaPToP.TheoryDesign.ListProgramStack.top[complete]
-
LaPToP.TheoryDesign.ListProgramStack.top_push[complete]
-
LaPToP.TheoryDesign.ListProgramStack.push_pop[complete]
-
LaPToP.TheoryDesign.ListProgramStack.theory[complete]
-
LaPToP.TheoryDesign.PS[complete] -
LaPToP.TheoryDesign.ListProgramStack.push[complete] -
LaPToP.TheoryDesign.ListProgramStack.pop[complete] -
LaPToP.TheoryDesign.ListProgramStack.top[complete] -
LaPToP.TheoryDesign.ListProgramStack.top_push[complete] -
LaPToP.TheoryDesign.ListProgramStack.push_pop[complete] -
LaPToP.TheoryDesign.ListProgramStack.theory[complete]
-
structuredefined in LaPToP/TheoryDesign/ProgramStack.leancomplete
structure LaPToP.TheoryDesign.PS.{u} (X : Type u) : Type u
structure LaPToP.TheoryDesign.PS.{u} (X : Type u) : Type u
The implementer's state: the variable `s: [*X]`.
Fields
s : LaPToP.DataStructures.HList X
The implementer's variable `s`.
-
defdefined in LaPToP/TheoryDesign/ProgramStack.leancomplete
def LaPToP.TheoryDesign.ListProgramStack.push.{u} {X : Type u} (x : X) : LaPToP.ProgramTheory.Spec (LaPToP.TheoryDesign.PS X)
def LaPToP.TheoryDesign.ListProgramStack.push.{u} {X : Type u} (x : X) : LaPToP.ProgramTheory.Spec (LaPToP.TheoryDesign.PS X)
`push x = s:= s;;[x]`.
-
defdefined in LaPToP/TheoryDesign/ProgramStack.leancomplete
def LaPToP.TheoryDesign.ListProgramStack.pop.{u} {X : Type u} : LaPToP.ProgramTheory.Spec (LaPToP.TheoryDesign.PS X)
def LaPToP.TheoryDesign.ListProgramStack.pop.{u} {X : Type u} : LaPToP.ProgramTheory.Spec (LaPToP.TheoryDesign.PS X)
`pop = s:= s[0;..#s–1]`.
-
defdefined in LaPToP/TheoryDesign/ProgramStack.leancomplete
def LaPToP.TheoryDesign.ListProgramStack.top.{u} {X : Type u} [Inhabited X] (st : LaPToP.TheoryDesign.PS X) : X
def LaPToP.TheoryDesign.ListProgramStack.top.{u} {X : Type u} [Inhabited X] (st : LaPToP.TheoryDesign.PS X) : X
`top = s(#s–1)`.
-
theoremdefined in LaPToP/TheoryDesign/ProgramStack.leancomplete
theorem LaPToP.TheoryDesign.ListProgramStack.top_push.{u} {X : Type u} [Inhabited X] (x : X) : LaPToP.ProgramTheory.Spec.Refines (fun x_1 st' => LaPToP.TheoryDesign.ListProgramStack.top st' = x) (LaPToP.TheoryDesign.ListProgramStack.push x)
theorem LaPToP.TheoryDesign.ListProgramStack.top_push.{u} {X : Type u} [Inhabited X] (x : X) : LaPToP.ProgramTheory.Spec.Refines (fun x_1 st' => LaPToP.TheoryDesign.ListProgramStack.top st' = x) (LaPToP.TheoryDesign.ListProgramStack.push x)
The first axiom, the book's calculation: `(top′=x ⇐ push x) = (s′(#s′–1) = x ⇐ s:= s;;[x]) = ⊤`.
-
theoremdefined in LaPToP/TheoryDesign/ProgramStack.leancomplete
theorem LaPToP.TheoryDesign.ListProgramStack.push_pop.{u} {X : Type u} (x : X) : LaPToP.ProgramTheory.Spec.ok.Refines ((LaPToP.TheoryDesign.ListProgramStack.push x).seq LaPToP.TheoryDesign.ListProgramStack.pop)
theorem LaPToP.TheoryDesign.ListProgramStack.push_pop.{u} {X : Type u} (x : X) : LaPToP.ProgramTheory.Spec.ok.Refines ((LaPToP.TheoryDesign.ListProgramStack.push x).seq LaPToP.TheoryDesign.ListProgramStack.pop)
The second axiom, Exercise 429: `ok ⇐ push x. pop`.
-
defdefined in LaPToP/TheoryDesign/ProgramStack.leancomplete
def LaPToP.TheoryDesign.ListProgramStack.theory.{u} (X : Type u) [Inhabited X] : LaPToP.TheoryDesign.ProgramStackTheory X (LaPToP.TheoryDesign.PS X)
def LaPToP.TheoryDesign.ListProgramStack.theory.{u} (X : Type u) [Inhabited X] : LaPToP.TheoryDesign.ProgramStackTheory X (LaPToP.TheoryDesign.PS X)
Lists implement program-stack theory.
-
LaPToP.TheoryDesign.FancyProgramStackTheory[complete] -
LaPToP.TheoryDesign.FancyProgramStackTheory.top_push_not_isempty[complete] -
LaPToP.TheoryDesign.ListProgramStack.mkempty[complete] -
LaPToP.TheoryDesign.ListProgramStack.isempty[complete] -
LaPToP.TheoryDesign.ListProgramStack.fancyTheory[complete] -
LaPToP.TheoryDesign.WeakProgramStackTheory[complete] -
LaPToP.TheoryDesign.WeakProgramStackTheory.balanced[complete] -
LaPToP.TheoryDesign.WeakProgramStackTheory.balance_refines_balanced[complete] -
LaPToP.TheoryDesign.WeakProgramStackTheory.top_balanced[complete] -
LaPToP.TheoryDesign.ProgramStackTheory.toWeak[complete]
"A slightly fancier program-stack theory introduces two more names:
\mathit{mkempty} (a program to make the stack empty) and \mathit{isempty} (a binary
variable to say whether the stack is empty). Letting x : X, the axioms are
\mathit{top}' = x \land \neg\mathit{isempty}' \Leftarrow \mathit{push}\ x, \mathit{ok} \Leftarrow \mathit{push}\ x.\ \mathit{pop},
\mathit{isempty}' \Leftarrow \mathit{mkempty}" — the list implementation satisfies them too.
"The program-stack theory we presented first can be weakened and still retain
its stack character. We must keep the axiom \mathit{top}' = x \Leftarrow \mathit{push}\ x
but we do not need the composition \mathit{push}\ x.\ \mathit{pop} to leave all variables
unchanged. We do require that any natural number of pushes followed by the same
number of pops gives back the original top. The axioms are
\mathit{top}' = \mathit{top} \Leftarrow \mathit{balance}, \mathit{balance} \Leftarrow \mathit{ok},
\mathit{balance} \Leftarrow \mathit{push}\ x.\ \mathit{balance}.\ \mathit{pop}, where \mathit{balance} is a
specification that helps in writing the axioms, but is not an addition to the
theory, and does not need to be implemented." Proved: \mathit{top}' = \mathit{top} after
any number of pushes followed by the same number of pops, and that the strong
theory implies the weak one (with \mathit{balance} := \mathit{ok}). The book's remark
that the weak theory "allows an implementation in which popping ... marks the
last item as garbage" is not formalized. The axiom
\mathbf{screen}!\ \text{“error”} \Leftarrow \mathit{mkempty}.\ \mathit{pop} mentioned for robustness
is a Chapter 9 notation, cf. Definition 6.10. Uses
Definition 8.7 and Theorem 8.8.
Lean code for Definition8.9●10 declarations
Associated Lean declarations
-
LaPToP.TheoryDesign.FancyProgramStackTheory[complete]
-
LaPToP.TheoryDesign.FancyProgramStackTheory.top_push_not_isempty[complete]
-
LaPToP.TheoryDesign.ListProgramStack.mkempty[complete]
-
LaPToP.TheoryDesign.ListProgramStack.isempty[complete]
-
LaPToP.TheoryDesign.ListProgramStack.fancyTheory[complete]
-
LaPToP.TheoryDesign.WeakProgramStackTheory[complete]
-
LaPToP.TheoryDesign.WeakProgramStackTheory.balanced[complete]
-
LaPToP.TheoryDesign.WeakProgramStackTheory.balance_refines_balanced[complete]
-
LaPToP.TheoryDesign.WeakProgramStackTheory.top_balanced[complete]
-
LaPToP.TheoryDesign.ProgramStackTheory.toWeak[complete]
-
LaPToP.TheoryDesign.FancyProgramStackTheory[complete] -
LaPToP.TheoryDesign.FancyProgramStackTheory.top_push_not_isempty[complete] -
LaPToP.TheoryDesign.ListProgramStack.mkempty[complete] -
LaPToP.TheoryDesign.ListProgramStack.isempty[complete] -
LaPToP.TheoryDesign.ListProgramStack.fancyTheory[complete] -
LaPToP.TheoryDesign.WeakProgramStackTheory[complete] -
LaPToP.TheoryDesign.WeakProgramStackTheory.balanced[complete] -
LaPToP.TheoryDesign.WeakProgramStackTheory.balance_refines_balanced[complete] -
LaPToP.TheoryDesign.WeakProgramStackTheory.top_balanced[complete] -
LaPToP.TheoryDesign.ProgramStackTheory.toWeak[complete]
-
structuredefined in LaPToP/TheoryDesign/ProgramStack.leancomplete
structure LaPToP.TheoryDesign.FancyProgramStackTheory.{u, v} (X : Type u) (σ : Type v) : Type (max u v)
structure LaPToP.TheoryDesign.FancyProgramStackTheory.{u, v} (X : Type u) (σ : Type v) : Type (max u v)
The fancy theory adds `mkempty` ("a program to make the stack empty") and `isempty` ("a binary variable to say whether the stack is empty"), with `top′=x ∧ ¬isempty′ ⇐ push x`, `ok ⇐ push x. pop`, `isempty′ ⇐ mkempty`.Extends
-
LaPToP.TheoryDesign.ProgramStackTheory X σ
Fields
push : X → LaPToP.ProgramTheory.Spec σ
Inherited from-
LaPToP.TheoryDesign.ProgramStackTheory
pop : LaPToP.ProgramTheory.Spec σ
Inherited from-
LaPToP.TheoryDesign.ProgramStackTheory
top : σ → X
Inherited from-
LaPToP.TheoryDesign.ProgramStackTheory
top_push : ∀ (x : X), LaPToP.ProgramTheory.Spec.Refines (fun x_1 s' => self.top s' = x) (self.push x)
Inherited from-
LaPToP.TheoryDesign.ProgramStackTheory
push_pop : ∀ (x : X), LaPToP.ProgramTheory.Spec.ok.Refines ((self.push x).seq self.pop)
Inherited from-
LaPToP.TheoryDesign.ProgramStackTheory
mkempty : LaPToP.ProgramTheory.Spec σ
`mkempty`, a program.
isempty : σ → Prop
`isempty`, a binary variable.
not_isempty_push : ∀ (x : X), LaPToP.ProgramTheory.Spec.Refines (fun x s' => ¬self.isempty s') (self.push x)
`¬isempty′ ⇐ push x` (with `top′=x ⇐ push x` inherited).
isempty_mkempty : LaPToP.ProgramTheory.Spec.Refines (fun x s' => self.isempty s') self.mkempty
`isempty′ ⇐ mkempty`.
-
-
theoremdefined in LaPToP/TheoryDesign/ProgramStack.leancomplete
theorem LaPToP.TheoryDesign.FancyProgramStackTheory.top_push_not_isempty.{u, v} {X : Type u} {σ : Type v} (T : LaPToP.TheoryDesign.FancyProgramStackTheory X σ) (x : X) : LaPToP.ProgramTheory.Spec.Refines (fun x_1 s' => T.top s' = x ∧ ¬T.isempty s') (T.push x)
theorem LaPToP.TheoryDesign.FancyProgramStackTheory.top_push_not_isempty.{u, v} {X : Type u} {σ : Type v} (T : LaPToP.TheoryDesign.FancyProgramStackTheory X σ) (x : X) : LaPToP.ProgramTheory.Spec.Refines (fun x_1 s' => T.top s' = x ∧ ¬T.isempty s') (T.push x)
The book's first fancy axiom in one piece: `top′=x ∧ ¬isempty′ ⇐ push x`.
-
defdefined in LaPToP/TheoryDesign/ProgramStack.leancomplete
def LaPToP.TheoryDesign.ListProgramStack.mkempty.{u} {X : Type u} : LaPToP.ProgramTheory.Spec (LaPToP.TheoryDesign.PS X)
def LaPToP.TheoryDesign.ListProgramStack.mkempty.{u} {X : Type u} : LaPToP.ProgramTheory.Spec (LaPToP.TheoryDesign.PS X)
`mkempty = s:= [nil]`.
-
defdefined in LaPToP/TheoryDesign/ProgramStack.leancomplete
def LaPToP.TheoryDesign.ListProgramStack.isempty.{u} {X : Type u} (st : LaPToP.TheoryDesign.PS X) : Prop
def LaPToP.TheoryDesign.ListProgramStack.isempty.{u} {X : Type u} (st : LaPToP.TheoryDesign.PS X) : Prop
`isempty = (s = [nil])`.
-
defdefined in LaPToP/TheoryDesign/ProgramStack.leancomplete
def LaPToP.TheoryDesign.ListProgramStack.fancyTheory.{u} (X : Type u) [Inhabited X] : LaPToP.TheoryDesign.FancyProgramStackTheory X (LaPToP.TheoryDesign.PS X)
def LaPToP.TheoryDesign.ListProgramStack.fancyTheory.{u} (X : Type u) [Inhabited X] : LaPToP.TheoryDesign.FancyProgramStackTheory X (LaPToP.TheoryDesign.PS X)
Lists implement the fancy theory too.
-
structuredefined in LaPToP/TheoryDesign/ProgramStack.leancomplete
structure LaPToP.TheoryDesign.WeakProgramStackTheory.{u, v} (X : Type u) (σ : Type v) : Type (max u v)
structure LaPToP.TheoryDesign.WeakProgramStackTheory.{u, v} (X : Type u) (σ : Type v) : Type (max u v)
The weak theory keeps `top′=x ⇐ push x` "but we do not need the composition `push x. pop` to leave all variables unchanged. We do require that any natural number of pushes followed by the same number of pops gives back the original top": `top′=top ⇐ balance`, `balance ⇐ ok`, `balance ⇐ push x. balance. pop`, "where `balance` is a specification that helps in writing the axioms, but is not an addition to the theory, and does not need to be implemented".
Fields
push : X → LaPToP.ProgramTheory.Spec σ
`push x`.
pop : LaPToP.ProgramTheory.Spec σ
`pop`.
top : σ → X
`top`.
balance : LaPToP.ProgramTheory.Spec σ
`balance`, an auxiliary specification.
top_push : ∀ (x : X), LaPToP.ProgramTheory.Spec.Refines (fun x_1 s' => self.top s' = x) (self.push x)
`top′=x ⇐ push x`.
top_balance : LaPToP.ProgramTheory.Spec.Refines (fun s s' => self.top s' = self.top s) self.balance
`top′=top ⇐ balance`.
balance_ok : self.balance.Refines LaPToP.ProgramTheory.Spec.ok
`balance ⇐ ok`.
balance_push_pop : ∀ (x : X), self.balance.Refines ((self.push x).seq (self.balance.seq self.pop))
`balance ⇐ push x. balance. pop`.
-
defdefined in LaPToP/TheoryDesign/ProgramStack.leancomplete
def LaPToP.TheoryDesign.WeakProgramStackTheory.balanced.{u, v} {X : Type u} {σ : Type v} (T : LaPToP.TheoryDesign.WeakProgramStackTheory X σ) : List X → LaPToP.ProgramTheory.Spec σ
def LaPToP.TheoryDesign.WeakProgramStackTheory.balanced.{u, v} {X : Type u} {σ : Type v} (T : LaPToP.TheoryDesign.WeakProgramStackTheory X σ) : List X → LaPToP.ProgramTheory.Spec σ
`n` pushes followed by `n` pops, as for the strong theory.
-
theoremdefined in LaPToP/TheoryDesign/ProgramStack.leancomplete
theorem LaPToP.TheoryDesign.WeakProgramStackTheory.balance_refines_balanced.{u, v} {X : Type u} {σ : Type v} (T : LaPToP.TheoryDesign.WeakProgramStackTheory X σ) (xs : List X) : T.balance.Refines (T.balanced xs)
theorem LaPToP.TheoryDesign.WeakProgramStackTheory.balance_refines_balanced.{u, v} {X : Type u} {σ : Type v} (T : LaPToP.TheoryDesign.WeakProgramStackTheory X σ) (xs : List X) : T.balance.Refines (T.balanced xs)
`balance ⇐ balanced xs`.
-
theoremdefined in LaPToP/TheoryDesign/ProgramStack.leancomplete
theorem LaPToP.TheoryDesign.WeakProgramStackTheory.top_balanced.{u, v} {X : Type u} {σ : Type v} (T : LaPToP.TheoryDesign.WeakProgramStackTheory X σ) (xs : List X) : LaPToP.ProgramTheory.Spec.Refines (fun s s' => T.top s' = T.top s) (T.balanced xs)
theorem LaPToP.TheoryDesign.WeakProgramStackTheory.top_balanced.{u, v} {X : Type u} {σ : Type v} (T : LaPToP.TheoryDesign.WeakProgramStackTheory X σ) (xs : List X) : LaPToP.ProgramTheory.Spec.Refines (fun s s' => T.top s' = T.top s) (T.balanced xs)
"Any natural number of pushes followed by the same number of pops gives back the original top": `top′=top ⇐ balanced xs`.
-
defdefined in LaPToP/TheoryDesign/ProgramStack.leancomplete
def LaPToP.TheoryDesign.ProgramStackTheory.toWeak.{u, v} {X : Type u} {σ : Type v} (T : LaPToP.TheoryDesign.ProgramStackTheory X σ) : LaPToP.TheoryDesign.WeakProgramStackTheory X σ
def LaPToP.TheoryDesign.ProgramStackTheory.toWeak.{u, v} {X : Type u} {σ : Type v} (T : LaPToP.TheoryDesign.ProgramStackTheory X σ) : LaPToP.TheoryDesign.WeakProgramStackTheory X σ
The strong theory implies the weak one, with `balance := ok`.