Imports
Adjacency representation and cached-cut invariant
The input is a stored array of adjacency lists. Its representation contract says that each graph edge contributes its two endpoint incidences, in any row order. Thus the total adjacency length is derived as twice the edge count; it is not a supplied bound on the execution's decreases.
namespace CLRS.MST.ExecutablePrim.ArrayPrimopen Finsetvariable {n : Nat} {E : Type} [LinearOrder E]def incidences (G : Graph (Fin n) E) (u : Fin n) (e : E) : List (Fin n × E) :=
(if G.src e = u then [(G.dst e,e)] else []) ++
(if G.dst e = u then [(G.src e,e)] else [])structure Adjacency (G : FiniteGraph (Fin n) E) where
rows : Vector (List (Fin n × E)) n
represents : ∀ u : Fin n, (rows[u.val]).Perm
((G.edges.sort (· ≤ ·)).flatMap (incidences G.toGraph u))
@[simp] theorem Adjacency.mem_iff {G : FiniteGraph (Fin n) E} (adj : Adjacency G)
(u v : Fin n) (e : E) :
(v,e) ∈ adj.rows[u.val] ↔ e ∈ G.edges ∧
((G.src e = u ∧ G.dst e = v) ∨ (G.dst e = u ∧ G.src e = v)) := by
rw [(adj.represents u).mem_iff]
simp only [List.mem_flatMap]
constructor
· rintro ⟨f,hf,h⟩
simp only [incidences, List.mem_append] at h
rcases h with h | h
· split at h
· simp only [List.mem_singleton, Prod.mk.injEq] at h
rcases h with ⟨rfl,rfl⟩
exact ⟨(G.edges.mem_sort (· ≤ ·)).1 hf, Or.inl ⟨by assumption,rfl⟩⟩
· simp at h
· split at h
· simp only [List.mem_singleton, Prod.mk.injEq] at h
rcases h with ⟨rfl,rfl⟩
exact ⟨(G.edges.mem_sort (· ≤ ·)).1 hf, Or.inr ⟨by assumption,rfl⟩⟩
· simp at h
· rintro ⟨he,h⟩
refine ⟨e, (G.edges.mem_sort (· ≤ ·)).2 he, ?_⟩
rcases h with ⟨hs,hd⟩ | ⟨hd,hs⟩ <;> simp [incidences, hs, hd]
theorem Adjacency.total_length {G : FiniteGraph (Fin n) E} (adj : Adjacency G) :
∑ u : Fin n, (adj.rows[u.val]).length = 2 * G.edges.card := by
have general (es : List E) :
∑ u : Fin n, (es.flatMap (incidences G.toGraph u)).length = 2 * es.length := by
induction es with
| nil => simp
| cons e es ih =>
simp only [List.flatMap_cons, List.length_append, Finset.sum_add_distrib, ih,
List.length_cons]
have h : ∑ u : Fin n, (incidences G.toGraph u e).length = 2 := by
simp only [incidences, List.length_append]
simp_rw [apply_ite List.length]
simp [Finset.sum_add_distrib, eq_comm]
rw [h]
omega
calc
_ = ∑ u : Fin n,
((G.edges.sort (· ≤ ·)).flatMap (incidences G.toGraph u)).length :=
Finset.sum_congr rfl (fun u _ => (adj.represents u).length_eq)
_ = _ := by simpa using general (G.edges.sort (· ≤ ·))All active cells describe the best known parent into the reached set.
structure Invariant {G : FiniteGraph (Fin n) E} (adj : Adjacency G) (w : E → Nat)
(S : Finset (Fin n)) (q : Cells n E) : Prop where
active : ∀ v, (read q v).active = true ↔ v ∉ S
parent : ∀ v e, (read q v).active = true → (read q v).parent = some e →
∃ u ∈ S, (v,e) ∈ adj.rows[u.val] ∧ (read q v).key = (w e : Key)
covers : ∀ u ∈ S, ∀ v e, (v,e) ∈ adj.rows[u.val] →
(read q v).active = true → (read q v).key ≤ (w e : Key)
none_key : ∀ v, (read q v).parent = none → (read q v).key = ⊤theorem initialCells_invariant {G : FiniteGraph (Fin n) E} (adj : Adjacency G)
(w : E → Nat) : Invariant adj w ∅ (initialCells n).1 := by
refine ⟨?_, ?_, ?_, ?_⟩ <;> simpRemove one vertex and scan only its cached adjacency list.
def advance {G : FiniteGraph (Fin n) E} (adj : Adjacency G) (w : E → Nat)
(q : Cells n E) (u : Fin n) : Relaxed n E :=
relaxAll w (deactivate q u) adj.rows[u.val]@[simp] theorem advance_active {G : FiniteGraph (Fin n) E} (adj : Adjacency G)
(w : E → Nat) (q : Cells n E) (u v : Fin n) :
(read (advance adj w q u).cells v).active =
if u = v then false else (read q v).active := by simp [advance]
theorem advance_invariant {G : FiniteGraph (Fin n) E} (adj : Adjacency G)
(w : E → Nat) (S : Finset (Fin n)) (q : Cells n E) (u : Fin n)
(h : Invariant adj w S q) : Invariant adj w (insert u S) (advance adj w q u).cells := by
have ha (v : Fin n) : (read (advance adj w q u).cells v).active = true ↔
u ≠ v ∧ (read q v).active = true := by
by_cases huv : u = v <;> simp [huv]
refine ⟨?_, ?_, ?_, ?_⟩
· intro v
rw [ha, h.active]
simp [eq_comm]
· intro v e hv hp
obtain ⟨huv,hvold⟩ := (ha v).1 hv
rcases relaxAll_origin w (deactivate q u) adj.rows[u.val] v with hold | ⟨f,hf,hcell⟩
· have hpold : (read q v).parent = some e := by
change (read (relaxAll w (deactivate q u) adj.rows[u.val]).cells v).parent = _ at hp
rw [hold, deactivate_parent] at hp
exact hp
obtain ⟨x,hx,he,hkey⟩ := h.parent v e hvold hpold
refine ⟨x, mem_insert_of_mem hx, he, ?_⟩
change (read (relaxAll w (deactivate q u) adj.rows[u.val]).cells v).key = _
rw [hold, deactivate_key, hkey]
· have hfe : f = e := by
change (read (relaxAll w (deactivate q u) adj.rows[u.val]).cells v).parent = _ at hp
rw [hcell] at hp
exact Option.some.inj hp
subst f
exact ⟨u, mem_insert_self _ _, hf, congrArg Cell.key hcell⟩
· intro x hx v e he hv
obtain ⟨huv,hvold⟩ := (ha v).1 hv
rcases mem_insert.mp hx with hx | hx
· subst x
apply relaxAll_target_le w (deactivate q u) _ v e he
simpa [huv] using hvold
· exact (relaxAll_key_le w (deactivate q u) _ v).trans
(by simpa using h.covers x hx v e he hvold)
· intro v hp
rcases relaxAll_origin w (deactivate q u) adj.rows[u.val] v with hold | ⟨e,he,hcell⟩
· have hpold : (read q v).parent = none := by
change (read (relaxAll w (deactivate q u) adj.rows[u.val]).cells v).parent = _ at hp
rw [hold, deactivate_parent] at hp
exact hp
change (read (relaxAll w (deactivate q u) adj.rows[u.val]).cells v).key = _
rw [hold, deactivate_key, h.none_key v hpold]
· change (read (relaxAll w (deactivate q u) adj.rows[u.val]).cells v).parent = _ at hp
rw [hcell] at hp
contradictionSelecting a finite parent yields a real crossing edge and its outside vertex.
theorem Invariant.selected {G : FiniteGraph (Fin n) E} {adj : Adjacency G}
{w : E → Nat} {S : Finset (Fin n)} {q : Cells n E} (h : Invariant adj w S q)
(indices : List (Fin n)) (hfull : ∀ v, v ∈ indices)
{u : Fin n} {c : Cell E} {e : E}
(hs : (scan q indices).choice = some (u,c)) (hp : c.parent = some e) :
e ∈ G.edges ∧ G.toGraph.Crosses S e ∧ outsideVertex G.toGraph S e = u ∧
∀ f ∈ G.edges, G.toGraph.Crosses S f → w e ≤ w f := by
obtain ⟨_,rfl,hu,hmin⟩ := scan_some q _ u c hs
obtain ⟨x,hx,he,hkey⟩ := h.parent u e hu hp
have hout := (h.active u).1 hu
obtain ⟨heG,heEnds⟩ := adj.mem_iff x u e |>.1 he
have hc : G.toGraph.Crosses S e := by
rcases heEnds with ⟨hsrc,hdst⟩ | ⟨hdst,hsrc⟩
· exact Or.inl ⟨hsrc ▸ hx, hdst ▸ hout⟩
· exact Or.inr ⟨hdst ▸ hx, hsrc ▸ hout⟩
refine ⟨heG, hc, ?_, ?_⟩
· rcases heEnds with ⟨hsrc,hdst⟩ | ⟨hdst,hsrc⟩ <;>
simp [outsideVertex, hsrc, hdst, hx, hout]
· intro f hf hfc
let v := outsideVertex G.toGraph S f
have hv : v ∉ S := outsideVertex_not_mem hfc
have hvc := (h.active v).2 hv
have hcover : (read q v).key ≤ (w f : Key) := by
rcases hfc with hfc | hfc
· have hm : (v,f) ∈ adj.rows[(G.src f).val] := by
apply (adj.mem_iff _ _ _).2
exact ⟨hf, Or.inl ⟨rfl, by simp [v, outsideVertex, hfc.1]⟩⟩
exact h.covers _ hfc.1 v f hm hvc
· have hsrc : G.src f ∉ S := hfc.2
have hm : (v,f) ∈ adj.rows[(G.dst f).val] := by
apply (adj.mem_iff _ _ _).2
exact ⟨hf, Or.inr ⟨rfl, by simp [v, outsideVertex, hsrc]⟩⟩
exact h.covers _ hfc.1 v f hm hvc
have hm := hmin v (hfull v) hvc
rw [hkey] at hm
exact_mod_cast hm.trans hcoverend CLRS.MST.ExecutablePrim.ArrayPrim