Add environment, expr, and stmt equivalence lemmas

This commit is contained in:
2026-10-06 19:44:57 -05:00
parent 655b7de684
commit f55a440784
2 changed files with 136 additions and 0 deletions

View File

@@ -0,0 +1,135 @@
import Spa.Language.Semantics
namespace Spa
/-- Environments agree on the current values of the selected variables. -/
def Env.AgreeOn (xs : Finset String) (ρ σ : Env) : Prop :=
∀ x ∈ xs, ∀ v, Env.Mem (x, v) ρ ↔ Env.Mem (x, v) σ
/-- Observable environment equality, ignoring shadowed bindings. -/
def Env.Equiv (ρ σ : Env) : Prop :=
∀ x v, Env.Mem (x, v) ρ ↔ Env.Mem (x, v) σ
lemma Env.Mem.functional {ρ : Env} {x : String} {v w : Value}
(h : Env.Mem (x, v) ρ) (h' : Env.Mem (x, w) ρ) : v = w := by
induction ρ with
| nil => cases h
| cons pair rest ih =>
cases h <;> cases h' <;> aesop
lemma Env.mem_cons {ρ : Env} {x y : String} {v w : Value} :
Env.Mem (x, v) ((y, w) :: ρ) ↔ (x = y ∧ v = w) ∨ (x ≠ y ∧ Env.Mem (x, v) ρ) := by
constructor
· intro h; cases h <;> aesop
· rintro (⟨rfl, rfl⟩ | ⟨hne, h⟩)
· exact .here _ _ _
· exact .there _ _ _ _ _ hne h
lemma Env.Equiv.refl (ρ : Env) : Env.Equiv ρ ρ := fun _ _ => Iff.rfl
lemma Env.Equiv.symm {ρ σ : Env} (h : Env.Equiv ρ σ) : Env.Equiv σ ρ :=
fun x v => (h x v).symm
lemma Env.Equiv.trans {ρ σ τ : Env} (h : Env.Equiv ρ σ) (h' : Env.Equiv σ τ) :
Env.Equiv ρ τ := fun x v => (h x v).trans (h' x v)
lemma Env.Equiv.cons {ρ σ : Env} (h : Env.Equiv ρ σ) (x : String) (v : Value) :
Env.Equiv ((x, v) :: ρ) ((x, v) :: σ) := by
intro y w; simp only [Env.mem_cons, h y w]
lemma Env.cons_equiv_of_mem {ρ : Env} {x : String} {v : Value}
(h : Env.Mem (x, v) ρ) : Env.Equiv ((x, v) :: ρ) ρ := by
intro y w
rw [Env.mem_cons]
constructor
· rintro (⟨rfl, rfl⟩ | ⟨_, hw⟩) <;> assumption
· intro hw
by_cases he : y = x
· subst y; exact Or.inl ⟨rfl, hw.functional h⟩
· exact Or.inr ⟨he, hw⟩
lemma EvalExpr.congr_env {ρ σ : Env} {e : Expr} {v : Value}
(h : EvalExpr ρ e v) (ha : Env.AgreeOn e.vars ρ σ) : EvalExpr σ e v := by
induction h with
| num => exact .num _ _
| var x v hm => exact .var _ _ _ ((ha x (by simp [Expr.vars]) v).mp hm)
| add a b u v _ _ iha ihb =>
exact .add _ _ _ _ _ (iha (fun x hx => ha x (Finset.mem_union_left _ hx)))
(ihb (fun x hx => ha x (Finset.mem_union_right _ hx)))
| sub a b u v _ _ iha ihb =>
exact .sub _ _ _ _ _ (iha (fun x hx => ha x (Finset.mem_union_left _ hx)))
(ihb (fun x hx => ha x (Finset.mem_union_right _ hx)))
lemma EvalExpr.deterministic {ρ : Env} {e : Expr} {v w : Value}
(h : EvalExpr ρ e v) (h' : EvalExpr ρ e w) : v = w := by
induction h generalizing w with
| num => cases h'; rfl
| var _ _ hm => cases h' with | var _ _ hm' => exact hm.functional hm'
| add a b u v h₁ h₂ ih₁ ih₂ =>
cases h' with
| add _ _ u' v' h₁' h₂' =>
have := ih₁ h₁'; have := ih₂ h₂'; aesop
| sub a b u v h₁ h₂ ih₁ ih₂ =>
cases h' with
| sub _ _ u' v' h₁' h₂' =>
have := ih₁ h₁'; have := ih₂ h₂'; aesop
/-- Variables a statement may assign. -/
def Stmt.writes : Stmt → Finset String
| .basic .noop => ∅
| .basic (.assign x _) => {x}
| .andThen a b => a.writes ∪ b.writes
| .ifElse _ a b => a.writes ∪ b.writes
| .whileLoop _ b => b.writes
lemma EvalStmt.preserves_unwritten {ρ σ : Env} {s : Stmt} (h : EvalStmt ρ s σ)
{x : String} (hx : x ∉ s.writes) :
∀ v, Env.Mem (x, v) ρ ↔ Env.Mem (x, v) σ := by
induction h with
| basic _ _ _ hb =>
cases hb with
| noop => exact fun _ => Iff.rfl
| assign y _ _ _ =>
have hn : x ≠ y := by simpa [Stmt.writes] using hx
intro v; simp [Env.mem_cons, hn]
| andThen _ _ _ _ _ _ _ ih₁ ih₂ =>
simp only [Stmt.writes, Finset.mem_union, not_or] at hx
exact fun v => (ih₁ hx.1 v).trans (ih₂ hx.2 v)
| ifTrue _ _ _ _ _ _ _ _ _ ih =>
exact ih (fun hm => hx (Finset.mem_union_left _ hm))
| ifFalse _ _ _ _ _ _ _ ih =>
exact ih (fun hm => hx (Finset.mem_union_right _ hm))
| whileTrue _ _ _ _ _ _ _ _ _ _ ih₁ ih₂ =>
exact fun v => (ih₁ hx v).trans (ih₂ hx v)
| whileFalse => exact fun _ => Iff.rfl
/-- Evaluations depend on current bindings, not the list of shadowed bindings. -/
noncomputable def EvalStmt.congr_env {ρ ρ' : Env} {s : Stmt} (h : EvalStmt ρ s ρ') :
∀ {σ}, Env.Equiv ρ σ → Σ σ', {_h : EvalStmt σ s σ' // Env.Equiv ρ' σ'} := by
induction h with
| basic _ _ _ hb =>
intro σ he
cases hb with
| noop => exact ⟨σ, .basic _ _ _ (.noop _), he⟩
| assign x rhs v hv =>
exact ⟨_, .basic _ _ _ (.assign _ _ _ _ (hv.congr_env (fun y _ => he y))), he.cons x v⟩
| andThen _ _ _ _ _ _ _ ih₁ ih₂ =>
intro σ he
obtain ⟨σ₁, h₁, he₁⟩ := ih₁ he
obtain ⟨σ₂, h₂, he₂⟩ := ih₂ he₁
exact ⟨σ₂, .andThen _ _ _ _ _ h₁ h₂, he₂⟩
| ifTrue _ _ _ _ _ _ hc hz _ ih =>
intro σ he
obtain ⟨σ', h', he'⟩ := ih he
exact ⟨σ', .ifTrue _ _ _ _ _ _ (hc.congr_env (fun x _ => he x)) hz h', he'⟩
| ifFalse _ _ _ _ _ hc _ ih =>
intro σ he
obtain ⟨σ', h', he'⟩ := ih he
exact ⟨σ', .ifFalse _ _ _ _ _ (hc.congr_env (fun x _ => he x)) h', he'⟩
| whileTrue _ _ _ _ _ _ hc hz _ _ ih₁ ih₂ =>
intro σ he
obtain ⟨σ₁, h₁, he₁⟩ := ih₁ he
obtain ⟨σ₂, h₂, he₂⟩ := ih₂ he₁
exact ⟨σ₂, .whileTrue _ _ _ _ _ _ (hc.congr_env (fun x _ => he x)) hz h₁ h₂, he₂⟩
| whileFalse _ _ _ hc =>
intro σ he
exact ⟨σ, .whileFalse _ _ _ (hc.congr_env (fun x _ => he x)), he⟩
end Spa