2026-06-23 15:12:37 -05:00
|
|
|
|
import Spa.Analysis.Forward
|
2026-06-28 09:46:54 -05:00
|
|
|
|
import Spa.Lattice.Finset
|
2026-06-23 15:12:37 -05:00
|
|
|
|
import Spa.Showable
|
|
|
|
|
|
|
|
|
|
|
|
namespace Spa
|
|
|
|
|
|
|
|
|
|
|
|
open Forward
|
|
|
|
|
|
|
2026-06-28 09:46:54 -05:00
|
|
|
|
instance {n : ℕ} : Showable (Finset (Fin n)) :=
|
|
|
|
|
|
⟨fun s =>
|
2026-06-27 16:29:16 -05:00
|
|
|
|
"{" ++ (List.finRange n).foldr
|
2026-06-28 09:46:54 -05:00
|
|
|
|
(fun i rest => if i ∈ s then show' i ++ ", " ++ rest else rest) ""
|
2026-06-27 16:29:16 -05:00
|
|
|
|
++ "}"⟩
|
|
|
|
|
|
|
2026-08-09 17:35:30 -05:00
|
|
|
|
abbrev DefSet (prog : Program) : Type := Finset prog.State
|
2026-06-23 15:12:37 -05:00
|
|
|
|
|
|
|
|
|
|
namespace ReachingAnalysis
|
|
|
|
|
|
|
|
|
|
|
|
variable (prog : Program)
|
|
|
|
|
|
|
2026-06-30 23:21:00 -05:00
|
|
|
|
def eval (s : prog.State) (vs : VariableValues (DefSet prog) prog) : VariableValues (DefSet prog) prog :=
|
|
|
|
|
|
match prog.code s with
|
|
|
|
|
|
| none => vs
|
|
|
|
|
|
| some bs =>
|
|
|
|
|
|
match bs with
|
2026-08-09 17:35:30 -05:00
|
|
|
|
| .assign k _ => FiniteMap.generalizedUpdate id (fun _ _ => {s}) [k] vs
|
2026-06-30 23:21:00 -05:00
|
|
|
|
| .noop => vs
|
|
|
|
|
|
|
|
|
|
|
|
lemma eval_mono (s : prog.State) :
|
|
|
|
|
|
Monotone (eval prog s) := by
|
|
|
|
|
|
intros vs₁ vs₂ hle
|
|
|
|
|
|
unfold eval; split <;> try simpa
|
|
|
|
|
|
split <;> try simpa
|
|
|
|
|
|
apply FiniteMap.generalizedUpdate_monotone monotone_id (fun _ => monotone_const)
|
|
|
|
|
|
assumption
|
2026-06-23 15:12:37 -05:00
|
|
|
|
|
|
|
|
|
|
instance stmtEvaluator : StmtEvaluator (DefSet prog) prog :=
|
|
|
|
|
|
⟨eval prog, eval_mono prog⟩
|
|
|
|
|
|
|
|
|
|
|
|
def output : String :=
|
|
|
|
|
|
show' (result (DefSet prog) prog)
|
|
|
|
|
|
|
2026-10-06 19:30:35 -05:00
|
|
|
|
/-- Executed nodes, most recent first. Instructions are read from `prog.code`.
|
|
|
|
|
|
This is `Path.steps` (chronological) reversed, so facts about concatenating
|
|
|
|
|
|
traces reduce to mathlib's `List.append`/`List.reverse` lemmas. -/
|
|
|
|
|
|
abbrev Run (prog : Program) : Type := List prog.State
|
2026-06-27 16:29:16 -05:00
|
|
|
|
|
2026-10-06 19:30:35 -05:00
|
|
|
|
/-- The first node in a newest-first history whose instruction assigns `x`. -/
|
2026-06-27 19:30:01 -05:00
|
|
|
|
@[aesop unsafe cases]
|
2026-08-09 17:35:30 -05:00
|
|
|
|
inductive LastAssign (prog : Program) (x : String) : Run prog → prog.State → Prop
|
2026-10-06 19:30:35 -05:00
|
|
|
|
| here (s : prog.State) (e : Expr) (rest : Run prog)
|
|
|
|
|
|
(hc : prog.code s = some (.assign x e)) :
|
|
|
|
|
|
LastAssign prog x (s :: rest) s
|
|
|
|
|
|
| there (s : prog.State) (rest : Run prog) {n : prog.State} :
|
|
|
|
|
|
(∀ e, prog.code s ≠ some (.assign x e)) → LastAssign prog x rest n →
|
|
|
|
|
|
LastAssign prog x (s :: rest) n
|
2026-07-02 09:01:09 -05:00
|
|
|
|
|
2026-10-04 09:58:39 -05:00
|
|
|
|
def runOfPath {a b : Configuration prog.cfg} (p : Path prog.cfg a b) : Run prog :=
|
|
|
|
|
|
p.steps.reverse
|
2026-07-02 09:01:09 -05:00
|
|
|
|
|
2026-10-04 09:58:39 -05:00
|
|
|
|
abbrev runOfTraceₗ {s₁ s₂ : prog.State} {ρ₁ ρ₂ : Env}
|
|
|
|
|
|
(tr : Traceₗ prog.cfg s₁ s₂ ρ₁ ρ₂) : Run prog := runOfPath prog tr
|
|
|
|
|
|
|
|
|
|
|
|
abbrev runOfTrace {s₁ s₂ : prog.State} {ρ₁ ρ₂ : Env}
|
|
|
|
|
|
(tr : Trace prog.cfg s₁ s₂ ρ₁ ρ₂) : Run prog := runOfPath prog tr
|
2026-06-27 16:29:16 -05:00
|
|
|
|
|
2026-06-29 10:00:01 -05:00
|
|
|
|
instance stateInterp : StateInterpretation (DefSet prog) prog where
|
2026-07-02 09:01:09 -05:00
|
|
|
|
Proj := Run prog
|
2026-10-04 09:58:39 -05:00
|
|
|
|
Pre := fun tr => runOfPath prog tr
|
|
|
|
|
|
Post := fun tr => runOfPath prog tr
|
2026-07-02 09:01:09 -05:00
|
|
|
|
|
|
|
|
|
|
interp vs run := ∀ (x : String) (assigners : DefSet prog), (x, assigners) ∈ vs →
|
2026-08-09 17:35:30 -05:00
|
|
|
|
∀ (n : prog.State), LastAssign prog x run n → n ∈ assigners
|
2026-06-27 16:29:16 -05:00
|
|
|
|
interp_sup := by
|
2026-07-02 09:01:09 -05:00
|
|
|
|
intro vs₁ vs₂ run h x assigners hmem n hla
|
2026-06-27 16:29:16 -05:00
|
|
|
|
obtain ⟨a₁, a₂, rfl, h₁, h₂⟩ := FiniteMap.mem_sup hmem
|
2026-06-28 09:46:54 -05:00
|
|
|
|
aesop (add simp Finset.mem_union)
|
2026-06-27 16:29:16 -05:00
|
|
|
|
interp_inf := by
|
2026-07-02 09:01:09 -05:00
|
|
|
|
intro vs₁ vs₂ run h x assigners hmem n hla
|
2026-06-27 16:29:16 -05:00
|
|
|
|
obtain ⟨a₁, a₂, rfl, h₁, h₂⟩ := FiniteMap.mem_inf hmem
|
2026-06-28 09:46:54 -05:00
|
|
|
|
aesop (add simp Finset.mem_inter)
|
2026-06-27 16:29:16 -05:00
|
|
|
|
|
2026-07-02 09:01:09 -05:00
|
|
|
|
post_pre := by
|
|
|
|
|
|
intro vs s₁ s₂ s₃ ρ₁ ρ₂ tr hedge hvs
|
2026-10-04 09:58:39 -05:00
|
|
|
|
simpa only [runOfPath, Trace.addEdge, Path.steps_append, Path.single,
|
|
|
|
|
|
Path.steps, Step.steps, List.append_nil] using hvs
|
2026-07-02 09:01:09 -05:00
|
|
|
|
|
2026-10-06 20:09:08 -05:00
|
|
|
|
private lemma valid_step (s : prog.State)
|
2026-07-02 09:01:09 -05:00
|
|
|
|
{vs : VariableValues (DefSet prog) prog} {run : Run prog}
|
|
|
|
|
|
(hvs : ⟦vs⟧ run) :
|
2026-10-06 20:09:08 -05:00
|
|
|
|
⟦eval prog s vs⟧ ((match prog.code s with | none => [] | some _ => [s]) ++ run) := by
|
|
|
|
|
|
cases hcode : prog.code s with
|
|
|
|
|
|
| none => simpa [eval, hcode] using hvs
|
|
|
|
|
|
| some bs =>
|
|
|
|
|
|
cases bs with
|
|
|
|
|
|
| noop =>
|
|
|
|
|
|
simp [eval, hcode]
|
|
|
|
|
|
intro x assigners hmem n hla; aesop (add simp hcode)
|
|
|
|
|
|
| assign x e =>
|
|
|
|
|
|
simp [eval, hcode]; intro k assigners hmem n hla
|
|
|
|
|
|
by_cases hx : k = x
|
|
|
|
|
|
· subst hx
|
|
|
|
|
|
have hd := FiniteMap.generalizedUpdate_mem_eq (List.mem_singleton.mpr rfl) hmem
|
|
|
|
|
|
rcases hla <;> simp [hd] <;> aesop (add simp hcode)
|
|
|
|
|
|
· have hmem' := FiniteMap.generalizedUpdate_not_mem_backward
|
|
|
|
|
|
(fun hc => hx (List.mem_singleton.mp hc)) hmem
|
|
|
|
|
|
aesop (add simp hcode)
|
2026-06-30 23:21:00 -05:00
|
|
|
|
|
2026-06-27 16:29:16 -05:00
|
|
|
|
instance validStateEvaluator : ValidStateEvaluator (DefSet prog) prog where
|
|
|
|
|
|
valid := by
|
2026-07-02 09:01:09 -05:00
|
|
|
|
intro s₁ s₂ ρ₁ ρ₂ ρ₃ vs tr hbs hvs
|
2026-10-04 09:58:39 -05:00
|
|
|
|
change ⟦vs⟧ (runOfPath prog tr) at hvs
|
|
|
|
|
|
change ⟦eval prog s₂ vs⟧ (runOfPath prog (Path.append tr (.single (.execute hbs))))
|
2026-10-06 20:09:08 -05:00
|
|
|
|
cases hcode : prog.code s₂ <;>
|
|
|
|
|
|
simpa [runOfPath, Path.single, Path.steps, Step.steps, hcode] using valid_step prog s₂ hvs
|
2026-06-27 16:29:16 -05:00
|
|
|
|
botV_init := by intro x assigners _ n hla; cases hla
|
|
|
|
|
|
|
|
|
|
|
|
theorem analyze_correct {ρ : Env} (hrun : EvalStmt [] prog.rootStmt ρ) :
|
2026-07-02 09:01:09 -05:00
|
|
|
|
⟦ variablesAt prog.finalState (result (DefSet prog) prog) ⟧
|
|
|
|
|
|
(runOfTrace prog (prog.trace hrun)) :=
|
|
|
|
|
|
Forward.analyze_correct' (DefSet prog) prog hrun
|
2026-06-27 16:29:16 -05:00
|
|
|
|
|
2026-08-09 21:23:21 -05:00
|
|
|
|
theorem analyze_correct_at {s : prog.State} {ρin ρout : Env}
|
|
|
|
|
|
(hr : Reaches s ρin ρout) :
|
2026-07-02 09:01:09 -05:00
|
|
|
|
⟦ joinForKey s (result (DefSet prog) prog) ⟧ (runOfTraceₗ prog hr.pre)
|
|
|
|
|
|
∧ ⟦ variablesAt s (result (DefSet prog) prog) ⟧ (runOfTrace prog hr.post) :=
|
2026-08-09 21:23:21 -05:00
|
|
|
|
Forward.analyze_correct_at (DefSet prog) prog hr
|
2026-06-28 14:24:46 -05:00
|
|
|
|
|
2026-06-23 15:12:37 -05:00
|
|
|
|
end ReachingAnalysis
|
|
|
|
|
|
|
|
|
|
|
|
end Spa
|