Theory Prim_Abstract
section ‹Abstract Prim Algorithm›
theory Prim_Abstract
imports
Main
Common
Undirected_Graph
"HOL-Eisbach.Eisbach"
begin
subsection ‹Generic Algorithm: Light Edges\label{sec:generic_mst}›
definition "is_subset_MST w g A ≡ ∃t. is_MST w g t ∧ A ⊆ edges t"
lemma is_subset_MST_empty[simp]: "connected g ⟹ is_subset_MST w g {}"
using exists_MST unfolding is_subset_MST_def by blast
text ‹We fix a start node and a weighted graph›
locale Prim =
fixes w :: "'v set ⇒ nat" and g :: "'v ugraph" and r :: 'v
begin
text ‹Reachable part of the graph›
definition "rg ≡ component_of g r"
lemma reachable_connected[simp, intro!]: "connected rg"
unfolding rg_def by auto
lemma reachable_edges_subset: "edges rg ⊆ edges g"
unfolding rg_def by (rule component_edges_subset)
definition "light_edge C u v
≡ u∈C ∧ v∉C ∧ (u,v)∈edges rg
∧ (∀(u',v')∈edges rg ∩ C×-C. w {u,v} ≤ w {u',v'})"
definition "respects_cut A C ≡ A ⊆ C×C ∪ (-C)×(-C)"
lemma light_edge_is_safe:
fixes A :: "('v×'v) set" and C :: "'v set"
assumes subset_MST: "is_subset_MST w rg A"
assumes respects_cut: "respects_cut A C"
assumes light_edge: "light_edge C u v"
shows "is_subset_MST w rg ({(v,u)} ∪ A)"
proof -
have crossing_edge: "u∈C" "v∉C" "(u,v)∈edges rg"
and min_edge: "∀(u',v')∈edges rg ∩ C×-C. w {u,v} ≤ w {u',v'}"
using light_edge unfolding light_edge_def by auto
from subset_MST obtain T where T: "is_MST w rg T" "A ⊆ edges T"
unfolding is_subset_MST_def by auto
hence "tree T" "edges T ⊆ edges rg" "nodes T = nodes rg"
by (simp_all add: is_MST_def is_spanning_tree_def)
hence "connected T" by(simp_all add: tree_def)
show ?thesis
proof cases
assume "(u,v) ∈ edges T"
thus ?thesis unfolding is_subset_MST_def using T by (auto simp: edges_sym')
next
assume "(u,v) ∉ edges T" hence "(v,u)∉edges T" by (auto simp: edges_sym')
from ‹(u,v)∈edges rg› obtain p where p: "path T u p v" "simple p"
by (metis connectedD ‹connected T› ‹nodes T = nodes rg› nodesI
rtrancl_edges_iff_path simplify_pathE)
have [simp]: "u≠v" using crossing_edge by blast
from find_crossing_edge_on_path[OF p(1), where P="λx. x∉C"]
crossing_edge(1,2)
obtain x y p1 p2 where xy: "(x,y) ∈ set p" "x ∈ C" "y ∉ C"
and ux: "path (restrict_edges T (-{(x,y),(y,x)})) u p1 x"
and yv: "path (restrict_edges T (-{(x,y),(y,x)})) y p2 v"
using path_change[OF crossing_edge(1,2) p] by blast
have "(x,y) ∈ edges T"
by (meson contra_subsetD p(1) path_edges xy(1))
let ?E' = "edges T - {(x,y),(y,x)}"
from split_tree[OF ‹tree T› ‹(x,y)∈edges T›]
obtain T1 T2 where T12:
"tree T1" "tree T2"
and "nodes T1 ∩ nodes T2 = {}"
and "nodes T = nodes T1 ∪ nodes T2"
and "edges T1 ∪ edges T2 = ?E'"
and "nodes T1 = { u . (x,u)∈?E'⇧*}"
and "nodes T2 = { u . (y,u)∈?E'⇧*}"
and "x∈nodes T1" "y∈nodes T2" .
let ?T' = "ins_edge (u,v) (graph_join T1 T2)"
have "is_spanning_tree rg ?T'" proof -
have E'_sym: "sym (?E'⇧*)"
by (meson edgesT_diff_sng_inv_eq sym_conv_converse_eq sym_rtrancl)
have "u∈nodes T1"
unfolding ‹nodes T1 = _›
using path_rtrancl_edgesD[OF ux] by (auto dest: symD[OF E'_sym])
have "v∈nodes T2"
unfolding ‹nodes T2 = _›
using path_rtrancl_edgesD[OF yv] by auto
have "tree ?T'" by (rule join_trees) fact+
show "is_spanning_tree rg ?T'"
unfolding is_spanning_tree_def
using ‹nodes T = nodes rg› ‹nodes T = nodes T1 ∪ nodes T2›[symmetric]
using ‹tree ?T'› ‹u≠v›
using ‹edges T ⊆ edges rg› ‹edges T1 ∪ edges T2 = ?E'›
apply simp
by (metis Diff_subset crossing_edge(3) edges_sym' insert_absorb
nodesI(2) subset_trans)
qed
moreover
have "weight w ?T' ≤ weight w T'" if "is_spanning_tree rg T'" for T'
proof -
have ww: "w {u,v} ≤ w{x,y}"
using min_edge ‹(x,y)∈edges T› ‹edges T ⊆ edges rg› ‹x∈C› ‹y∉C›
by blast
have "weight w ?T' = weight w T - w {x,y} + w{u,v}"
using ‹(u, v) ∉ edges T› ‹(x, y) ∈ edges T›
using ‹edges T1 ∪ edges T2 = edges T - {(x, y), (y, x)}› ‹u ≠ v›
by (smt Diff_eq Diff_subset add.commute contra_subsetD edges_join
edges_restrict_edges minus_inv_sym_aux sup.idem weight_cong
weight_del_edge weight_ins_edge)
also have "… ≤ weight w T"
using weight_ge_edge[OF ‹(x,y)∈edges T›, of w] ww by auto
also have "weight w T ≤ weight w T'" using T(1) ‹is_spanning_tree rg T'›
unfolding is_MST_def by simp
finally show ?thesis .
qed
ultimately have "is_MST w rg ?T'" using is_MST_def by blast
have "{(u,v),(v,u)} ∪ A ⊆ edges ?T'"
using T(2) respects_cut xy(2,3) ‹edges T1 ∪ edges T2 = ?E'›
unfolding respects_cut_def
by auto
with ‹is_MST w rg ?T'› show ?thesis unfolding is_subset_MST_def by force
qed
qed
end
subsection ‹Abstract Prim: Growing a Tree\label{sec:prim_algo}›
context Prim begin
text ‹The current nodes›
definition "S A ≡ {r} ∪ fst`A ∪ snd`A"
lemma respects_cut': "A ⊆ S A × S A"
unfolding S_def by force
corollary respects_cut: "respects_cut A (S A)"
unfolding respects_cut_def using respects_cut' by auto
text ‹Refined invariant: Adds connectedness of ‹A››
definition "prim_invar1 A ≡ is_subset_MST w rg A ∧ (∀(u,v)∈A. (v,r)∈A⇧*)"
text ‹Measure: Number of nodes not in tree›
definition "T_measure1 A = card (nodes rg - S A)"
end
text ‹We use a locale that fixes a state and assumes the invariant›
locale Prim_Invar1_loc =
Prim w g r for w g and r :: 'v +
fixes A :: "('v×'v) set"
assumes invar1: "prim_invar1 A"
begin
lemma subset_MST: "is_subset_MST w rg A"
using invar1 unfolding prim_invar1_def by auto
lemma A_connected: "(u,v)∈A ⟹ (v,r)∈A⇧*"
using invar1 unfolding prim_invar1_def by auto
lemma S_alt_def: "S A = {r} ∪ fst`A"
unfolding S_def
apply (safe;simp)
by (metis A_connected Domain_fst Not_Domain_rtrancl)
lemma finite_rem_nodes[simp,intro!]: "finite (nodes rg - S A)" by auto
lemma A_edges: "A ⊆ edges g"
using subset_MST
by (meson is_MST_def is_spanning_tree_def is_subset_MST_def
reachable_edges_subset subset_eq)
lemma S_reachable: "S A ⊆ nodes rg"
unfolding S_alt_def
by (smt DomainE Un_insert_left fst_eq_Domain insert_subset is_MST_def
is_spanning_tree_def is_subset_MST_def nodesI(1) nodes_of_component
reachable_nodes_refl rg_def subset_MST subset_iff sup_bot.left_neutral)
lemma S_edge_reachable: "⟦u∈S A; (u,v)∈edges g ⟧ ⟹ (u,v)∈edges rg"
using S_reachable unfolding rg_def
using reachable_nodes_step'(2) by fastforce
lemma edges_S_rg_edges: "edges g ∩ S A×-S A = edges rg ∩ S A×-S A"
using S_edge_reachable reachable_edges_subset by auto
lemma T_measure1_less: "T_measure1 A < card (nodes rg)"
unfolding T_measure1_def S_def
by (metis Diff_subset S_def S_reachable Un_insert_left le_supE nodes_finite
psubsetI psubset_card_mono singletonI subset_Diff_insert)
lemma finite_A[simp, intro!]: "finite A"
using A_edges finite_subset by auto
lemma finite_S[simp, intro!]: "finite (S A)"
using S_reachable rev_finite_subset by blast
lemma S_A_consistent[simp, intro!]: "nodes_edges_consistent (S A) (A∪A¯)"
unfolding nodes_edges_consistent_def
apply (intro conjI)
subgoal by simp
subgoal using A_edges irrefl_def by fastforce
subgoal by (simp add: sym_Un_converse)
using respects_cut' by auto
end
context Prim begin
lemma invar1_initial: "prim_invar1 {}"
by (auto simp: is_subset_MST_def prim_invar1_def exists_MST)
lemma maintain_invar1:
assumes invar: "prim_invar1 A"
assumes light_edge: "light_edge (S A) u v"
shows "prim_invar1 ({(v,u)}∪A)
∧ T_measure1 ({(v,u)}∪A) < T_measure1 A" (is "?G1 ∧ ?G2")
proof
from invar interpret Prim_Invar1_loc w g r A by unfold_locales
from light_edge have "u∈S A" "v∉S A" by (simp_all add: light_edge_def)
show ?G1
unfolding prim_invar1_def
proof (intro conjI)
show "is_subset_MST w rg ({(v, u)} ∪ A)"
by (rule light_edge_is_safe[OF subset_MST respects_cut light_edge])
next
show "∀(ua, va)∈{(v, u)} ∪ A. (va, r) ∈ ({(v, u)} ∪ A)⇧*"
apply safe
subgoal
using A_connected
by (simp add: rtrancl_insert)
(metis DomainE S_alt_def converse_rtrancl_into_rtrancl ‹u∈S A›
fst_eq_Domain insertE insert_is_Un rtrancl_eq_or_trancl)
subgoal using A_connected by (simp add: rtrancl_insert)
done
qed
then interpret N: Prim_Invar1_loc w g r "{(v,u)}∪A" by unfold_locales
have "S A ⊂ S ({(v,u)}∪A)" using ‹v∉S A›
unfolding S_def by auto
then show "?G2" unfolding T_measure1_def
using S_reachable N.S_reachable
by (auto intro!: psubset_card_mono)
qed
lemma invar1_finish:
assumes INV: "prim_invar1 A"
assumes FIN: "edges g ∩ S A×-S A = {}"
shows "is_MST w rg (graph {r} A)"
proof -
from INV interpret Prim_Invar1_loc w g r A by unfold_locales
from subset_MST obtain t where MST: "is_MST w rg t" and "A ⊆ edges t"
unfolding is_subset_MST_def by auto
have "S A = nodes t"
proof safe
fix u
show "u∈S A ⟹ u∈nodes t" using MST
unfolding is_MST_def is_spanning_tree_def
using S_reachable by auto
next
fix u
assume "u∈nodes t"
hence "u∈nodes rg"
using MST is_MST_def is_spanning_tree_def by force
hence 1: "(u,r)∈(edges rg)⇧*" by (simp add: connectedD rg_def)
have "r∈S A" by (simp add: S_def)
show "u∈S A" proof (rule ccontr)
assume "u∉S A"
from find_crossing_edge_rtrancl[where P="λu. u∈S A", OF 1 ‹u∉S A› ‹r∈S A›]
FIN reachable_edges_subset
show False
by (smt ComplI IntI contra_subsetD edges_sym' emptyE mem_Sigma_iff)
qed
qed
also have "nodes t = nodes rg"
using MST unfolding is_MST_def is_spanning_tree_def
by auto
finally have S_eq: "S A = nodes rg" .
define t' where "t' = graph {r} A"
have [simp]: "nodes t' = S A" and Et': "edges t' = (A∪A¯)" unfolding t'_def
using A_edges
by (auto simp: graph_accs S_def)
hence "edges t' ⊆ edges t"
by (smt UnE ‹A ⊆ edges t› converseD edges_sym' subrelI subset_eq)
have "is_spanning_tree rg t'"
proof -
have "connected t'"
apply rule
apply (simp add: Et' S_def)
apply safe
apply ((simp add: A_connected converse_rtrancl_into_rtrancl
in_rtrancl_UnI rtrancl_converse
)+
) [4]
apply simp_all [4]
apply ((meson A_connected in_rtrancl_UnI r_into_rtrancl
rtrancl_converseI rtrancl_trans
)+
) [4]
done
moreover have "cycle_free t'"
by (meson MST ‹edges t' ⊆ edges t› cycle_free_antimono is_MST_def
is_spanning_tree_def tree_def)
moreover have "edges t' ⊆ edges rg"
by (meson MST ‹edges t' ⊆ edges t› dual_order.trans is_MST_def
is_spanning_tree_def)
ultimately show ?thesis
unfolding is_spanning_tree_def tree_def
by (auto simp: S_eq)
qed
then show ?thesis
using MST weight_mono[OF ‹edges t' ⊆ edges t›]
unfolding t'_def is_MST_def
using dual_order.trans by blast
qed
end
subsection ‹Prim: Using a Priority Queue\label{sec:using_pq}›
text ‹We define a new locale. Note that we could also reuse @{locale Prim}, however,
this would complicate referencing the constants later in the theories from
which we generate the paper.
›
locale Prim2 = Prim w g r for w :: "'v set ⇒ nat" and g :: "'v ugraph" and r :: 'v
begin
text ‹Abstraction to edge set›
definition "A Q π ≡ {(u,v). π u = Some v ∧ Q u = ∞}"
text ‹Initialization›
definition initQ :: "'v ⇒ enat" where "initQ ≡ (λ_. ∞)(r := 0)"
definition initπ :: "'v ⇒ 'v option" where "initπ ≡ Map.empty"
text ‹Step›
definition "upd_cond Q π u v' ≡
(v',u) ∈ edges g
∧ v'≠r ∧ (Q v' = ∞ ⟶ π v' = None)
∧ enat (w {v',u}) < Q v'"
text ‹State after inner loop›
definition "Qinter Q π u v'
= (if upd_cond Q π u v' then enat (w {v',u}) else Q v')"
text ‹State after one step›
definition "Q' Q π u ≡ (Qinter Q π u)(u:=∞)"
definition "π' Q π u v' = (if upd_cond Q π u v' then Some u else π v')"
definition "prim_invar2_init Q π ≡ Q=initQ ∧ π=initπ"
definition "prim_invar2_ctd Q π ≡ let A = A Q π; S = S A in
prim_invar1 A
∧ π r = None ∧ Q r = ∞
∧ (∀(u,v)∈edges rg ∩ (-S)×S. Q u ≠ ∞)
∧ (∀u. Q u ≠ ∞ ⟶ π u ≠ None)
∧ (∀u v. π u = Some v ⟶ v∈S ∧ (u,v)∈edges rg)
∧ (∀u v d. Q u = enat d ∧ π u = Some v
⟶ d=w {u,v} ∧ (∀v'∈S. (u,v')∈edges rg ⟶ d ≤ w {u,v'}))
"
lemma prim_invar2_ctd_alt_aux1:
assumes "prim_invar1 (A Q π)"
assumes "Q u ≠ ∞" "u≠r"
shows "u∉S (A Q π)"
proof -
interpret Prim_Invar1_loc w g r "A Q π" by unfold_locales fact
show ?thesis
unfolding S_alt_def unfolding A_def using assms
by auto
qed
lemma prim_invar2_ctd_alt: "prim_invar2_ctd Q π ⟷ (
let A = A Q π; S = S A; cE=edges rg ∩ (-S)×S in
prim_invar1 A
∧ π r = None ∧ Q r = ∞
∧ (∀(u,v)∈cE. Q u ≠ ∞)
∧ (∀u v. π u = Some v ⟶ v∈S ∧ (u,v)∈edges rg)
∧ (∀u d. Q u = enat d
⟶ (∃v. π u = Some v ∧ d=w {u,v} ∧ (∀v'. (u,v')∈cE ⟶ d ≤ w {u,v'})))
)"
unfolding prim_invar2_ctd_def Let_def
using prim_invar2_ctd_alt_aux1[of Q π]
apply safe
subgoal by auto
subgoal by (auto 0 3)
subgoal by (auto 0 3)
subgoal by clarsimp (metis (no_types,lifting) option.simps(3))
done
definition "prim_invar2 Q π ≡ prim_invar2_init Q π ∨ prim_invar2_ctd Q π"
definition "T_measure2 Q π
≡ if Q r = ∞ then T_measure1 (A Q π) else card (nodes rg)"
lemma Q'_init_eq:
"Q' initQ initπ r = (λu. if (u,r)∈edges rg then enat (w {u,r}) else ∞)"
apply (rule ext)
using reachable_edges_subset
apply (simp add: Q'_def Qinter_def upd_cond_def initQ_def initπ_def)
by (auto simp: Prim.rg_def edges_sym' reachable_nodes_step'(2))
lemma π'_init_eq:
"π' initQ initπ r = (λu. if (u,r)∈edges rg then Some r else None)"
apply (rule ext)
using reachable_edges_subset
apply (simp add: π'_def upd_cond_def initQ_def initπ_def)
by (auto simp: Prim.rg_def edges_sym' reachable_nodes_step'(2))
lemma A_init_eq: "A initQ initπ = {}"
unfolding A_def initπ_def
by auto
lemma S_empty: "S {} = {r}" unfolding S_def by (auto simp: A_init_eq)
lemma maintain_invar2_first_step:
assumes INV: "prim_invar2_init Q π"
assumes UNS: "Q u = enat d"
shows "prim_invar2_ctd (Q' Q π u) (π' Q π u)" (is ?G1)
and "T_measure2 (Q' Q π u) (π' Q π u) < T_measure2 Q π" (is ?G2)
proof -
from INV have [simp]: "Q=initQ" "π=initπ"
unfolding prim_invar2_init_def by auto
from UNS have [simp]: "u=r" by (auto simp: initQ_def split: if_splits)
note Q'_init_eq π'_init_eq A_init_eq
have [simp]: "(A (Q' initQ initπ r) (π' initQ initπ r)) = {}"
apply (simp add: Q'_init_eq π'_init_eq)
by (auto simp: A_def split: if_splits)
show ?G1
apply (simp add: prim_invar2_ctd_def Let_def invar1_initial)
by (auto simp: Q'_init_eq π'_init_eq S_empty split: if_splits)
have [simp]: "Q' initQ initπ r r = ∞"
by (auto simp: Q'_init_eq)
have [simp]: "initQ r = 0" by (simp add: initQ_def)
show ?G2
unfolding T_measure2_def
apply simp
apply (simp add: T_measure1_def S_empty)
by (metis card_Diff1_less nodes_finite nodes_of_component
reachable_nodes_refl rg_def)
qed
lemma maintain_invar2_first_step_presentation:
assumes INV: "prim_invar2_init Q π"
assumes UNS: "Q u = enat d"
shows "prim_invar2_ctd (Q' Q π u) (π' Q π u)
∧ T_measure2 (Q' Q π u) (π' Q π u) < T_measure2 Q π"
using maintain_invar2_first_step assms by blast
end
locale Prim_Invar2_ctd_Presentation_Loc =
fixes w g and r :: 'v and Q π A S rg cE
assumes I: "Prim2.prim_invar2_ctd w g r Q π"
defines local_A_def: "A ≡ Prim2.A Q π"
defines local_S_def: "S ≡ Prim.S r A"
defines local_rg_def: "rg ≡ Prim.rg g r"
defines local_cE_def: "cE ≡ edges rg ∩ (-S)×S"
begin
lemma
invar1: "Prim.prim_invar1 w g r A" (is ?G1)
and root_contained: "π r = None ∧ Q r = ∞" (is ?G2)
and Q_defined: "∀(u,v)∈cE. Q u ≠ ∞" (is ?G3)
and π_edges: "∀u v. π u = Some v ⟶ v∈S ∧ (u,v)∈edges rg" (is ?G4)
and Q_min: "∀u d. Q u = enat d
⟶ (∃v. π u = Some v ∧ d=w {u,v} ∧ (∀v'. (u,v')∈cE ⟶ d ≤ w {u,v'}))"
(is ?G5)
proof -
interpret Prim2 w g r .
show ?G1 ?G2 ?G3 ?G4 ?G5
using I
unfolding local_A_def local_S_def local_rg_def local_cE_def
prim_invar2_ctd_alt Let_def
by simp_all
qed
end
lemma (in Prim2) Prim_Invar2_ctd_Presentation_Loc_eq:
"Prim_Invar2_ctd_Presentation_Loc w g r Q π ⟷ prim_invar2_ctd Q π"
unfolding Prim_Invar2_ctd_Presentation_Loc_def ..
text ‹Again, we define a locale to fix a state and assume the invariant›
locale Prim_Invar2_ctd_loc =
Prim2 w g r for w g and r :: 'v +
fixes Q π
assumes invar2: "prim_invar2_ctd Q π"
begin
sublocale Prim_Invar1_loc w g r "A Q π"
using invar2 unfolding prim_invar2_ctd_def
apply unfold_locales by (auto simp: Let_def)
lemma upd_cond_alt: "upd_cond Q π u v' ⟷
(v',u) ∈ edges g ∧ v'∉S (A Q π) ∧ enat (w {v',u}) < Q v'"
unfolding upd_cond_def S_alt_def unfolding A_def
by (auto simp: fst_eq_Domain)
lemma π_root: "π r = None"
and Q_root: "Q r = ∞"
and Q_defined: "⟦ (u,v)∈edges rg; u∉S (A Q π); v∈S (A Q π) ⟧ ⟹ Q u ≠ ∞"
and π_defined: "⟦ Q u ≠ ∞ ⟧ ⟹ π u ≠ None"
and frontier: "π u = Some v ⟹ v∈S (A Q π)"
and edges: "π u = Some v ⟹ (u,v)∈edges rg"
and Q_π_consistent: "⟦ Q u = enat d; π u = Some v ⟧ ⟹ d = w {u,v}"
and Q_min: "Q u = enat d
⟹ (∀v'∈S (A Q π). (u,v')∈edges rg ⟶ d ≤ w {u,v'})"
using invar2 unfolding prim_invar2_ctd_def Let_def by auto
lemma π_def_on_S: "⟦u∈S (A Q π); u≠r⟧ ⟹ π u ≠ None"
unfolding S_alt_def
unfolding A_def
by auto
lemma π_def_on_edges_to_S: "⟦v∈S (A Q π); u≠r; (u,v)∈edges rg⟧ ⟹ π u ≠ None"
apply (cases "u∈S (A Q π)")
subgoal using π_def_on_S by auto
subgoal by (simp add: Q_defined π_defined)
done
lemma Q_min_is_light:
assumes UNS: "Q u = enat d"
assumes MIN: "∀v. enat d ≤ Q v"
obtains v where "π u = Some v" "light_edge (S (A Q π)) v u"
proof -
let ?A = "A Q π"
let ?S = "S ?A"
from UNS obtain v where
S1[simp]: "π u = Some v" "d = w {u,v}"
using π_defined Q_π_consistent
by blast
have "v∈?S" using frontier[of u v] by auto
have [simp]: "u≠r" using π_root using S1 by (auto simp del: S1)
have "u∉?S" unfolding S_alt_def unfolding A_def using UNS by auto
have "(v,u)∈edges rg" using edges[OF S1(1)]
by (meson edges_sym' rev_subsetD)
have M: "∀(u', v')∈edges rg ∩ ?S × - ?S. w {v, u} ≤ w {u', v'}"
proof safe
fix a b
assume "(a,b)∈edges rg" "a∈?S" "b∉?S"
hence "(b,a)∈edges rg" by (simp add: edges_sym')
from Q_defined[OF ‹(b,a)∈edges rg› ‹b∉?S› ‹a∈?S›]
obtain d' where 1: "Q b = enat d'" by blast
with π_defined obtain a' where "π b = Some a'" by auto
from MIN 1 have "d≤d'" by (metis enat_ord_simps(1))
also from Q_min[OF 1] ‹(b,a)∈edges rg› ‹a∈?S› have "d'≤w {b,a}" by blast
finally show "w {v,u} ≤ w {a,b}" by (simp add: insert_commute)
qed
have LE: "light_edge ?S v u" using invar1 ‹v∈?S› ‹u∉?S› ‹(v,u)∈edges rg› M
unfolding light_edge_def by blast
thus ?thesis using that by auto
qed
lemma maintain_invar_ctd:
assumes UNS: "Q u = enat d"
assumes MIN: "∀v. enat d ≤ Q v"
shows "prim_invar2_ctd (Q' Q π u) (π' Q π u)" (is ?G1)
and "T_measure2 (Q' Q π u) (π' Q π u) < T_measure2 Q π" (is ?G2)
proof -
let ?A = "A Q π"
let ?S = "S ?A"
from Q_min_is_light[OF UNS MIN] obtain v where
[simp]: "π u = Some v" and LE: "light_edge ?S v u" .
let ?Q' = "Q' Q π u"
let ?π' = "π' Q π u"
let ?A' = "A ?Q' ?π'"
let ?S' = "S ?A'"
have NA: "?A' = {(u,v)} ∪ ?A"
unfolding A_def
unfolding Q'_def π'_def upd_cond_def Qinter_def
by (auto split: if_splits)
from maintain_invar1[OF invar1 LE]
have "prim_invar1 ?A'" and M1: "T_measure1 ?A' < T_measure1 ?A"
by (auto simp: NA)
then interpret N: Prim_Invar1_loc w g r ?A' by unfold_locales
have [simp]: "?S' = insert u ?S"
unfolding S_alt_def N.S_alt_def
unfolding Q'_def Qinter_def π'_def upd_cond_def
unfolding A_def
by (auto split: if_splits simp: image_iff)
show ?G1
unfolding prim_invar2_ctd_def Let_def
apply safe
subgoal by fact
subgoal
unfolding π'_def upd_cond_def
by (auto simp: π_root)
subgoal
by (simp add: Prim2.Q'_def Prim2.Qinter_def Prim2.upd_cond_def Q_root)
subgoal for a b
apply simp
apply safe
subgoal
unfolding Q'_def Qinter_def upd_cond_def
apply (simp add: S_alt_def A_def)
apply safe
subgoal using reachable_edges_subset by blast
subgoal by (simp add: Prim.S_def)
subgoal by (metis (no_types) A_def Q_defined edges frontier)
subgoal using not_infinity_eq by fastforce
done
subgoal
unfolding S_alt_def N.S_alt_def
unfolding A_def Q'_def Qinter_def upd_cond_def
apply (simp; safe; (auto;fail)?)
subgoal
proof -
assume a1: "(a, r) ∈ edges rg"
assume "a ∉ fst ` {(u, v). π u = Some v ∧ Q u = ∞}"
then have "a ∉ fst ` A Q π"
by (simp add: A_def)
then show ?thesis
using a1
by (metis (no_types) S_alt_def Q_defined Un_insert_left
edges_irrefl' insert_iff not_infinity_eq sup_bot.left_neutral)
qed
subgoal by (simp add: fst_eq_Domain)
subgoal
apply clarsimp
by (smt Domain.intros Q_defined π_def_on_edges_to_S case_prod_conv
edges enat.exhaust frontier fst_eq_Domain mem_Collect_eq
option.exhaust)
subgoal by (simp add: fst_eq_Domain)
done
done
subgoal
by (metis Q'_def Qinter_def π'_def π_defined enat.distinct(2)
fun_upd_apply not_None_eq)
subgoal
by (metis ‹S (A (Q' Q π u) (π' Q π u)) = insert u (S (A Q π))› π'_def
frontier insertCI option.inject)
subgoal
by (metis N.S_edge_reachable upd_cond_def
‹S (A (Q' Q π u) (π' Q π u)) = insert u (S (A Q π))› π'_def edges
edges_sym' insertI1 option.inject)
subgoal
by (smt Q'_def π'_def Q_π_consistent Qinter_def fun_upd_apply
insert_absorb not_enat_eq option.inject the_enat.simps)
subgoal for v' d'
apply clarsimp
unfolding Q'_def Qinter_def upd_cond_def
using Q_min
apply (clarsimp split: if_splits; safe)
apply (all ‹(auto;fail)?›)
subgoal by (simp add: le_less less_le_trans)
subgoal using π_def_on_edges_to_S by auto
subgoal using reachable_edges_subset by auto
subgoal by (simp add: Q_root)
done
done
then interpret N: Prim_Invar2_ctd_loc w g r ?Q' ?π' by unfold_locales
show ?G2
unfolding T_measure2_def
by (auto simp: Q_root N.Q_root M1)
qed
end
context Prim2 begin
lemma maintain_invar2_ctd:
assumes INV: "prim_invar2_ctd Q π"
assumes UNS: "Q u = enat d"
assumes MIN: "∀v. enat d ≤ Q v"
shows "prim_invar2_ctd (Q' Q π u) (π' Q π u)" (is ?G1)
and "T_measure2 (Q' Q π u) (π' Q π u) < T_measure2 Q π" (is ?G2)
proof -
interpret Prim_Invar2_ctd_loc w g r Q π using INV by unfold_locales
from maintain_invar_ctd[OF UNS MIN] show ?G1 ?G2 by auto
qed
lemma Q_min_is_light_presentation:
assumes INV: "prim_invar2_ctd Q π"
assumes UNS: "Q u = enat d"
assumes MIN: "∀v. enat d ≤ Q v"
obtains v where "π u = Some v" "light_edge (S (A Q π)) v u"
proof -
interpret Prim_Invar2_ctd_loc w g r Q π using INV by unfold_locales
from Q_min_is_light[OF UNS MIN] show ?thesis using that .
qed
lemma maintain_invar2_ctd_presentation:
assumes INV: "prim_invar2_ctd Q π"
assumes UNS: "Q u = enat d"
assumes MIN: "∀v. enat d ≤ Q v"
shows "prim_invar2_ctd (Q' Q π u) (π' Q π u)
∧ T_measure2 (Q' Q π u) (π' Q π u) < T_measure2 Q π"
using maintain_invar2_ctd assms by blast
lemma not_invar2_ctd_init:
"prim_invar2_init Q π ⟹ ¬prim_invar2_ctd Q π"
unfolding prim_invar2_init_def prim_invar2_ctd_def initQ_def Let_def
by (auto)
lemma invar2_init_init: "prim_invar2_init initQ initπ"
unfolding prim_invar2_init_def by auto
lemma invar2_init: "prim_invar2 initQ initπ"
unfolding prim_invar2_def using invar2_init_init by auto
lemma maintain_invar2:
assumes A: "prim_invar2 Q π"
assumes UNS: "Q u = enat d"
assumes MIN: "∀v. enat d ≤ Q v"
shows "prim_invar2 (Q' Q π u) (π' Q π u)" (is ?G1)
and "T_measure2 (Q' Q π u) (π' Q π u) < T_measure2 Q π" (is ?G2)
using A unfolding prim_invar2_def
using maintain_invar2_first_step[of Q,OF _ UNS]
using maintain_invar2_ctd[OF _ UNS MIN]
using not_invar2_ctd_init
apply blast+
done
lemma invar2_ctd_finish:
assumes INV: "prim_invar2_ctd Q π"
assumes FIN: "Q = (λ_. ∞)"
shows "is_MST w rg (graph {r} {(u, v). π u = Some v})"
proof -
from INV interpret Prim_Invar2_ctd_loc w g r Q π by unfold_locales
let ?A = "A Q π" let ?S="S ?A"
have FC: "edges g ∩ ?S × - ?S = {}"
proof (safe; simp)
fix a b
assume "(a,b)∈edges g" "a∈?S" "b∉?S"
with Q_defined[OF edges_sym'] S_edge_reachable have "Q b ≠ ∞"
by blast
with FIN show False by auto
qed
have Aeq: "?A = {(u, v). π u = Some v}"
unfolding A_def using FIN by auto
from invar1_finish[OF invar1 FC, unfolded Aeq] show ?thesis .
qed
lemma invar2_finish:
assumes INV: "prim_invar2 Q π"
assumes FIN: "Q = (λ_. ∞)"
shows "is_MST w rg (graph {r} {(u, v). π u = Some v})"
proof -
from INV have "prim_invar2_ctd Q π"
unfolding prim_invar2_def prim_invar2_init_def initQ_def
by (auto simp: fun_eq_iff FIN split: if_splits)
with FIN invar2_ctd_finish show ?thesis by blast
qed
end
subsection ‹Refinement of Inner Foreach Loop\label{sec:using_foreach}›
context Prim2 begin
definition "foreach_body u ≡ λ(v,d) (Q,π).
if v=r then (Q,π)
else
case (Q v, π v) of
(∞,None) ⇒ (Q(v:=enat d), π(v↦u))
| (enat d',_) ⇒ if d<d' then (Q(v:=enat d), π(v↦u)) else (Q,π)
| (∞,Some _) ⇒ (Q,π)
"
lemma foreach_body_alt: "foreach_body u = (λ(v,d) (Q,π).
if v≠r ∧ (π v = None ∨ Q v ≠ ∞) ∧ enat d < Q v then
(Q(v:=enat d), π(v↦u))
else
(Q,π)
)"
unfolding foreach_body_def S_def
by (auto split: enat.splits option.splits simp: fst_eq_Domain fun_eq_iff)
definition foreach where
"foreach u adjs Qπ = foldr (foreach_body u) adjs Qπ"
definition "⋀Q V.
Qigen Q π u adjs v = (if v ∉ fst`set adjs then Q v else Qinter Q π u v)"
definition "⋀Q V π.
π'gen Q π u adjs v = (if v ∉ fst`set adjs then π v else π' Q π u v)"
context begin
private lemma Qc:
"Qigen Q π u ((v, w {u, v}) # adjs) x
= (if x=v then Qinter Q π u v else Qigen Q π u adjs x)" for x
unfolding Qigen_def by auto
private lemma πc:
"π'gen Q π u ((v, w {u, v}) # adjs) x
= (if x=v then π' Q π u v else π'gen Q π u adjs x)" for x
unfolding π'gen_def by auto
lemma foreach_refine_gen:
assumes "set adjs ⊆ {(v,d). (u,v)∈edges g ∧ w {u,v} = d}"
shows "foreach u adjs (Q,π) = (Qigen Q π u adjs,π'gen Q π u adjs)"
using assms
unfolding foreach_def
proof (induction adjs arbitrary: Q π)
case Nil
have INVAR_INIT: "Qigen Q π u [] = Q" "π'gen Q π u [] = π" for Q π
unfolding assms Qigen_def π'gen_def
by (auto simp: fun_eq_iff image_def Q'_def π'_def edges_def)
with Nil show ?case by (simp add: INVAR_INIT)
next
case (Cons a adjs)
obtain v d where [simp]: "a=(v,d)" by (cases a)
have [simp]: "u≠v" "v≠u" using Cons.prems by auto
have QinfD: "Qigen Q π u adjs v = ∞ ⟹ Q v = ∞"
unfolding Qigen_def Q'_def Qinter_def by (auto split: if_splits)
show ?case using Cons.prems
apply (cases a)
apply (clarsimp simp: Cons.IH)
unfolding foreach_body_def
apply (clarsimp; safe)
subgoal by (auto simp: Qigen_def Qinter_def upd_cond_def)
subgoal by (auto simp: π'gen_def π'_def upd_cond_def)
subgoal
apply (clarsimp split: enat.split option.split simp: πc Qc fun_eq_iff)
unfolding Qinter_def Qigen_def π'_def π'gen_def upd_cond_def
apply (safe; simp split: if_splits add: insert_commute)
by (auto dest: edges_sym')
done
qed
lemma foreach_refine:
assumes "set adjs = {(v,d). (u,v)∈edges g ∧ w {u,v} = d}"
shows "foreach u adjs (Q,π) = (Qinter Q π u,π' Q π u)"
proof -
have INVAR_INIT: "Qigen Q π u [] = Q" "π'gen Q π u [] = π" for Q π
unfolding assms Qigen_def π'gen_def
by (auto simp: fun_eq_iff image_def Q'_def π'_def edges_def)
from assms have 1: "set adjs ⊆ {(v,d). (u,v)∈edges g ∧ w {u,v} = d}"
by simp
have [simp]:
"v ∈ fst ` {(v, d). (u, v) ∈ edges g ∧ w {u, v} = d}
⟷ (u,v)∈edges g"
for v
by force
show ?thesis
unfolding foreach_refine_gen[OF 1]
unfolding Qigen_def π'gen_def assms upd_cond_def Qinter_def π'_def
by (auto simp: fun_eq_iff image_def dest: edges_sym')
qed
end
end
end