Theory UGraph_Impl
section "Kruskal on UGraphs"
theory UGraph_Impl
imports
Kruskal_Impl UGraph
begin
definition "α = (λ(u,w,v). Upair u v)"
subsection "Interpreting ‹Kruskl_Impl› with a UGraph"
abbreviation (in uGraph)
"getEdges_SPEC csuper_E
≡ (SPEC (λL. distinct (map α L) ∧ α ` set L = E
∧ (∀(a, wv, b)∈set L. w (α (a, wv, b)) = wv) ∧ set L ⊆ csuper_E))"
locale uGraph_impl = uGraph E w for E :: "nat uprod set" and w :: "nat uprod ⇒ int" +
fixes getEdges_impl :: "(nat × int × nat) list Heap" and csuper_E :: "(nat × int × nat) set"
assumes getEdges_impl:
"(uncurry0 getEdges_impl, uncurry0 (getEdges_SPEC csuper_E))
∈ unit_assn⇧k →⇩a list_assn (nat_assn ×⇩a int_assn ×⇩a nat_assn)"
begin
abbreviation "V ≡ ⋃ (set_uprod ` E)"
lemma max_node_is_Max_V: " E = α ` set la ⟹ max_node la = Max (insert 0 V)"
proof -
assume E: "E = α ` set la"
have *: "fst ` set la ∪ (snd ∘ snd) ` set la = (⋃x∈set la. case x of (x1, x1a, x2a) ⇒ {x1, x2a})"
by auto force
show ?thesis
unfolding E using *
by (auto simp add: α_def max_node_def prod.case_distrib)
qed
sublocale s: Kruskal_Impl E "⋃(set_uprod ` E)" set_uprod "λu v e. Upair u v = e"
"subforest" "uconnectedV" w α "PR_CONST (λ(u,w,v). RETURN (u,v))"
"PR_CONST (getEdges_SPEC csuper_E)"
getEdges_impl "csuper_E" " (λ(u,w,v). return (u,v))"
unfolding subforest_def
proof (unfold_locales, goal_cases)
show "finite E" by simp
next
fix E'
assume "forest E' ∧ E' ⊆ E"
then show "E' ⊆ E" by auto
next
show "forest {} ∧ {} ⊆ E" apply (auto simp: decycle_def forest_def)
using epath.elims(2) by fastforce
next
fix X Y
assume "forest X ∧ X ⊆ E" "Y ⊆ X"
then show "forest Y ∧ Y ⊆ E" using forest_mono by auto
next
case (5 u v)
then show ?case unfolding uconnected_def apply auto
using epath.elims(2) by force
next
case (6 E1 E2 u v)
then have "(u, v) ∈ (uconnected E1)" and uv: "u ∈ V" "v ∈ V"
by auto
then obtain p where 1: "epath E1 u p v" unfolding uconnected_def by auto
from 6 uv have 2: "¬(∃p. epath E2 u p v)" unfolding uconnected_def by auto
from 1 2 have "∃a b. (a, b) ∉ uconnected E2
∧ Upair a b ∉ E2 ∧ Upair a b ∈ E1" by(rule findaugmenting_edge)
then show ?case by auto
next
case (7 F e u v)
note f = ‹forest F ∧ F ⊆ E›
note notin = ‹e ∈ E - F› ‹Upair u v = e›
from notin ecard2 have unv: "u≠v" by fastforce
show "(forest (insert e F) ∧ insert e F ⊆ E) = ((u, v) ∉ uconnectedV F)"
proof
assume a: "forest (insert e F) ∧ insert e F ⊆ E "
have "(u, v) ∉ uconnected F" apply(rule insert_stays_forest_means_not_connected)
using notin a unv by auto
then show "((u, v) ∉ Restr (uconnected F) V)" by auto
next
assume a: "(u, v) ∉ Restr (uconnected F) V"
have "forest (insert (Upair u v) F)" apply(rule augment_forest_overedges[where E=E])
using notin f a unv by auto
moreover have "insert e F ⊆ E"
using notin f by auto
ultimately show "forest (insert e F) ∧ insert e F ⊆ E" using notin by auto
qed
next
fix F
assume "F⊆E"
show "equiv V (uconnectedV F)" by(rule equiv_vert_uconnected)
next
case (9 F)
then show ?case by auto
next
case (10 x y F)
then show ?case using insert_uconnectedV_per' by metis
next
case (11 x)
then show ?case apply(cases x) by auto
next
case (12 u v e)
then show ?case by auto
next
case (13 u v e)
then show ?case by auto
next
case (14 a F e)
then show ?case using ecard2 by force
next
case (15 v)
then show ?case using ecard2 by auto
next
case 16
show "V ⊆ V" by auto
next
case 17
show "finite V" by simp
next
case (18 a b e T)
then show ?case
apply auto
subgoal unfolding uconnected_def apply auto apply(rule exI[where x="[e]"]) apply simp
using ecard2 by force
subgoal by force
subgoal by force
done
next
case (19 xi x)
then show ?case by (auto split: prod.splits simp: α_def)
next
case 20
show ?case by auto
next
case 21
show ?case using getEdges_impl by simp
next
case (22 l)
from max_node_is_Max_V[OF 22] show "max_node l = Max (insert 0 V)" .
next
case (23)
then show ?case
apply sepref_to_hoare by sep_auto
qed
lemma spanningForest_eq_basis: "spanningForest = s.basis"
unfolding spanningForest_def s.basis_def by auto
lemma minSpanningForest_eq_minbasis: "minSpanningForest = s.minBasis"
unfolding minSpanningForest_def s.MSF_def spanningForest_eq_basis by auto
lemma kruskal_correct':
"<emp> kruskal getEdges_impl (λ(u,w,v). return (u,v)) ()
<λr. ↑ (distinct r ∧ set r ⊆ csuper_E ∧ s.MSF (set (map α r)))>⇩t"
using s.kruskal_correct_forest by auto
lemma kruskal_correct:
"<emp> kruskal getEdges_impl (λ(u,w,v). return (u,v)) ()
<λr. ↑ (distinct r ∧ set r ⊆ csuper_E ∧ minSpanningForest (set (map α r)))>⇩t"
using s.kruskal_correct_forest minSpanningForest_eq_minbasis by auto
end
subsection "Kruskal on UGraph from list of concrete edges"
definition "uGraph_from_list_α_weight L e = (THE w. ∃a' b'. Upair a' b' = e ∧ (a', w, b') ∈ set L)"
abbreviation "uGraph_from_list_α_edges L ≡ α ` set L"
locale fromlist = fixes
L :: "(nat × int × nat) list"
assumes dist: "distinct (map α L)" and no_selfloop: "∀u w v. (u,w,v)∈set L ⟶ u≠v"
begin
lemma not_distinct_map: "a∈set l ⟹ b∈set l ⟹ a≠b ⟹ α a = α b ⟹ ¬ distinct (map α l)"
by (meson distinct_map_eq)
lemma ii: "(a, aa, b) ∈ set L ⟹ uGraph_from_list_α_weight L (Upair a b) = aa"
unfolding uGraph_from_list_α_weight_def
apply rule
subgoal by auto
apply clarify
subgoal for w a' b'
apply(auto)
subgoal using distinct_map_eq[OF dist, of "(a, aa, b)" "(a, w, b)"]
unfolding α_def by auto
subgoal using distinct_map_eq[OF dist, of "(a, aa, b)" "(a', w, b')"]
unfolding α_def by fastforce
done
done
sublocale uGraph_impl "α ` set L" "uGraph_from_list_α_weight L" "return L" "set L"
proof (unfold_locales)
fix e assume *: "e ∈ α ` set L"
from * obtain u w v where "(u,w,v) ∈ set L" "e = α (u, w, v)" by auto
then show "proper_uprod e" using no_selfloop unfolding α_def by auto
next
show "finite (α ` set L)" by auto
next
show "(uncurry0 (return L),uncurry0((SPEC
(λLa. distinct (map α La) ∧ α ` set La = α ` set L
∧ (∀(aa, wv, ba)∈set La. uGraph_from_list_α_weight L (α (aa, wv, ba)) = wv)
∧ set La ⊆ set L))))
∈ unit_assn⇧k →⇩a list_assn (nat_assn ×⇩a int_assn ×⇩a nat_assn)"
apply sepref_to_hoare using dist apply sep_auto
subgoal using ii unfolding α_def by auto
subgoal by simp
subgoal by (auto simp: pure_fold list_assn_emp)
done
qed
lemmas kruskal_correct = kruskal_correct
definition (in -) "kruskal_algo L = kruskal (return L) (λ(u,w,v). return (u,v)) ()"
end
subsection ‹Outside the locale›
definition uGraph_from_list_invar :: "(nat×int×nat) list ⇒ bool" where
"uGraph_from_list_invar L = (distinct (map α L) ∧ (∀p∈set L. case p of (u,w,v) ⇒u≠v))"
lemma uGraph_from_list_invar_conv: "uGraph_from_list_invar L = fromlist L"
by(auto simp add: uGraph_from_list_invar_def fromlist_def)
lemma uGraph_from_list_invar_subset:
"uGraph_from_list_invar L ⟹ set L'⊆ set L ⟹ distinct L' ⟹ uGraph_from_list_invar L'"
unfolding uGraph_from_list_invar_def by (auto simp: distinct_map inj_on_subset)
lemma uGraph_from_list_α_inj_on: "uGraph_from_list_invar E ⟹ inj_on α (set E)"
by(auto simp: distinct_map uGraph_from_list_invar_def )
lemma sum_easier: "uGraph_from_list_invar L
⟹ set E ⊆ set L
⟹ sum (uGraph_from_list_α_weight L) (uGraph_from_list_α_edges E) = sum (λ(u,w,v). w) (set E)"
proof -
assume a: "uGraph_from_list_invar L"
assume b: "set E ⊆ set L"
have *: "⋀e. e∈set E ⟹
((λe. THE w. ∃a' b'. Upair a' b' = e ∧ (a', w, b') ∈ set L) ∘ α) e
= (case e of (u, w, v) ⇒ w)"
apply simp
apply(rule the_equality)
subgoal using b by(auto simp: α_def split: prod.splits)
subgoal using a b apply(auto simp: uGraph_from_list_invar_def distinct_map split: prod.splits)
using α_def
by (smt α_def inj_onD old.prod.case prod.inject set_mp)
done
have inj_on_E: "inj_on α (set E)"
apply(rule inj_on_subset)
apply(rule uGraph_from_list_α_inj_on) by fact+
show ?thesis
unfolding uGraph_from_list_α_weight_def
apply(subst sum.reindex[OF inj_on_E] )
using * by auto
qed
lemma corr: "uGraph_from_list_invar L ⟹
<emp> kruskal_algo L
<λF. ↑ (uGraph_from_list_invar F ∧ set F ⊆ set L ∧
uGraph.minSpanningForest (uGraph_from_list_α_edges L)
(uGraph_from_list_α_weight L) (uGraph_from_list_α_edges F))>⇩t"
apply(sep_auto heap: fromlist.kruskal_correct
simp: uGraph_from_list_invar_conv kruskal_algo_def )
using uGraph_from_list_invar_subset uGraph_from_list_invar_conv by simp
lemma "uGraph_from_list_invar L ⟹
<emp> kruskal_algo L
<λF. ↑ (uGraph_from_list_invar F ∧ set F ⊆ set L ∧
uGraph.spanningForest (uGraph_from_list_α_edges L) (uGraph_from_list_α_edges F)
∧ (∀F'. uGraph.spanningForest (uGraph_from_list_α_edges L) (uGraph_from_list_α_edges F')
⟶ set F' ⊆ set L ⟶ sum (λ(u,w,v). w) (set F) ≤ sum (λ(u,w,v). w) (set F')))>⇩t"
proof -
assume a: "uGraph_from_list_invar L"
then interpret fromlist L apply unfold_locales by (auto simp: uGraph_from_list_invar_def)
from a show ?thesis
by(sep_auto heap: corr simp: minSpanningForest_def sum_easier)
qed
subsection ‹Kruskal with input check›
definition "kruskal' L = kruskal (return L) (λ(u,w,v). return (u,v)) ()"
definition "kruskal_checked L = (if uGraph_from_list_invar L
then do { F ← kruskal' L; return (Some F) }
else return None)"
lemma "<emp> kruskal_checked L <λ
Some F ⇒ ↑ (uGraph_from_list_invar L ∧ set F ⊆ set L
∧ uGraph.minSpanningForest (uGraph_from_list_α_edges L) (uGraph_from_list_α_weight L)
(uGraph_from_list_α_edges F))
| None ⇒ ↑ (¬ uGraph_from_list_invar L)>⇩t"
unfolding kruskal_checked_def
apply(cases "uGraph_from_list_invar L") apply simp_all
subgoal proof -
assume [simp]: "uGraph_from_list_invar L"
then interpret fromlist L apply unfold_locales by(auto simp: uGraph_from_list_invar_def)
show ?thesis unfolding kruskal'_def by (sep_auto heap: kruskal_correct)
qed
subgoal by sep_auto
done
subsection ‹Code export›
export_code uGraph_from_list_invar checking SML_imp
export_code kruskal_checked checking SML_imp
ML_val ‹
val export_nat = @{code integer_of_nat}
val import_nat = @{code nat_of_integer}
val export_int = @{code integer_of_int}
val import_int = @{code int_of_integer}
val import_list = map (fn (a,b,c) => (import_nat a, (import_int b, import_nat c)))
val export_list = map (fn (a,(b,c)) => (export_nat a, export_int b, export_nat c))
val export_Some_list = (fn SOME l => SOME (export_list l) | NONE => NONE)
fun kruskal l = @{code kruskal} (fn () => import_list l) (fn (a,(_,c)) => fn () => (a,c)) () ()
|> export_list
fun kruskal_checked l = @{code kruskal_checked} (import_list l) () |> export_Some_list
val result = kruskal [(1,~9,2),(2,~3,3),(3,~4,1)]
val result4 = kruskal [(1,~100,4), (3,64,5), (1,13,2), (3,20,2), (2,5,5), (4,80,3), (4,40,5)]
val result' = kruskal_checked [(1,~9,2),(2,~3,3),(3,~4,1)]
val result1' = kruskal_checked [(1,~9,2),(2,~3,3),(3,~4,1),(1,5,3)]
val result2' = kruskal_checked [(1,~9,2),(2,~3,3),(3,~4,1),(3,~4,1)]
val result3' = kruskal_checked [(1,~9,2),(2,~3,3),(3,~4,1),(1,~4,1)]
val result4' = kruskal_checked [(1,~100,4), (3,64,5), (1,13,2), (3,20,2),
(2,5,5), (4,80,3), (4,40,5)]
›
end