2026-06-09 20:14:53 -07:00
|
|
|
|
import Spa.Language
|
|
|
|
|
|
import Spa.Lattice.FiniteMap
|
2026-06-23 13:29:54 -05:00
|
|
|
|
import Spa.Interp
|
2026-06-09 20:14:53 -07:00
|
|
|
|
|
|
|
|
|
|
namespace Spa
|
|
|
|
|
|
|
2026-06-24 13:54:37 -05:00
|
|
|
|
namespace Forward
|
|
|
|
|
|
|
2026-06-09 20:14:53 -07:00
|
|
|
|
variable (L : Type) [Lattice L] (prog : Program)
|
|
|
|
|
|
|
|
|
|
|
|
abbrev VariableValues : Type := FiniteMap String L prog.vars
|
|
|
|
|
|
|
|
|
|
|
|
abbrev StateVariables : Type := FiniteMap prog.State (VariableValues L prog) prog.states
|
|
|
|
|
|
|
Lean migration: typeclass-based parameter passing, as in the Agda original
The port had flattened Agda's instance arguments ({{flA}}, {{evaluator}},
{{latticeInterpretation}}, {{validEvaluator}}) into explicitly threaded
values (fhL, E, I, hE). Restore them as typeclasses:
- Spa.FiniteHeightLattice: now actually used — Fixedpoint takes the
instance instead of a FixedHeight value; FiniteMap gets the missing
instance (height = ks.length * height B), so varsFixedHeight /
statesFixedHeight / signFixedHeight / constFixedHeight plumbing
disappears (instance bottoms are defeq to the old ones)
- Spa.Analysis.Forward.Evaluation: StmtEvaluator/ExprEvaluator become
classes; the Valid* Props become Prop-classes, as in Agda
- Spa.Analysis.Forward.Adapters: the expr→stmt adapter and its validity
are instances (Agda: the ExprToStmtAdapter instances)
- LatticeInterpretation is a class; sign/const interpretations,
evaluators and validity proofs are instances; use sites read like the
Agda module applications: result SignLattice prog
Proof simplifications (same theorems, proofs factored):
- Spa.Lattice.AboveBelow.monotone₂_of_strict: any ⊥-strict/⊤-dominated
operation on a flat lattice is monotone — replaces the four near-
identical case bashes per analysis (postulates in Agda)
- Spa.Lattice.AboveBelow.interp_sup_of/interp_inf_of: the shared flat-
lattice interpretation case analysis, making interpSign_sup/inf and
interpConst_sup/inf one-liners
lake build green with zero warnings; lake exe spa output verified
byte-identical (diff) to the previous, Agda-verified output.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-06-09 23:32:38 -07:00
|
|
|
|
def botV [FiniteHeightLattice L] : VariableValues L prog :=
|
2026-06-22 18:33:48 -05:00
|
|
|
|
(⊥ : VariableValues L prog)
|
2026-06-09 20:14:53 -07:00
|
|
|
|
|
|
|
|
|
|
variable {L prog}
|
|
|
|
|
|
|
|
|
|
|
|
omit [Lattice L] in
|
2026-06-25 13:59:08 -05:00
|
|
|
|
lemma states_memKey (s : prog.State) (sv : StateVariables L prog) :
|
2026-06-09 20:14:53 -07:00
|
|
|
|
FiniteMap.MemKey s sv :=
|
2026-06-25 13:28:30 -05:00
|
|
|
|
FiniteMap.MemKey_iff.mpr (prog.states_complete s)
|
2026-06-09 20:14:53 -07:00
|
|
|
|
|
|
|
|
|
|
def variablesAt (s : prog.State) (sv : StateVariables L prog) :
|
|
|
|
|
|
VariableValues L prog :=
|
|
|
|
|
|
(FiniteMap.locate (states_memKey s sv)).1
|
|
|
|
|
|
|
|
|
|
|
|
omit [Lattice L] in
|
2026-06-25 13:59:08 -05:00
|
|
|
|
lemma variablesAt_mem (s : prog.State) (sv : StateVariables L prog) :
|
2026-06-09 20:14:53 -07:00
|
|
|
|
(s, variablesAt s sv) ∈ sv :=
|
|
|
|
|
|
(FiniteMap.locate (states_memKey s sv)).2
|
|
|
|
|
|
|
2026-06-25 13:59:08 -05:00
|
|
|
|
lemma variablesAt_le {sv₁ sv₂ : StateVariables L prog} (hle : sv₁ ≤ sv₂)
|
2026-06-09 20:14:53 -07:00
|
|
|
|
(s : prog.State) : variablesAt s sv₁ ≤ variablesAt s sv₂ :=
|
|
|
|
|
|
FiniteMap.le_of_mem_mem prog.states_nodup hle
|
|
|
|
|
|
(variablesAt_mem s sv₁) (variablesAt_mem s sv₂)
|
|
|
|
|
|
|
Lean migration: typeclass-based parameter passing, as in the Agda original
The port had flattened Agda's instance arguments ({{flA}}, {{evaluator}},
{{latticeInterpretation}}, {{validEvaluator}}) into explicitly threaded
values (fhL, E, I, hE). Restore them as typeclasses:
- Spa.FiniteHeightLattice: now actually used — Fixedpoint takes the
instance instead of a FixedHeight value; FiniteMap gets the missing
instance (height = ks.length * height B), so varsFixedHeight /
statesFixedHeight / signFixedHeight / constFixedHeight plumbing
disappears (instance bottoms are defeq to the old ones)
- Spa.Analysis.Forward.Evaluation: StmtEvaluator/ExprEvaluator become
classes; the Valid* Props become Prop-classes, as in Agda
- Spa.Analysis.Forward.Adapters: the expr→stmt adapter and its validity
are instances (Agda: the ExprToStmtAdapter instances)
- LatticeInterpretation is a class; sign/const interpretations,
evaluators and validity proofs are instances; use sites read like the
Agda module applications: result SignLattice prog
Proof simplifications (same theorems, proofs factored):
- Spa.Lattice.AboveBelow.monotone₂_of_strict: any ⊥-strict/⊤-dominated
operation on a flat lattice is monotone — replaces the four near-
identical case bashes per analysis (postulates in Agda)
- Spa.Lattice.AboveBelow.interp_sup_of/interp_inf_of: the shared flat-
lattice interpretation case analysis, making interpSign_sup/inf and
interpConst_sup/inf one-liners
lake build green with zero warnings; lake exe spa output verified
byte-identical (diff) to the previous, Agda-verified output.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-06-09 23:32:38 -07:00
|
|
|
|
variable [FiniteHeightLattice L]
|
2026-06-09 20:14:53 -07:00
|
|
|
|
|
|
|
|
|
|
def joinForKey (k : prog.State) (sv : StateVariables L prog) :
|
|
|
|
|
|
VariableValues L prog :=
|
Lean migration: typeclass-based parameter passing, as in the Agda original
The port had flattened Agda's instance arguments ({{flA}}, {{evaluator}},
{{latticeInterpretation}}, {{validEvaluator}}) into explicitly threaded
values (fhL, E, I, hE). Restore them as typeclasses:
- Spa.FiniteHeightLattice: now actually used — Fixedpoint takes the
instance instead of a FixedHeight value; FiniteMap gets the missing
instance (height = ks.length * height B), so varsFixedHeight /
statesFixedHeight / signFixedHeight / constFixedHeight plumbing
disappears (instance bottoms are defeq to the old ones)
- Spa.Analysis.Forward.Evaluation: StmtEvaluator/ExprEvaluator become
classes; the Valid* Props become Prop-classes, as in Agda
- Spa.Analysis.Forward.Adapters: the expr→stmt adapter and its validity
are instances (Agda: the ExprToStmtAdapter instances)
- LatticeInterpretation is a class; sign/const interpretations,
evaluators and validity proofs are instances; use sites read like the
Agda module applications: result SignLattice prog
Proof simplifications (same theorems, proofs factored):
- Spa.Lattice.AboveBelow.monotone₂_of_strict: any ⊥-strict/⊤-dominated
operation on a flat lattice is monotone — replaces the four near-
identical case bashes per analysis (postulates in Agda)
- Spa.Lattice.AboveBelow.interp_sup_of/interp_inf_of: the shared flat-
lattice interpretation case analysis, making interpSign_sup/inf and
interpConst_sup/inf one-liners
lake build green with zero warnings; lake exe spa output verified
byte-identical (diff) to the previous, Agda-verified output.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-06-09 23:32:38 -07:00
|
|
|
|
(sv.valuesAt (prog.incoming k)).foldr (· ⊔ ·) (botV L prog)
|
2026-06-09 20:14:53 -07:00
|
|
|
|
|
2026-06-25 13:59:08 -05:00
|
|
|
|
lemma joinForKey_mono (k : prog.State) :
|
Lean migration: typeclass-based parameter passing, as in the Agda original
The port had flattened Agda's instance arguments ({{flA}}, {{evaluator}},
{{latticeInterpretation}}, {{validEvaluator}}) into explicitly threaded
values (fhL, E, I, hE). Restore them as typeclasses:
- Spa.FiniteHeightLattice: now actually used — Fixedpoint takes the
instance instead of a FixedHeight value; FiniteMap gets the missing
instance (height = ks.length * height B), so varsFixedHeight /
statesFixedHeight / signFixedHeight / constFixedHeight plumbing
disappears (instance bottoms are defeq to the old ones)
- Spa.Analysis.Forward.Evaluation: StmtEvaluator/ExprEvaluator become
classes; the Valid* Props become Prop-classes, as in Agda
- Spa.Analysis.Forward.Adapters: the expr→stmt adapter and its validity
are instances (Agda: the ExprToStmtAdapter instances)
- LatticeInterpretation is a class; sign/const interpretations,
evaluators and validity proofs are instances; use sites read like the
Agda module applications: result SignLattice prog
Proof simplifications (same theorems, proofs factored):
- Spa.Lattice.AboveBelow.monotone₂_of_strict: any ⊥-strict/⊤-dominated
operation on a flat lattice is monotone — replaces the four near-
identical case bashes per analysis (postulates in Agda)
- Spa.Lattice.AboveBelow.interp_sup_of/interp_inf_of: the shared flat-
lattice interpretation case analysis, making interpSign_sup/inf and
interpConst_sup/inf one-liners
lake build green with zero warnings; lake exe spa output verified
byte-identical (diff) to the previous, Agda-verified output.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-06-09 23:32:38 -07:00
|
|
|
|
Monotone (joinForKey (L := L) k) := by
|
2026-06-09 20:14:53 -07:00
|
|
|
|
intro sv₁ sv₂ hle
|
|
|
|
|
|
exact foldr_mono _ (FiniteMap.valuesAt_le hle (prog.incoming k)) (le_refl _)
|
|
|
|
|
|
(fun b _ _ hab => sup_le_sup_right hab b)
|
|
|
|
|
|
(fun a _ _ hab => sup_le_sup_left hab a)
|
|
|
|
|
|
|
|
|
|
|
|
def joinAll (sv : StateVariables L prog) : StateVariables L prog :=
|
Lean migration: typeclass-based parameter passing, as in the Agda original
The port had flattened Agda's instance arguments ({{flA}}, {{evaluator}},
{{latticeInterpretation}}, {{validEvaluator}}) into explicitly threaded
values (fhL, E, I, hE). Restore them as typeclasses:
- Spa.FiniteHeightLattice: now actually used — Fixedpoint takes the
instance instead of a FixedHeight value; FiniteMap gets the missing
instance (height = ks.length * height B), so varsFixedHeight /
statesFixedHeight / signFixedHeight / constFixedHeight plumbing
disappears (instance bottoms are defeq to the old ones)
- Spa.Analysis.Forward.Evaluation: StmtEvaluator/ExprEvaluator become
classes; the Valid* Props become Prop-classes, as in Agda
- Spa.Analysis.Forward.Adapters: the expr→stmt adapter and its validity
are instances (Agda: the ExprToStmtAdapter instances)
- LatticeInterpretation is a class; sign/const interpretations,
evaluators and validity proofs are instances; use sites read like the
Agda module applications: result SignLattice prog
Proof simplifications (same theorems, proofs factored):
- Spa.Lattice.AboveBelow.monotone₂_of_strict: any ⊥-strict/⊤-dominated
operation on a flat lattice is monotone — replaces the four near-
identical case bashes per analysis (postulates in Agda)
- Spa.Lattice.AboveBelow.interp_sup_of/interp_inf_of: the shared flat-
lattice interpretation case analysis, making interpSign_sup/inf and
interpConst_sup/inf one-liners
lake build green with zero warnings; lake exe spa output verified
byte-identical (diff) to the previous, Agda-verified output.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-06-09 23:32:38 -07:00
|
|
|
|
FiniteMap.generalizedUpdate id joinForKey prog.states sv
|
2026-06-09 20:14:53 -07:00
|
|
|
|
|
2026-06-25 13:59:08 -05:00
|
|
|
|
lemma joinAll_mono : Monotone (joinAll (L := L) (prog := prog)) :=
|
Lean migration: typeclass-based parameter passing, as in the Agda original
The port had flattened Agda's instance arguments ({{flA}}, {{evaluator}},
{{latticeInterpretation}}, {{validEvaluator}}) into explicitly threaded
values (fhL, E, I, hE). Restore them as typeclasses:
- Spa.FiniteHeightLattice: now actually used — Fixedpoint takes the
instance instead of a FixedHeight value; FiniteMap gets the missing
instance (height = ks.length * height B), so varsFixedHeight /
statesFixedHeight / signFixedHeight / constFixedHeight plumbing
disappears (instance bottoms are defeq to the old ones)
- Spa.Analysis.Forward.Evaluation: StmtEvaluator/ExprEvaluator become
classes; the Valid* Props become Prop-classes, as in Agda
- Spa.Analysis.Forward.Adapters: the expr→stmt adapter and its validity
are instances (Agda: the ExprToStmtAdapter instances)
- LatticeInterpretation is a class; sign/const interpretations,
evaluators and validity proofs are instances; use sites read like the
Agda module applications: result SignLattice prog
Proof simplifications (same theorems, proofs factored):
- Spa.Lattice.AboveBelow.monotone₂_of_strict: any ⊥-strict/⊤-dominated
operation on a flat lattice is monotone — replaces the four near-
identical case bashes per analysis (postulates in Agda)
- Spa.Lattice.AboveBelow.interp_sup_of/interp_inf_of: the shared flat-
lattice interpretation case analysis, making interpSign_sup/inf and
interpConst_sup/inf one-liners
lake build green with zero warnings; lake exe spa output verified
byte-identical (diff) to the previous, Agda-verified output.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-06-09 23:32:38 -07:00
|
|
|
|
FiniteMap.generalizedUpdate_monotone monotone_id joinForKey_mono
|
2026-06-09 20:14:53 -07:00
|
|
|
|
|
2026-06-25 13:59:08 -05:00
|
|
|
|
lemma joinAll_mem_eq {s : prog.State} {vs : VariableValues L prog}
|
Lean migration: typeclass-based parameter passing, as in the Agda original
The port had flattened Agda's instance arguments ({{flA}}, {{evaluator}},
{{latticeInterpretation}}, {{validEvaluator}}) into explicitly threaded
values (fhL, E, I, hE). Restore them as typeclasses:
- Spa.FiniteHeightLattice: now actually used — Fixedpoint takes the
instance instead of a FixedHeight value; FiniteMap gets the missing
instance (height = ks.length * height B), so varsFixedHeight /
statesFixedHeight / signFixedHeight / constFixedHeight plumbing
disappears (instance bottoms are defeq to the old ones)
- Spa.Analysis.Forward.Evaluation: StmtEvaluator/ExprEvaluator become
classes; the Valid* Props become Prop-classes, as in Agda
- Spa.Analysis.Forward.Adapters: the expr→stmt adapter and its validity
are instances (Agda: the ExprToStmtAdapter instances)
- LatticeInterpretation is a class; sign/const interpretations,
evaluators and validity proofs are instances; use sites read like the
Agda module applications: result SignLattice prog
Proof simplifications (same theorems, proofs factored):
- Spa.Lattice.AboveBelow.monotone₂_of_strict: any ⊥-strict/⊤-dominated
operation on a flat lattice is monotone — replaces the four near-
identical case bashes per analysis (postulates in Agda)
- Spa.Lattice.AboveBelow.interp_sup_of/interp_inf_of: the shared flat-
lattice interpretation case analysis, making interpSign_sup/inf and
interpConst_sup/inf one-liners
lake build green with zero warnings; lake exe spa output verified
byte-identical (diff) to the previous, Agda-verified output.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-06-09 23:32:38 -07:00
|
|
|
|
{sv : StateVariables L prog} (h : (s, vs) ∈ joinAll sv) :
|
|
|
|
|
|
vs = joinForKey s sv :=
|
2026-06-09 20:14:53 -07:00
|
|
|
|
FiniteMap.generalizedUpdate_mem_eq (prog.states_complete s) h
|
|
|
|
|
|
|
2026-06-25 13:59:08 -05:00
|
|
|
|
lemma variablesAt_joinAll (s : prog.State) (sv : StateVariables L prog) :
|
Lean migration: typeclass-based parameter passing, as in the Agda original
The port had flattened Agda's instance arguments ({{flA}}, {{evaluator}},
{{latticeInterpretation}}, {{validEvaluator}}) into explicitly threaded
values (fhL, E, I, hE). Restore them as typeclasses:
- Spa.FiniteHeightLattice: now actually used — Fixedpoint takes the
instance instead of a FixedHeight value; FiniteMap gets the missing
instance (height = ks.length * height B), so varsFixedHeight /
statesFixedHeight / signFixedHeight / constFixedHeight plumbing
disappears (instance bottoms are defeq to the old ones)
- Spa.Analysis.Forward.Evaluation: StmtEvaluator/ExprEvaluator become
classes; the Valid* Props become Prop-classes, as in Agda
- Spa.Analysis.Forward.Adapters: the expr→stmt adapter and its validity
are instances (Agda: the ExprToStmtAdapter instances)
- LatticeInterpretation is a class; sign/const interpretations,
evaluators and validity proofs are instances; use sites read like the
Agda module applications: result SignLattice prog
Proof simplifications (same theorems, proofs factored):
- Spa.Lattice.AboveBelow.monotone₂_of_strict: any ⊥-strict/⊤-dominated
operation on a flat lattice is monotone — replaces the four near-
identical case bashes per analysis (postulates in Agda)
- Spa.Lattice.AboveBelow.interp_sup_of/interp_inf_of: the shared flat-
lattice interpretation case analysis, making interpSign_sup/inf and
interpConst_sup/inf one-liners
lake build green with zero warnings; lake exe spa output verified
byte-identical (diff) to the previous, Agda-verified output.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-06-09 23:32:38 -07:00
|
|
|
|
variablesAt s (joinAll sv) = joinForKey s sv :=
|
|
|
|
|
|
joinAll_mem_eq (variablesAt_mem s (joinAll sv))
|
2026-06-09 20:14:53 -07:00
|
|
|
|
|
2026-06-27 16:29:16 -05:00
|
|
|
|
class StateInterp (L : Type) [Lattice L] (prog : Program) where
|
|
|
|
|
|
St : Env → Type
|
|
|
|
|
|
init : St []
|
|
|
|
|
|
interp : VariableValues L prog → (ρ : Env) → St ρ → Prop
|
|
|
|
|
|
interp_sup : ∀ {vs₁ vs₂ : VariableValues L prog} {ρ : Env} {st : St ρ},
|
|
|
|
|
|
interp vs₁ ρ st ∨ interp vs₂ ρ st → interp (vs₁ ⊔ vs₂) ρ st
|
|
|
|
|
|
interp_inf : ∀ {vs₁ vs₂ : VariableValues L prog} {ρ : Env} {st : St ρ},
|
|
|
|
|
|
interp vs₁ ρ st ∧ interp vs₂ ρ st → interp (vs₁ ⊓ vs₂) ρ st
|
|
|
|
|
|
|
|
|
|
|
|
instance [S : StateInterp L prog] :
|
|
|
|
|
|
Interp (VariableValues L prog) ((ρ : Env) → S.St ρ → Prop) :=
|
|
|
|
|
|
⟨S.interp⟩
|
|
|
|
|
|
|
|
|
|
|
|
lemma interp_foldr [S : StateInterp L prog]
|
|
|
|
|
|
{vs : VariableValues L prog} {vss : List (VariableValues L prog)}
|
|
|
|
|
|
{ρ : Env} {st : S.St ρ} (hvs : ⟦ vs ⟧ ρ st) (hmem : vs ∈ vss) :
|
|
|
|
|
|
⟦ vss.foldr (· ⊔ ·) (botV L prog) ⟧ ρ st := by
|
2026-06-09 20:14:53 -07:00
|
|
|
|
induction vss with
|
|
|
|
|
|
| nil => cases hmem
|
|
|
|
|
|
| cons vs' vss' ih =>
|
|
|
|
|
|
rcases List.mem_cons.mp hmem with rfl | hmem'
|
2026-06-27 16:29:16 -05:00
|
|
|
|
· exact S.interp_sup (Or.inl hvs)
|
|
|
|
|
|
· exact S.interp_sup (Or.inr (ih hmem'))
|
|
|
|
|
|
|
|
|
|
|
|
variable [I : LatticeInterpretation L]
|
|
|
|
|
|
|
|
|
|
|
|
instance : StateInterp L prog where
|
|
|
|
|
|
St := fun _ => PUnit
|
|
|
|
|
|
init := PUnit.unit
|
|
|
|
|
|
interp vs ρ _ := ∀ (k : String) (l : L), (k, l) ∈ vs →
|
|
|
|
|
|
∀ (v : Value), Env.Mem (k, v) ρ → I.interp l v
|
|
|
|
|
|
interp_sup := by
|
|
|
|
|
|
intro vs₁ vs₂ ρ st h k l hmem v hv
|
|
|
|
|
|
obtain ⟨l₁, l₂, rfl, h₁, h₂⟩ := FiniteMap.mem_sup hmem
|
|
|
|
|
|
rcases h with h | h
|
|
|
|
|
|
· exact I.interp_sup v (Or.inl (h _ _ h₁ _ hv))
|
|
|
|
|
|
· exact I.interp_sup v (Or.inr (h _ _ h₂ _ hv))
|
|
|
|
|
|
interp_inf := by
|
|
|
|
|
|
intro vs₁ vs₂ ρ st h k l hmem v hv
|
|
|
|
|
|
obtain ⟨l₁, l₂, rfl, h₁, h₂⟩ := FiniteMap.mem_inf hmem
|
|
|
|
|
|
exact I.interp_inf v ⟨h.1 _ _ h₁ _ hv, h.2 _ _ h₂ _ hv⟩
|
2026-06-09 20:14:53 -07:00
|
|
|
|
|
2026-06-24 13:54:37 -05:00
|
|
|
|
end Forward
|
|
|
|
|
|
|
2026-06-09 20:14:53 -07:00
|
|
|
|
end Spa
|