/- Port of `Language.agda` (the `Program` record and re-exports). Correspondence: Program record ↦ structure Program (defs in the `Program` namespace) graph ↦ Program.graph State ↦ Program.State initialState ↦ Program.initialState finalState ↦ Program.finalState trace ↦ Program.trace vars, vars-Unique ↦ Program.vars, Program.vars_nodup (Finset.toList + Finset.nodup_toList replace `to-Listˢ` and the intrinsic MapSet uniqueness) states, states-complete, states-Unique ↦ Program.states, .states_complete, .states_nodup code ↦ Program.code _≟_, _≟ᵉ_ ↦ (instances, automatic for Fin/products) incoming ↦ Program.incoming initialState-pred-∅ ↦ Program.incoming_initialState_eq_nil edge⇒incoming ↦ Program.mem_incoming_of_edge -/ import Spa.Language.Base import Spa.Language.Semantics import Spa.Language.Graphs import Spa.Language.Traces import Spa.Language.Properties import Mathlib.Data.Finset.Sort import Mathlib.Data.String.Basic namespace Spa structure Program where rootStmt : Stmt namespace Program variable (p : Program) def graph : Graph := Graph.wrap (buildCfg p.rootStmt) abbrev State : Type := p.graph.Index def initialState : p.State := (buildCfg p.rootStmt).wrapInput def finalState : p.State := (buildCfg p.rootStmt).wrapOutput /-- Agda: `Program.trace`. -/ theorem trace {ρ : Env} (h : EvalStmt [] p.rootStmt ρ) : Trace p.graph p.initialState p.finalState [] ρ := by obtain ⟨i₁, h₁, i₂, h₂, tr⟩ := EndToEndTrace.wrap (buildCfg_sufficient h) rw [Graph.wrap_inputs, List.mem_singleton] at h₁ rw [Graph.wrap_outputs, List.mem_singleton] at h₂ subst h₁; subst h₂ exact tr /-- Agda: `vars` (via `vars-Set = Stmt-vars rootStmt`). `Finset.toList` is noncomputable, so the variables are listed in sorted order instead — this is the computable stand-in for MapSet's `to-List`. -/ def vars : List String := p.rootStmt.vars.sort (· ≤ ·) /-- Agda: `vars-Unique`. -/ theorem vars_nodup : p.vars.Nodup := Finset.sort_nodup _ _ def states : List p.State := p.graph.indices /-- Agda: `states-complete`. -/ theorem states_complete (s : p.State) : s ∈ p.states := p.graph.mem_indices s /-- Agda: `states-Unique`. -/ theorem states_nodup : p.states.Nodup := p.graph.nodup_indices /-- Agda: `code`. -/ def code (st : p.State) : List BasicStmt := p.graph.nodes st /-- Agda: `incoming`. -/ def incoming (s : p.State) : List p.State := p.graph.predecessors s /-- Agda: `initialState-pred-∅`. -/ theorem incoming_initialState_eq_nil : p.incoming p.initialState = [] := Graph.wrap_predecessors_eq_nil (buildCfg p.rootStmt) p.initialState (by rw [Graph.wrap_inputs]; exact List.mem_singleton_self _) /-- Agda: `edge⇒incoming`. -/ theorem mem_incoming_of_edge {s₁ s₂ : p.State} (h : (s₁, s₂) ∈ p.graph.edges) : s₁ ∈ p.incoming s₂ := p.graph.mem_predecessors_of_edge h end Program end Spa