Theory FiniteListGraph
theory FiniteListGraph
imports
FiniteGraph
"Transitive-Closure.Transitive_Closure_List_Impl"
begin
section ‹Specification of a finite graph, implemented by lists›
text‹A graph ‹G=(V,E)› consits of a list of vertices @{term V}, also called nodes,
and a list of edges @{term E}. The edges are tuples of vertices.
Using lists instead of sets, code can be easily created.›
record 'v list_graph =
nodesL :: "'v list"
edgesL :: "('v ×'v) list"
text‹Correspondence the FiniteGraph›
definition list_graph_to_graph :: "'v list_graph ⇒ 'v graph" where
"list_graph_to_graph G = ⦇ nodes = set (nodesL G), edges = set (edgesL G) ⦈"
definition wf_list_graph_axioms :: "'v list_graph ⇒ bool" where
"wf_list_graph_axioms G ⟷ fst` set (edgesL G) ⊆ set (nodesL G) ∧ snd` set (edgesL G) ⊆ set (nodesL G)"
lemma wf_list_graph_iff_wf_graph: "wf_graph (list_graph_to_graph G) ⟷ wf_list_graph_axioms G"
unfolding list_graph_to_graph_def wf_graph_def wf_list_graph_axioms_def
by simp
text‹We say a @{typ "'v list_graph"} is valid if it fulfills the graph axioms and its lists are distinct›
definition wf_list_graph::"('v) list_graph ⇒ bool" where
"wf_list_graph G = (distinct (nodesL G) ∧ distinct (edgesL G) ∧ wf_list_graph_axioms G)"
section‹FiniteListGraph operations›
text ‹Adds a node to a graph.›
definition add_node :: "'v ⇒ 'v list_graph ⇒ 'v list_graph" where
"add_node v G = ⦇ nodesL = (if v ∈ set (nodesL G) then nodesL G else v#nodesL G), edgesL=edgesL G ⦈"
text ‹Adds an edge to a graph.›
definition add_edge :: "'v ⇒ 'v ⇒ 'v list_graph ⇒ 'v list_graph" where
"add_edge v v' G = (add_node v (add_node v' G)) ⦇edgesL := (if (v, v') ∈ set (edgesL G) then edgesL G else (v, v')#edgesL G) ⦈"
text ‹Deletes a node from a graph. Also deletes all adjacent edges.›
definition delete_node :: "'v ⇒ 'v list_graph ⇒ 'v list_graph" where
"delete_node v G = ⦇
nodesL = remove1 v (nodesL G), edgesL = [(e1,e2) ← (edgesL G). e1 ≠ v ∧ e2 ≠ v]
⦈"
text ‹Deletes an edge from a graph.›
definition delete_edge :: "'v ⇒ 'v ⇒ 'v list_graph ⇒ 'v list_graph" where
"delete_edge v v' G = ⦇nodesL = nodesL G, edgesL = [(e1,e2) ← edgesL G. e1 ≠ v ∨ e2 ≠ v'] ⦈"
fun delete_edges::"'v list_graph ⇒ ('v × 'v) list ⇒ 'v list_graph" where
"delete_edges G [] = G"|
"delete_edges G ((v,v')#es) = delete_edges (delete_edge v v' G) es"
text ‹extended graph operations›
text ‹Reflexive transitive successors of a node. Or: All reachable nodes for v including v.›
definition succ_rtran :: "'v list_graph ⇒ 'v ⇒ 'v list" where
"succ_rtran G v = rtrancl_list_impl (edgesL G) [v]"
text ‹Transitive successors of a node. Or: All reachable nodes for v.›
definition succ_tran :: "'v list_graph ⇒ 'v ⇒ 'v list" where
"succ_tran G v = trancl_list_impl (edgesL G) [v]"
text ‹The number of reachable nodes from v›
definition num_reachable :: "'v list_graph ⇒ 'v ⇒ nat" where
"num_reachable G v = length (succ_tran G v)"
definition num_reachable_norefl :: "'v list_graph ⇒ 'v ⇒ nat" where
"num_reachable_norefl G v = length ([ x ← succ_tran G v. x ≠ v])"
subsection‹undirected graph simulation›
text ‹Create undirected graph from directed graph by adding backward links›
fun backlinks :: "('v × 'v) list ⇒ ('v × 'v) list" where
"backlinks [] = []" |
"backlinks ((e1, e2)#es) = (e2, e1)#(backlinks es)"
definition undirected :: "'v list_graph ⇒ 'v list_graph"
where "undirected G ≡ ⦇ nodesL = nodesL G, edgesL = remdups (edgesL G @ backlinks (edgesL G)) ⦈"
section‹Correctness lemmata›
lemma add_node_wf: "wf_list_graph G ⟹ wf_list_graph (add_node v G)"
unfolding wf_list_graph_def wf_list_graph_axioms_def add_node_def
by auto
lemma add_node_set_nodes: "set (nodesL (add_node v G)) = set (nodesL G) ∪ {v}"
unfolding add_node_def
by auto
lemma add_node_set_edges: "set (edgesL (add_node v G)) = set (edgesL G)"
unfolding add_node_def
by auto
lemma add_node_correct: "FiniteGraph.add_node v (list_graph_to_graph G) = list_graph_to_graph (add_node v G)"
unfolding FiniteGraph.add_node_def list_graph_to_graph_def
by (simp add: add_node_set_edges add_node_set_nodes)
lemma add_node_wf2: "wf_graph (list_graph_to_graph G) ⟹ wf_graph (list_graph_to_graph (add_node v G))"
by (subst add_node_correct[symmetric]) simp
lemma add_edge_wf: "wf_list_graph G ⟹ wf_list_graph (add_edge v v' G)"
unfolding wf_list_graph_def add_edge_def add_node_def wf_list_graph_axioms_def
by auto
lemma add_edge_set_nodes: "set (nodesL (add_edge v v' G)) = set (nodesL G) ∪ {v,v'}"
unfolding add_edge_def add_node_def
by auto
lemma add_edge_set_edges: "set (edgesL (add_edge v v' G)) = set (edgesL G) ∪ {(v,v')}"
unfolding add_edge_def add_node_def
by auto
lemma add_edge_correct: "FiniteGraph.add_edge v v' (list_graph_to_graph G) = list_graph_to_graph (add_edge v v' G)"
unfolding FiniteGraph.add_edge_def add_edge_def list_graph_to_graph_def
by (auto simp: add_node_set_nodes)
lemma add_edge_wf2: "wf_graph (list_graph_to_graph G) ⟹ wf_graph (list_graph_to_graph (add_edge v v' G))"
by (subst add_edge_correct[symmetric]) simp
lemma delete_node_wf: "wf_list_graph G ⟹ wf_list_graph (delete_node v G)"
unfolding wf_list_graph_def delete_node_def wf_list_graph_axioms_def
by auto
lemma delete_node_set_edges:
"set (edgesL (delete_node v G)) = {(a,b). (a, b) ∈ set (edgesL G) ∧ a ≠ v ∧ b ≠ v}"
unfolding delete_node_def
by auto
lemma delete_node_correct:
assumes "wf_list_graph G"
shows "FiniteGraph.delete_node v (list_graph_to_graph G) = list_graph_to_graph (delete_node v G)"
using assms
unfolding FiniteGraph.delete_node_def delete_node_def list_graph_to_graph_def wf_list_graph_def
by auto
lemma delete_edge_set_nodes: "set (nodesL (delete_edge v v' G)) = set (nodesL G)"
unfolding delete_edge_def
by simp
lemma delete_edge_set_edges:
"set (edgesL (delete_edge v v' G)) = {(a,b). (a,b) ∈ set (edgesL G) ∧ (a,b) ≠ (v,v')}"
unfolding delete_edge_def
by auto
lemma delete_edge_set_edges2:
"set (edgesL (delete_edge v v' G)) = set (edgesL G) - {(v,v')}"
by (auto simp:delete_edge_set_edges)
lemma delete_edge_wf: "wf_list_graph G ⟹ wf_list_graph (delete_edge v v' G)"
unfolding wf_list_graph_def delete_edge_def wf_list_graph_axioms_def
by auto
lemma delete_edge_length: "length (edgesL (delete_edge v v' G)) ≤ length (edgesL G)"
unfolding delete_edge_def
by simp
lemma delete_edge_commute: "delete_edge a1 a2 (delete_edge b1 b2 G) = delete_edge b1 b2 (delete_edge a1 a2 G)"
unfolding delete_edge_def
by simp metis
lemma delete_edge_correct: "FiniteGraph.delete_edge v v' (list_graph_to_graph G) = list_graph_to_graph (delete_edge v v' G)"
unfolding FiniteGraph.delete_edge_def delete_edge_def list_graph_to_graph_def
by auto
lemma delete_edge_wf2: "wf_graph (list_graph_to_graph G) ⟹ wf_graph (list_graph_to_graph (delete_edge v v' G))"
by (subst delete_edge_correct[symmetric]) simp
lemma delete_edges_wf: "wf_list_graph G ⟹ wf_list_graph (delete_edges G E)"
by (induction E arbitrary: G) (auto simp: delete_edge_wf)
lemma delete_edges_set_nodes: "set (nodesL (delete_edges G E)) = set (nodesL G)"
by (induction E arbitrary: G) (auto simp: delete_edge_set_nodes)
lemma delete_edges_nodes: "nodesL (delete_edges G es) = nodesL G"
by (induction es arbitrary: G) (auto simp: delete_edge_def)
lemma delete_edges_set_edges: "set (edgesL (delete_edges G E)) = set (edgesL G) - set E"
by (induction E arbitrary: G) (auto simp: delete_edge_def delete_edge_set_nodes)
lemma delete_edges_set_edges2:
"set (edgesL (delete_edges G E)) = {(a,b). (a,b) ∈ set (edgesL G) ∧ (a,b) ∉ set E}"
by (auto simp: delete_edges_set_edges)
lemma delete_edges_length: "length (edgesL (delete_edges G f)) ≤ length (edgesL G)"
proof (induction f arbitrary:G)
case (Cons f fs)
thus ?case
apply (cases f, hypsubst)
apply (subst delete_edges.simps(2))
apply (metis delete_edge_length le_trans)
done
qed simp
lemma delete_edges_chain: "delete_edges G (as @ bs) = delete_edges (delete_edges G as) bs"
proof (induction as arbitrary: bs G)
case (Cons f fs)
thus ?case
by (cases f) auto
qed simp
lemma delete_edges_delete_edge_commute:
"delete_edges (delete_edge a1 a2 G) as = delete_edge a1 a2 (delete_edges G as)"
proof (induction as arbitrary: G a1 a2)
case (Cons f fs)
thus ?case
by (cases f) (simp add: delete_edge_commute)
qed simp
lemma delete_edges_commute:
"delete_edges (delete_edges G as) bs = delete_edges (delete_edges G bs) as"
proof (induction as arbitrary: bs G)
case (Cons f fs)
thus ?case
by (cases f) (simp add: delete_edges_delete_edge_commute)
qed simp
lemma delete_edges_as_filter:
"delete_edges G l = ⦇ nodesL = nodesL G, edgesL = [x ← edgesL G. x ∉ set l] ⦈"
proof (induction l)
case (Cons f fs)
thus ?case
apply (cases f)
apply (simp add: delete_edges_delete_edge_commute)
apply (simp add: delete_edge_def)
apply (metis (lifting, full_types) prod.exhaust case_prodI split_conv)
done
qed simp
declare delete_edges.simps[simp del]
lemma delete_edges_correct:
"FiniteGraph.delete_edges (list_graph_to_graph G) (set E) = list_graph_to_graph (delete_edges G E)"
unfolding list_graph_to_graph_def FiniteGraph.delete_edges_def
by (auto simp add: delete_edges_as_filter )
lemma delete_edges_wf2:
"wf_graph (list_graph_to_graph G) ⟹ wf_graph (list_graph_to_graph (delete_edges G E))"
by (subst delete_edges_correct[symmetric]) simp
lemma distinct_relpow_impl:
"distinct L ⟹ distinct new ⟹ distinct have ⟹ distinct (new@have) ⟹
distinct (relpow_impl (λas. remdups (map snd [(a, b)←L . a ∈ set as])) (λxs ys. [x←xs . x ∉ set ys] @ ys) (λx xs. x ∈ set xs) new have M)"
proof (induction M arbitrary: "new" "have")
case Suc
hence
"distinct ([x←new . x ∉ set have] @ have)"
"set ([n←remdups (map snd [(a, b)←L . a ∈ set new]) . (n ∈ set new ⟶ n ∈ set have) ∧ n ∉ set have]) ∩ set ([x←new . x ∉ set have] @ have) = {}"
by auto
with Suc show ?case
by auto
qed auto
lemma distinct_rtrancl_list_impl: "distinct L ⟹ distinct ls ⟹ distinct (rtrancl_list_impl L ls)"
unfolding rtrancl_list_impl_def rtrancl_impl_def
by (simp add:distinct_relpow_impl)
lemma distinct_trancl_list_impl: "distinct L ⟹ distinct ls ⟹ distinct (trancl_list_impl L ls)"
unfolding trancl_list_impl_def trancl_impl_def
by (simp add:distinct_relpow_impl)
value "succ_rtran ⦇ nodesL = [1::nat,2,3,4,8,9,10], edgesL = [(1,2), (2,3), (3,4), (8,9),(9,8)] ⦈ 1"
lemma succ_rtran_correct: "FiniteGraph.succ_rtran (list_graph_to_graph G) v = set (succ_rtran G v)"
unfolding FiniteGraph.succ_rtran_def succ_rtran_def list_graph_to_graph_def
by (simp add: rtrancl_list_impl)
lemma distinct_succ_rtran: "wf_list_graph G ⟹ distinct (succ_rtran G v)"
unfolding succ_rtran_def wf_list_graph_def
by (auto intro: distinct_rtrancl_list_impl)
lemma succ_rtran_set: "set (succ_rtran G v) = {e2. (v,e2) ∈ (set (edgesL G))⇧*}"
unfolding succ_rtran_def
by (simp add: rtrancl_list_impl)
lemma distinct_succ_tran: "wf_list_graph G ⟹ distinct (succ_tran G v)"
unfolding succ_tran_def wf_list_graph_def
by (auto intro: distinct_trancl_list_impl)
lemma succ_tran_set: "set (succ_tran G v) = {e2. (v,e2) ∈ (set (edgesL G))⇧+}"
unfolding succ_tran_def
by (simp add: trancl_list_impl)
value "succ_tran ⦇ nodesL = [1::nat,2,3,4,8,9,10], edgesL = [(1,2), (2,3), (3,4), (8,9),(9,8)] ⦈ 1"
lemma succ_tran_correct: "FiniteGraph.succ_tran (list_graph_to_graph G) v = set (succ_tran G v)"
unfolding FiniteGraph.succ_tran_def succ_tran_def list_graph_to_graph_def
by (simp add:trancl_list_impl)
lemma num_reachable_correct:
"wf_list_graph G ⟹ FiniteGraph.num_reachable (list_graph_to_graph G) v = num_reachable G v"
unfolding num_reachable_def FiniteGraph.num_reachable_def
by (metis List.distinct_card distinct_succ_tran succ_tran_correct)
lemma num_reachable_norefl_correct:
"wf_list_graph G ⟹
FiniteGraph.num_reachable_norefl (list_graph_to_graph G) v = num_reachable_norefl G v"
unfolding num_reachable_norefl_def FiniteGraph.num_reachable_norefl_def
by (metis (full_types) List.distinct_card distinct_filter distinct_succ_tran set_minus_filter_out succ_tran_correct)
lemma backlinks_alt: "backlinks E = [(snd e, fst e). e ← E]"
by (induction E) auto
lemma backlinks_set: "set (backlinks E) = {(e2, e1). (e1, e2) ∈ set E}"
by (induction E) auto
lemma undirected_nodes_set: "set (edgesL (undirected G)) = set (edgesL G) ∪ {(e2, e1). (e1, e2) ∈ set (edgesL G)}"
unfolding undirected_def
by (simp add: backlinks_set)
lemma undirected_succ_tran_set: "set (succ_tran (undirected G) v) = {e2. (v,e2) ∈ (set (edgesL (undirected G)))⇧+}"
by (fact succ_tran_set)
lemma backlinks_in_nodes_G: "⟦ fst ` set (edgesL G) ⊆ set (nodesL G); snd ` set (edgesL G) ⊆ set (nodesL G) ⟧ ⟹
fst` set (edgesL (undirected G)) ⊆ set (nodesL (undirected G)) ∧ snd` set (edgesL (undirected G)) ⊆ set (nodesL (undirected G))"
unfolding undirected_def
by(auto simp: backlinks_set)
lemma backlinks_distinct: "distinct E ⟹ distinct (backlinks E)"
by (induction E) (auto simp: backlinks_alt)
lemma backlinks_subset: "set (backlinks X) ⊆ set (backlinks Y) ⟷ set X ⊆ set Y"
by (auto simp: backlinks_set)
lemma backlinks_correct: "FiniteGraph.backflows (set E) = set (backlinks E)"
unfolding backflows_def
by(simp add: backlinks_set)
lemma undirected_wf: "wf_list_graph G ⟹ wf_list_graph (undirected G)"
unfolding wf_list_graph_def wf_list_graph_axioms_def
by (simp add:backlinks_in_nodes_G) (simp add: undirected_def)
lemma undirected_correct:
"FiniteGraph.undirected (list_graph_to_graph G) = list_graph_to_graph (undirected G)"
unfolding FiniteGraph.undirected_def undirected_def list_graph_to_graph_def
by (simp add: backlinks_set)
lemmas wf_list_graph_wf =
add_node_wf
add_edge_wf
delete_node_wf
delete_edge_wf
delete_edges_wf
undirected_wf
lemmas list_graph_correct =
add_node_correct
add_edge_correct
delete_node_correct
delete_edge_correct
delete_edges_correct
succ_rtran_correct
succ_tran_correct
num_reachable_correct
undirected_correct
end