2026-06-09 19:30:42 -07:00
|
|
|
|
import Spa.Language.Base
|
|
|
|
|
|
import Mathlib.Data.Fin.Tuple.Basic
|
|
|
|
|
|
import Mathlib.Data.List.ProdSigma
|
|
|
|
|
|
import Mathlib.Data.List.FinRange
|
|
|
|
|
|
|
2026-06-23 14:00:06 -05:00
|
|
|
|
def List.finCastAdd {n : ℕ} (l : List (Fin n)) (m : ℕ) : List (Fin (n + m)) :=
|
|
|
|
|
|
l.map (Fin.castAdd m)
|
|
|
|
|
|
|
|
|
|
|
|
def List.finNatAdd {m : ℕ} (l : List (Fin m)) (n : ℕ) : List (Fin (n + m)) :=
|
|
|
|
|
|
l.map (Fin.natAdd n)
|
|
|
|
|
|
|
|
|
|
|
|
def List.finCastAddProd {n : ℕ} (l : List (Fin n × Fin n)) (m : ℕ) :
|
|
|
|
|
|
List (Fin (n + m) × Fin (n + m)) :=
|
|
|
|
|
|
l.map (fun e => (e.1.castAdd m, e.2.castAdd m))
|
|
|
|
|
|
|
|
|
|
|
|
def List.finNatAddProd {m : ℕ} (l : List (Fin m × Fin m)) (n : ℕ) :
|
|
|
|
|
|
List (Fin (n + m) × Fin (n + m)) :=
|
|
|
|
|
|
l.map (fun e => (e.1.natAdd n, e.2.natAdd n))
|
|
|
|
|
|
|
2026-06-09 19:30:42 -07:00
|
|
|
|
namespace Spa
|
|
|
|
|
|
|
2026-06-24 16:02:49 -05:00
|
|
|
|
structure GGraph (α : Type) where
|
2026-06-09 19:30:42 -07:00
|
|
|
|
size : ℕ
|
2026-06-24 16:02:49 -05:00
|
|
|
|
nodes : Fin size → α
|
2026-06-09 19:30:42 -07:00
|
|
|
|
edges : List (Fin size × Fin size)
|
|
|
|
|
|
inputs : List (Fin size)
|
|
|
|
|
|
outputs : List (Fin size)
|
|
|
|
|
|
|
2026-06-24 16:02:49 -05:00
|
|
|
|
namespace GGraph
|
|
|
|
|
|
|
|
|
|
|
|
variable {α β : Type}
|
|
|
|
|
|
|
|
|
|
|
|
abbrev Index (g : GGraph α) : Type := Fin g.size
|
2026-06-09 19:30:42 -07:00
|
|
|
|
|
2026-06-24 16:02:49 -05:00
|
|
|
|
abbrev Edge (g : GGraph α) : Type := g.Index × g.Index
|
2026-06-09 19:30:42 -07:00
|
|
|
|
|
2026-06-24 16:02:49 -05:00
|
|
|
|
def map (f : α → β) (g : GGraph α) : GGraph β where
|
|
|
|
|
|
size := g.size
|
|
|
|
|
|
nodes := fun i => f (g.nodes i)
|
|
|
|
|
|
edges := g.edges
|
|
|
|
|
|
inputs := g.inputs
|
|
|
|
|
|
outputs := g.outputs
|
2026-06-09 19:30:42 -07:00
|
|
|
|
|
2026-06-25 13:59:08 -05:00
|
|
|
|
@[simp] lemma map_size (f : α → β) (g : GGraph α) : (g.map f).size = g.size := rfl
|
|
|
|
|
|
@[simp] lemma map_edges (f : α → β) (g : GGraph α) : (g.map f).edges = g.edges := rfl
|
|
|
|
|
|
@[simp] lemma map_inputs (f : α → β) (g : GGraph α) : (g.map f).inputs = g.inputs := rfl
|
|
|
|
|
|
@[simp] lemma map_outputs (f : α → β) (g : GGraph α) : (g.map f).outputs = g.outputs := rfl
|
2026-06-24 16:02:49 -05:00
|
|
|
|
|
|
|
|
|
|
def comp (g₁ g₂ : GGraph α) : GGraph α where
|
2026-06-09 19:30:42 -07:00
|
|
|
|
size := g₁.size + g₂.size
|
|
|
|
|
|
nodes := Fin.append g₁.nodes g₂.nodes
|
2026-06-23 14:00:06 -05:00
|
|
|
|
edges := g₁.edges.finCastAddProd g₂.size ++ g₂.edges.finNatAddProd g₁.size
|
|
|
|
|
|
inputs := g₁.inputs.finCastAdd g₂.size ++ g₂.inputs.finNatAdd g₁.size
|
|
|
|
|
|
outputs := g₁.outputs.finCastAdd g₂.size ++ g₂.outputs.finNatAdd g₁.size
|
2026-06-09 19:30:42 -07:00
|
|
|
|
|
2026-06-24 16:02:49 -05:00
|
|
|
|
@[inherit_doc] scoped infixr:70 " ∙ " => GGraph.comp
|
2026-06-09 19:30:42 -07:00
|
|
|
|
|
2026-06-24 16:02:49 -05:00
|
|
|
|
def link (g₁ g₂ : GGraph α) : GGraph α where
|
2026-06-09 19:30:42 -07:00
|
|
|
|
size := g₁.size + g₂.size
|
|
|
|
|
|
nodes := Fin.append g₁.nodes g₂.nodes
|
2026-06-23 14:00:06 -05:00
|
|
|
|
edges := g₁.edges.finCastAddProd g₂.size ++ g₂.edges.finNatAddProd g₁.size ++
|
|
|
|
|
|
(g₁.outputs.finCastAdd g₂.size).product (g₂.inputs.finNatAdd g₁.size)
|
|
|
|
|
|
inputs := g₁.inputs.finCastAdd g₂.size
|
|
|
|
|
|
outputs := g₂.outputs.finNatAdd g₁.size
|
2026-06-09 19:30:42 -07:00
|
|
|
|
|
2026-06-24 16:02:49 -05:00
|
|
|
|
@[inherit_doc] scoped infixr:70 " ⤳ " => GGraph.link
|
2026-06-09 19:30:42 -07:00
|
|
|
|
|
2026-06-24 16:02:49 -05:00
|
|
|
|
def loopIn (g : GGraph α) : Fin (2 + g.size) := (0 : Fin 2).castAdd g.size
|
2026-06-09 19:30:42 -07:00
|
|
|
|
|
2026-06-24 16:02:49 -05:00
|
|
|
|
def loopOut (g : GGraph α) : Fin (2 + g.size) := (1 : Fin 2).castAdd g.size
|
2026-06-09 19:30:42 -07:00
|
|
|
|
|
2026-06-24 16:02:49 -05:00
|
|
|
|
def loop (g : GGraph (List β)) : GGraph (List β) where
|
2026-06-09 19:30:42 -07:00
|
|
|
|
size := 2 + g.size
|
|
|
|
|
|
nodes := Fin.append (fun _ : Fin 2 => []) g.nodes
|
2026-06-23 14:00:06 -05:00
|
|
|
|
edges := g.edges.finNatAddProd 2 ++
|
|
|
|
|
|
(g.inputs.finNatAdd 2).map (g.loopIn, ·) ++
|
|
|
|
|
|
(g.outputs.finNatAdd 2).map (·, g.loopOut) ++
|
2026-06-09 19:30:42 -07:00
|
|
|
|
[(g.loopOut, g.loopIn), (g.loopIn, g.loopOut)]
|
|
|
|
|
|
inputs := [g.loopIn]
|
|
|
|
|
|
outputs := [g.loopOut]
|
|
|
|
|
|
|
2026-06-25 13:59:08 -05:00
|
|
|
|
@[simp] lemma loop_inputs (g : GGraph (List β)) : (loop g).inputs = [g.loopIn] := rfl
|
2026-06-09 19:30:42 -07:00
|
|
|
|
|
2026-06-25 13:59:08 -05:00
|
|
|
|
@[simp] lemma loop_outputs (g : GGraph (List β)) : (loop g).outputs = [g.loopOut] := rfl
|
2026-06-09 19:30:42 -07:00
|
|
|
|
|
2026-06-24 16:02:49 -05:00
|
|
|
|
def skipto (g₁ g₂ : GGraph α) : GGraph α where
|
2026-06-09 19:30:42 -07:00
|
|
|
|
size := g₁.size + g₂.size
|
|
|
|
|
|
nodes := Fin.append g₁.nodes g₂.nodes
|
2026-06-23 14:00:06 -05:00
|
|
|
|
edges := g₁.edges.finCastAddProd g₂.size ++ g₂.edges.finNatAddProd g₁.size ++
|
|
|
|
|
|
(g₁.inputs.finCastAdd g₂.size).product (g₂.inputs.finNatAdd g₁.size)
|
|
|
|
|
|
inputs := g₁.inputs.finCastAdd g₂.size
|
|
|
|
|
|
outputs := g₂.inputs.finNatAdd g₁.size
|
2026-06-09 19:30:42 -07:00
|
|
|
|
|
2026-06-24 16:02:49 -05:00
|
|
|
|
def singleton (a : α) : GGraph α where
|
2026-06-09 19:30:42 -07:00
|
|
|
|
size := 1
|
2026-06-24 16:02:49 -05:00
|
|
|
|
nodes := fun _ => a
|
2026-06-09 19:30:42 -07:00
|
|
|
|
edges := []
|
|
|
|
|
|
inputs := [0]
|
|
|
|
|
|
outputs := [0]
|
|
|
|
|
|
|
2026-06-24 16:02:49 -05:00
|
|
|
|
def wrap (g : GGraph (List β)) : GGraph (List β) :=
|
2026-06-09 19:30:42 -07:00
|
|
|
|
singleton [] ⤳ g ⤳ singleton []
|
|
|
|
|
|
|
2026-06-25 13:59:08 -05:00
|
|
|
|
@[simp] lemma map_singleton (f : α → β) (a : α) :
|
2026-06-25 09:25:35 -05:00
|
|
|
|
(singleton a).map f = singleton (f a) := rfl
|
|
|
|
|
|
|
2026-06-25 13:59:08 -05:00
|
|
|
|
@[simp] lemma map_comp (f : α → β) (g₁ g₂ : GGraph α) :
|
2026-06-25 09:25:35 -05:00
|
|
|
|
(g₁ ∙ g₂).map f = g₁.map f ∙ g₂.map f := by
|
|
|
|
|
|
rcases g₁ with ⟨n₁, nd₁, e₁, i₁, o₁⟩; rcases g₂ with ⟨n₂, nd₂, e₂, i₂, o₂⟩
|
|
|
|
|
|
simp only [GGraph.map, GGraph.comp]
|
|
|
|
|
|
congr 1
|
|
|
|
|
|
funext i
|
|
|
|
|
|
refine Fin.addCases ?_ ?_ i <;> intro j <;> simp [Fin.append_left, Fin.append_right]
|
|
|
|
|
|
|
2026-06-25 13:59:08 -05:00
|
|
|
|
@[simp] lemma map_link (f : α → β) (g₁ g₂ : GGraph α) :
|
2026-06-25 09:25:35 -05:00
|
|
|
|
(g₁ ⤳ g₂).map f = g₁.map f ⤳ g₂.map f := by
|
|
|
|
|
|
rcases g₁ with ⟨n₁, nd₁, e₁, i₁, o₁⟩; rcases g₂ with ⟨n₂, nd₂, e₂, i₂, o₂⟩
|
|
|
|
|
|
simp only [GGraph.map, GGraph.link]
|
|
|
|
|
|
congr 1
|
|
|
|
|
|
funext i
|
|
|
|
|
|
refine Fin.addCases ?_ ?_ i <;> intro j <;> simp [Fin.append_left, Fin.append_right]
|
|
|
|
|
|
|
2026-06-25 13:59:08 -05:00
|
|
|
|
@[simp] lemma map_loop (h : β → γ) (g : GGraph (List β)) :
|
2026-06-25 09:25:35 -05:00
|
|
|
|
(loop g).map (List.map h) = loop (g.map (List.map h)) := by
|
|
|
|
|
|
rcases g with ⟨n, nd, e, i, o⟩
|
|
|
|
|
|
simp only [GGraph.map, GGraph.loop]
|
|
|
|
|
|
congr 1
|
|
|
|
|
|
funext i
|
|
|
|
|
|
refine Fin.addCases ?_ ?_ i <;> intro j <;> simp [Fin.append_left, Fin.append_right]
|
|
|
|
|
|
|
2026-06-25 13:59:08 -05:00
|
|
|
|
@[simp] lemma map_wrap (h : β → γ) (g : GGraph (List β)) :
|
2026-06-25 09:25:35 -05:00
|
|
|
|
(wrap g).map (List.map h) = wrap (g.map (List.map h)) := by
|
|
|
|
|
|
simp [GGraph.wrap, GGraph.map_link, GGraph.map_singleton]
|
|
|
|
|
|
|
2026-06-24 16:02:49 -05:00
|
|
|
|
variable (g : GGraph α)
|
2026-06-09 19:30:42 -07:00
|
|
|
|
|
|
|
|
|
|
def indices : List g.Index := List.finRange g.size
|
|
|
|
|
|
|
2026-06-25 13:59:08 -05:00
|
|
|
|
lemma mem_indices (idx : g.Index) : idx ∈ g.indices :=
|
2026-06-09 19:30:42 -07:00
|
|
|
|
List.mem_finRange idx
|
|
|
|
|
|
|
2026-06-25 13:59:08 -05:00
|
|
|
|
lemma nodup_indices : g.indices.Nodup :=
|
2026-06-09 19:30:42 -07:00
|
|
|
|
List.nodup_finRange g.size
|
|
|
|
|
|
|
|
|
|
|
|
def predecessors (idx : g.Index) : List g.Index :=
|
|
|
|
|
|
g.indices.filter (fun idx' => (idx', idx) ∈ g.edges)
|
|
|
|
|
|
|
2026-06-25 13:59:08 -05:00
|
|
|
|
lemma mem_predecessors_of_edge {idx₁ idx₂ : g.Index}
|
2026-06-09 19:30:42 -07:00
|
|
|
|
(h : (idx₁, idx₂) ∈ g.edges) : idx₁ ∈ g.predecessors idx₂ :=
|
|
|
|
|
|
List.mem_filter.mpr ⟨g.mem_indices idx₁, by simpa using h⟩
|
|
|
|
|
|
|
2026-06-25 13:59:08 -05:00
|
|
|
|
lemma edge_of_mem_predecessors {idx₁ idx₂ : g.Index}
|
2026-06-09 19:30:42 -07:00
|
|
|
|
(h : idx₁ ∈ g.predecessors idx₂) : (idx₁, idx₂) ∈ g.edges := by
|
|
|
|
|
|
simpa using (List.mem_filter.mp h).2
|
|
|
|
|
|
|
2026-06-24 16:02:49 -05:00
|
|
|
|
end GGraph
|
|
|
|
|
|
|
|
|
|
|
|
abbrev Graph : Type := GGraph (List BasicStmt)
|
|
|
|
|
|
|
|
|
|
|
|
namespace Graph
|
|
|
|
|
|
|
|
|
|
|
|
export GGraph (comp link loop skipto singleton wrap loop_inputs loop_outputs)
|
|
|
|
|
|
|
|
|
|
|
|
@[inherit_doc] scoped infixr:70 " ∙ " => GGraph.comp
|
|
|
|
|
|
@[inherit_doc] scoped infixr:70 " ⤳ " => GGraph.link
|
|
|
|
|
|
|
2026-06-09 19:30:42 -07:00
|
|
|
|
end Graph
|
|
|
|
|
|
|
2026-06-24 13:54:37 -05:00
|
|
|
|
open Graph in
|
2026-06-25 09:45:30 -05:00
|
|
|
|
def Stmt.cfg : Stmt → Graph
|
2026-06-24 16:02:49 -05:00
|
|
|
|
| .basic bs => singleton [bs]
|
2026-06-25 09:45:30 -05:00
|
|
|
|
| .andThen s₁ s₂ => s₁.cfg ⤳ s₂.cfg
|
|
|
|
|
|
| .ifElse _ s₁ s₂ => s₁.cfg ∙ s₂.cfg
|
|
|
|
|
|
| .whileLoop _ s => loop s.cfg
|
2026-06-24 13:54:37 -05:00
|
|
|
|
|
2026-06-09 19:30:42 -07:00
|
|
|
|
end Spa
|