Theory Undirected_Graph_Impl
section ‹Implementation of Weighted Undirected Graph by Map›
theory Undirected_Graph_Impl
imports
"HOL-Data_Structures.Map_Specs"
Common
Undirected_Graph_Specs
begin
subsection ‹Doubleton Set to Pair›
definition "epair e = (if card e = 2 then Some (SOME (u,v). e={u,v}) else None)"
lemma epair_eqD: "epair e = Some (x,y) ⟹ (x≠y ∧ e={x,y})"
apply (cases "card e = 2")
unfolding epair_def
apply simp_all
apply (clarsimp simp: card_Suc_eq eval_nat_numeral doubleton_eq_iff)
by (smt case_prodD case_prodI someI)
lemma epair_not_sng[simp]: "epair e ≠ Some (x,x)"
by (auto dest: epair_eqD)
lemma epair_None[simp]: "epair {a,b} = None ⟷ a=b"
unfolding epair_def by (auto simp: card2_eq)
subsection ‹Generic Implementation›
text ‹
When instantiated with a map ADT, this locale provides a weighted graph ADT.
›
locale wgraph_by_map =
M: Map M_empty M_update M_delete M_lookup M_invar
for M_empty M_update M_delete
and M_lookup :: "'m ⇒ 'v ⇒ (('v×nat) list) option"
and M_invar
begin
definition "αnodes_aux g ≡ dom (M_lookup g)"
definition "αedges_aux g
≡ ({(u,v). ∃xs d. M_lookup g u = Some xs ∧ (v,d)∈set xs })"
definition "αg g ≡ graph (αnodes_aux g) (αedges_aux g)"
definition "αw g e ≡ case epair e of
Some (u,v) ⇒ (
case M_lookup g u of
None ⇒ 0
| Some xs ⇒ the_default 0 (map_of xs v)
)
| None ⇒ 0"
definition invar :: "'m ⇒ bool" where
"invar g ≡
M_invar g ∧ finite (dom (M_lookup g))
∧ (∀u xs. M_lookup g u = Some xs ⟶
distinct (map fst xs)
∧ u∉set (map fst xs)
∧ (∀(v,d)∈set xs. (u,d)∈set (the_default [] (M_lookup g v)))
)"
lemma in_the_default_empty_conv[simp]:
"x∈set (the_default [] m) ⟷ (∃xs. m=Some xs ∧ x∈set xs)"
by (cases m) auto
lemma αedges_irrefl: "invar g ⟹ irrefl (αedges_aux g)"
unfolding invar_def irrefl_def αedges_aux_def
by (force)
lemma αedges_sym: "invar g ⟹ sym (αedges_aux g)"
unfolding invar_def sym_def αedges_aux_def
by force
lemma αedges_subset: "invar g ⟹ αedges_aux g ⊆ αnodes_aux g × αnodes_aux g"
unfolding invar_def αnodes_aux_def αedges_aux_def
by force
lemma αnodes_finite[simp, intro!]: "invar g ⟹ finite (αnodes_aux g)"
unfolding invar_def αnodes_aux_def by simp
lemma αedges_finite[simp, intro!]: "invar g ⟹ finite (αedges_aux g)"
using finite_subset[OF αedges_subset] by blast
definition adj :: "'m ⇒ 'v ⇒ ('v×nat) list" where
"adj g v = the_default [] (M_lookup g v)"
definition empty :: "'m" where "empty = M_empty"
definition add_edge1 :: "'v×'v ⇒ nat ⇒ 'm ⇒ 'm" where
"add_edge1 ≡ λ(u,v) d g. M_update u ((v,d) # the_default [] (M_lookup g u)) g"
definition add_edge :: "'v×'v ⇒ nat ⇒ 'm ⇒ 'm" where
"add_edge ≡ λ(u,v) d g. add_edge1 (v,u) d (add_edge1 (u,v) d g)"
lemma edges_αg_aux: "invar g ⟹ edges (αg g) = αedges_aux g"
unfolding αg_def using αedges_sym αedges_irrefl
by (auto simp: irrefl_def graph_accs)
lemma nodes_αg_aux: "invar g ⟹ nodes (αg g) = αnodes_aux g"
unfolding αg_def using αedges_subset
by (force simp: graph_accs)
lemma card_doubleton_eq2[simp]: "card {a,b} = 2 ⟷ a≠b" by auto
lemma the_dflt_Z_eq: "the_default 0 m = d ⟷ (m=None ∧ d=0 ∨ m=Some d)"
by (cases m) auto
lemma adj_correct_aux:
"invar g ⟹ set (adj g u) = {(v, d). (u, v) ∈ edges (αg g) ∧ αw g {u, v} = d}"
apply (simp add: edges_αg_aux)
apply safe
subgoal unfolding adj_def αedges_aux_def by auto
subgoal for a d
unfolding adj_def αw_def
apply (clarsimp split: prod.splits option.splits simp: the_dflt_Z_eq)
unfolding invar_def
by (force dest!: epair_eqD simp: doubleton_eq_iff)+
subgoal for a
unfolding adj_def αw_def
using αedges_irrefl[of g]
apply (clarsimp split: prod.splits option.splits)
apply safe
subgoal by (auto simp: irrefl_def)
subgoal
apply (clarsimp dest!: epair_eqD simp: doubleton_eq_iff)
unfolding invar_def αedges_aux_def
by force
subgoal
apply (clarsimp dest!: epair_eqD simp: doubleton_eq_iff)
unfolding invar_def αedges_aux_def
apply clarsimp
by (smt case_prod_conv map_of_is_SomeI the_default.simps(2))
done
done
lemma invar_empty_aux: "invar empty"
by (simp add: invar_def empty_def M.map_specs)
lemma dist_fst_the_dflt_aux: "distinct (map fst (the_default [] m))
⟷ (∀xs. m = Some xs ⟶ distinct (map fst xs))"
by (cases m; auto)
lemma invar_add_edge_aux:
"⟦invar g; (u, v) ∉ edges (αg g); u ≠ v⟧ ⟹ invar (add_edge (u, v) d g)"
apply (simp add: edges_αg_aux)
unfolding add_edge_def add_edge1_def invar_def αedges_aux_def
by (auto simp: M.map_specs dist_fst_the_dflt_aux; force)
sublocale adt_wgraph αw αg invar adj empty add_edge
apply unfold_locales
subgoal by (simp add: adj_correct_aux)
subgoal by (simp add: invar_empty_aux)
subgoal
apply (simp
add: graph_eq_iff nodes_αg_aux invar_empty_aux edges_αg_aux
add: αnodes_aux_def αedges_aux_def
)
apply (simp add: empty_def M.map_specs)
done
subgoal
unfolding αw_def
by (auto simp: empty_def M.map_specs fun_eq_iff split: option.splits)
subgoal by (simp add: invar_add_edge_aux)
subgoal for g u v d
apply (simp add: edges_αg_aux nodes_αg_aux graph_eq_iff invar_add_edge_aux)
apply (rule conjI)
subgoal
unfolding add_edge_def add_edge1_def invar_def αnodes_aux_def
by (auto simp: M.map_specs)
subgoal
unfolding add_edge_def add_edge1_def invar_def αedges_aux_def
by (fastforce simp: M.map_specs split!: if_splits)
done
subgoal for g u v d
apply (simp add: edges_αg_aux invar_add_edge_aux)
unfolding invar_def αw_def add_edge_def add_edge1_def
by (auto
dest: epair_eqD
simp: fun_eq_iff M.map_specs
split!: prod.splits option.splits if_splits)
done
end
end