import Mathlib.Tactic.Ring namespace StackMachine -- ANCHOR: ops inductive Op where | push : Int → Op | pop : Op | add : Op | mul : Op | dup : Op deriving Repr, DecidableEq -- ANCHOR_END: ops -- ANCHOR: run def run : List Op → List Int → List Int | [], stack => stack | .push n :: ops, stack => run ops (n :: stack) | .pop :: ops, _ :: stack => run ops stack | .pop :: ops, [] => run ops [] | .add :: ops, b :: a :: stack => run ops ((a + b) :: stack) | .add :: ops, stack => run ops stack | .mul :: ops, b :: a :: stack => run ops ((a * b) :: stack) | .mul :: ops, stack => run ops stack | .dup :: ops, x :: stack => run ops (x :: x :: stack) | .dup :: ops, [] => run ops [] -- ANCHOR_END: run -- ANCHOR: examples #eval run [.push 3, .push 4, .add] [] #eval run [.push 3, .push 4, .mul] [] #eval run [.push 5, .dup, .mul] [] #eval run [.push 10, .push 3, .pop] [] -- ANCHOR_END: examples -- ANCHOR: composition theorem run_append (p1 p2 : List Op) (s : List Int) : run (p1 ++ p2) s = run p2 (run p1 s) := by induction p1 generalizing s with | nil => rfl | cons op ops ih => cases op with | push n => exact ih _ | pop => cases s <;> exact ih _ | add => match s with | [] | [_] => exact ih _ | _ :: _ :: _ => exact ih _ | mul => match s with | [] | [_] => exact ih _ | _ :: _ :: _ => exact ih _ | dup => cases s <;> exact ih _ -- ANCHOR_END: composition -- ANCHOR: effect def effect : Op → Int | .push _ => 1 | .pop => -1 | .add => -1 | .mul => -1 | .dup => 1 def totalEffect : List Op → Int | [] => 0 | op :: ops => effect op + totalEffect ops theorem effect_append (p1 p2 : List Op) : totalEffect (p1 ++ p2) = totalEffect p1 + totalEffect p2 := by induction p1 with | nil => simp [totalEffect] | cons op ops ih => simp [totalEffect, ih]; ring -- ANCHOR_END: effect -- ANCHOR: depth def minDepth : Op → Nat | .push _ => 0 | .pop => 1 | .add => 2 | .mul => 2 | .dup => 1 def isSafe : Nat → List Op → Bool | _, [] => true | d, op :: ops => d ≥ minDepth op && isSafe ((d : Int) + effect op).toNat ops #eval isSafe 0 [.push 3, .push 4, .add] #eval isSafe 0 [.add] #eval isSafe 2 [.add] #eval isSafe 0 [.push 1, .pop, .pop] -- ANCHOR_END: depth -- ANCHOR: equivalence theorem add_comm (n m : Int) (rest : List Op) (s : List Int) : run (.push n :: .push m :: .add :: rest) s = run (.push m :: .push n :: .add :: rest) s := by simp [run, Int.add_comm] theorem mul_comm (n m : Int) (rest : List Op) (s : List Int) : run (.push n :: .push m :: .mul :: rest) s = run (.push m :: .push n :: .mul :: rest) s := by simp [run, Int.mul_comm] theorem dup_add_eq_double (n : Int) (rest : List Op) (s : List Int) : run (.push n :: .dup :: .add :: rest) s = run (.push (n + n) :: rest) s := by simp [run] theorem dup_mul_eq_square (n : Int) (rest : List Op) (s : List Int) : run (.push n :: .dup :: .mul :: rest) s = run (.push (n * n) :: rest) s := by simp [run] -- ANCHOR_END: equivalence -- ANCHOR: universal example : ∀ p1 p2 s, run (p1 ++ p2) s = run p2 (run p1 s) := run_append example : ∀ p1 p2, totalEffect (p1 ++ p2) = totalEffect p1 + totalEffect p2 := effect_append -- ANCHOR_END: universal end StackMachine def stackMain : IO Unit := do IO.println s!"push 5; dup; mul => {StackMachine.run [.push 5, .dup, .mul] []}"