Theory Rooted_Tree
section ‹Rooted Trees›
theory Rooted_Tree
imports Tree_Graph "HOL-Library.FSet"
begin
datatype tree = Node "tree list"
fun tree_size :: "tree ⇒ nat" where
"tree_size (Node ts) = Suc (∑t←ts. tree_size t)"
fun height :: "tree ⇒ nat" where
"height (Node []) = 0"
| "height (Node ts) = Suc (Max (height ` set ts))"
text ‹Convenient case splitting and induction for trees›
lemma tree_cons_exhaust[case_names Nil Cons]:
"(t = Node [] ⟹ P) ⟹ (⋀r ts. t = Node (r # ts) ⟹ P) ⟹ P"
by (cases t) (metis list.exhaust)
lemma tree_rev_exhaust[case_names Nil Snoc]:
"(t = Node [] ⟹ P) ⟹ (⋀ts r. t = Node (ts @ [r]) ⟹ P) ⟹ P"
by (cases t) (metis rev_exhaust)
lemma tree_cons_induct[case_names Nil Cons]:
assumes "P (Node [])"
and "⋀t ts. P t ⟹ P (Node ts) ⟹ P (Node (t#ts))"
shows "P t"
proof (induction "size_tree t" arbitrary: t rule: less_induct)
case less
then show ?case using assms by (cases t rule: tree_cons_exhaust) auto
qed
fun lexord_tree where
"lexord_tree t (Node []) ⟷ False"
| "lexord_tree (Node []) r ⟷ True"
| "lexord_tree (Node (t#ts)) (Node (r#rs)) ⟷ lexord_tree t r ∨ (t = r ∧ lexord_tree (Node ts) (Node rs))"
fun mirror :: "tree ⇒ tree" where
"mirror (Node ts) = Node (map mirror (rev ts))"
instantiation tree :: linorder
begin
definition
tree_less_def: "(t::tree) < r ⟷ lexord_tree (mirror t) (mirror r)"
definition
tree_le_def: "(t :: tree) ≤ r ⟷ t < r ∨ t = r"
lemma lexord_tree_empty2[simp]: "lexord_tree (Node []) r ⟷ r ≠ Node []"
by (cases r rule: tree_cons_exhaust) auto
lemma mirror_empty[simp]: "mirror t = Node [] ⟷ t = Node []"
by (cases t) auto
lemma mirror_not_empty[simp]: "mirror t ≠ Node [] ⟷ t ≠ Node []"
by (cases t) auto
lemma tree_le_empty[simp]: "Node [] ≤ t"
unfolding tree_le_def tree_less_def using mirror_not_empty by auto
lemma tree_less_empty_iff: "Node [] < t ⟷ t ≠ Node []"
unfolding tree_less_def by simp
lemma not_tree_less_empty[simp]: "¬ t < Node []"
unfolding tree_less_def by simp
lemma tree_le_empty2_iff[simp]: "t ≤ Node [] ⟷ t = Node []"
unfolding tree_le_def by simp
lemma lexord_tree_antisym: "lexord_tree t r ⟹ ¬ lexord_tree r t"
by (induction r t rule: lexord_tree.induct) auto
lemma tree_less_antisym: "(t::tree) < r ⟹ ¬ r < t"
unfolding tree_less_def using lexord_tree_antisym by blast
lemma lexord_tree_not_eq: "lexord_tree t r ⟹ t ≠ r"
by (induction r t rule: lexord_tree.induct) auto
lemma tree_less_not_eq: "(t::tree) < r ⟹ t ≠ r"
unfolding tree_less_def using lexord_tree_not_eq by blast
lemma lexord_tree_irrefl: "¬ lexord_tree t t"
using lexord_tree_not_eq by blast
lemma tree_less_irrefl: "¬ (t::tree) < t"
unfolding tree_less_def using lexord_tree_irrefl by blast
lemma lexord_tree_eq_iff: "¬ lexord_tree t r ∧ ¬ lexord_tree r t ⟷ t = r"
using lexord_tree_empty2 by (induction t r rule: lexord_tree.induct, fastforce+)
lemma mirror_mirror: "mirror (mirror t) = t"
by (induction t rule: mirror.induct) (simp add: map_idI rev_map)
lemma mirror_inj: "mirror t = mirror r ⟹ t = r"
using mirror_mirror by metis
lemma tree_less_eq_iff: "¬ (t::tree) < r ∧ ¬ r < t ⟷ t = r"
unfolding tree_less_def using lexord_tree_eq_iff mirror_inj by blast
lemma lexord_tree_trans: "lexord_tree t r ⟹ lexord_tree r s ⟹ lexord_tree t s"
proof (induction t s arbitrary: r rule: lexord_tree.induct)
case (1 t)
then show ?case by auto
next
case (2 va vb)
then show ?case by auto
next
case (3 t ts s ss)
then show ?case by (cases r rule: tree_cons_exhaust) auto
qed
instance
proof
fix t r s :: tree
show "t < r ⟷ t ≤ r ∧ ¬ r ≤ t" unfolding tree_le_def using tree_less_antisym tree_less_irrefl by auto
show "t ≤ t" unfolding tree_le_def by simp
show "t ≤ r ⟹ r ≤ t ⟹ t = r" unfolding tree_le_def using tree_less_antisym by blast
show "t ≤ r ∨ r ≤ t" unfolding tree_le_def using tree_less_eq_iff by blast
show "t ≤ r ⟹ r ≤ s ⟹ t ≤ s" unfolding tree_le_def tree_less_def using lexord_tree_trans by blast
qed
end
lemma tree_size_children: "tree_size (Node ts) = Suc n ⟹ t ∈ set ts ⟹ tree_size t ≤ n"
by (auto simp: le_add1 sum_list_map_remove1)
lemma tree_size_ge_1: "tree_size t ≥ 1"
by (cases t) auto
lemma tree_size_ne_0: "tree_size t ≠ 0"
by (cases t) auto
lemma tree_size_1_iff: "tree_size t = 1 ⟷ t = Node []"
using tree_size_ne_0 by (cases t rule: tree_cons_exhaust) auto
lemma length_children: "tree_size (Node ts) = Suc n ⟹ length ts ≤ n"
by (induction ts arbitrary: n, auto, metis add_mono plus_1_eq_Suc tree_size_ge_1)
lemma height_Node_cons: "height (Node (t#ts)) ≥ Suc (height t)"
by auto
lemma height_0_iff: "height t = 0 ⟹ t = Node []"
using height.elims by blast
lemma height_children: "height (Node ts) = Suc n ⟹ t ∈ set ts ⟹ height t ≤ n"
by (metis List.finite_set Max_ge diff_Suc_1 finite_imageI height.elims imageI nat.simps(3) tree.inject)
lemma height_children_le_height: "∀t ∈ set ts. height t ≤ n ⟹ height (Node ts) ≤ Suc n"
by (cases ts) auto
lemma mirror_iff: "mirror t = Node ts ⟷ t = Node (map mirror (rev ts))"
by (metis mirror.simps mirror_mirror)
lemma mirror_append: "mirror (Node (ts@rs)) = Node (map mirror (rev rs) @ map mirror (rev ts))"
by (induction ts) auto
lemma lexord_tree_snoc: "lexord_tree (Node ts) (Node (ts@[t]))"
by (induction ts) auto
lemma tree_less_cons: "Node ts < Node (t#ts)"
unfolding tree_less_def using lexord_tree_snoc by simp
lemma tree_le_cons: "Node ts ≤ Node (t#ts)"
unfolding tree_le_def using tree_less_cons by simp
lemma tree_less_cons': "t ≤ Node rs ⟹ t < Node (r#rs)"
using tree_less_cons by (simp add: order_le_less_trans)
lemma tree_less_snoc2_iff[simp]: "Node (ts@[t]) < Node (rs@[r]) ⟷ t < r ∨ (t = r ∧ Node ts < Node rs)"
unfolding tree_less_def using mirror_inj by auto
lemma tree_le_snoc2_iff[simp]: "Node (ts@[t]) ≤ Node (rs@[r]) ⟷ t < r ∨ (t = r ∧ Node ts ≤ Node rs)"
unfolding tree_le_def by auto
lemma lexord_tree_cons2[simp]: "lexord_tree (Node (ts@[t])) (Node (ts@[r])) ⟷ lexord_tree t r"
by (induction ts) (auto simp: lexord_tree_irrefl)
lemma tree_less_cons2[simp]: "Node (t#ts) < Node (r#ts) ⟷ t < r"
unfolding tree_less_def using lexord_tree_cons2 by simp
lemma tree_le_cons2[simp]: "Node (t#ts) ≤ Node (r#ts) ⟷ t ≤ r"
unfolding tree_le_def using tree_less_cons2 by blast
lemma tree_less_sorted_snoc: "sorted (ts@[r]) ⟹ Node ts < Node (ts@[r])"
unfolding tree_less_def by (induction ts rule: rev_induct, auto,
metis leD lexord_tree_eq_iff sorted2 sorted_wrt_append tree_less_def,
metis dual_order.strict_iff_not list.set_intros(2) nle_le sorted2 sorted_append tree_less_def)
lemma lexord_tree_comm_prefix[simp]: "lexord_tree (Node (ss@ts)) (Node (ss@rs)) ⟷ lexord_tree (Node ts) (Node rs)"
using lexord_tree_antisym by (induction ss) auto
lemma less_tree_comm_suffix[simp]: "Node (ts@ss) < Node (rs@ss) ⟷ Node ts < Node rs"
unfolding tree_less_def by simp
lemma tree_le_comm_suffix[simp]: "Node (ts@ss) ≤ Node (rs@ss) ⟷ Node ts ≤ Node rs"
unfolding tree_le_def by simp
lemma tree_less_comm_suffix2: "t < r ⟹ Node (ts@t#ss) < Node (r#ss)"
unfolding tree_less_def using lexord_tree_comm_prefix by simp
lemma lexord_tree_append[simp]: "lexord_tree (Node ts) (Node (ts@rs)) ⟷ rs ≠ []"
using lexord_tree_irrefl by (induction ts) auto
lemma tree_less_append[simp]: "Node ts < Node (rs@ts) ⟷ rs ≠ []"
unfolding tree_less_def by simp
lemma tree_le_append: "Node ts ≤ Node (ss@ts)"
unfolding tree_le_def by simp
lemma tree_less_singleton_iff[simp]: "Node (ts@[t]) < Node [r] ⟷ t < r"
unfolding tree_less_def by simp
lemma tree_le_singleton_iff[simp]: "Node (ts@[t]) ≤ Node [r] ⟷ t < r ∨ (t = r ∧ ts = [])"
unfolding tree_le_def by auto
lemma lexord_tree_nested: "lexord_tree t (Node [t])"
proof (induction t rule: tree_cons_induct)
case Nil
then show ?case by auto
next
case (Cons t ts)
then show ?case by (cases t rule: tree_cons_exhaust) auto
qed
lemma tree_less_nested: "t < Node [t]"
unfolding tree_less_def using lexord_tree_nested by auto
lemma tree_le_nested: "t ≤ Node [t]"
unfolding tree_le_def using tree_less_nested by auto
lemma lexord_tree_iff:
"lexord_tree t r ⟷ (∃ts t' ss rs r'. t = Node (ss @ t' # ts) ∧ r = Node (ss @ r' # rs) ∧ lexord_tree t' r') ∨ (∃ts rs. rs ≠ [] ∧ t = Node ts ∧ r = Node (ts @ rs))" (is "?l ⟷ ?r")
proof
show "?l ⟹ ?r"
proof-
assume lexord: "lexord_tree t r"
obtain ts where ts: "t = Node ts" by (cases t) auto
obtain rs where rs: "r = Node rs" by (cases r) auto
obtain ss ts' rs' where prefix: "ts = ss @ ts' ∧ rs = ss @ rs' ∧ (ts' = [] ∨ rs' = [] ∨ hd ts' ≠ hd rs')" using longest_common_prefix by blast
then have "ts' = [] ∨ lexord_tree (hd ts') (hd rs')" using lexord unfolding ts rs
by (auto, metis lexord_tree.simps(1) lexord_tree.simps(3) list.exhaust_sel)
then show ?thesis using prefix
by (metis append.right_neutral lexord lexord_tree.simps(1) lexord_tree_comm_prefix list.exhaust_sel rs ts)
qed
show "?r ⟹ ?l" by auto
qed
lemma tree_less_iff: "t < r ⟷ (∃ts t' ss rs r'. t = Node (ts @ t' # ss) ∧ r = Node (rs @ r' # ss) ∧ t' < r') ∨ (∃ts rs. rs ≠ [] ∧ t = Node ts ∧ r = Node (rs @ ts))" (is "?l ⟷ ?r")
proof
show "?l ⟹ ?r"
unfolding tree_less_def using lexord_tree_iff[of "mirror t" "mirror r", unfolded mirror_iff]
by (simp, metis append_Nil lexord_tree_eq_iff mirror_mirror)
next
show "?r ⟹ ?l"
by (auto simp: order_le_neq_trans tree_le_append,
meson dual_order.strict_trans1 tree_le_append tree_less_comm_suffix2)
qed
lemma tree_empty_cons_lt_le: "r < Node (Node [] # ts) ⟹ r ≤ Node ts"
proof (induction ts arbitrary: r rule: rev_induct)
case Nil
then show ?case by (cases r rule: tree_rev_exhaust) auto
next
case (snoc x xs)
then show ?case
proof (cases r rule: tree_rev_exhaust)
case Nil
then show ?thesis by auto
next
case (Snoc rs r1)
then show ?thesis using snoc by (auto, (metis append_Cons tree_less_snoc2_iff)+)
qed
qed
fun regular :: "tree ⇒ bool" where
"regular (Node ts) ⟷ sorted ts ∧ (∀t∈set ts. regular t)"
definition n_trees :: "nat ⇒ tree set" where
"n_trees n = {t. tree_size t = n}"
definition regular_n_trees :: "nat ⇒ tree set" where
"regular_n_trees n = {t. tree_size t = n ∧ regular t}"
subsection ‹Rooted Graphs›
type_synonym 'a rpregraph = "('a set) × ('a edge set) × 'a"
locale rgraph = graph_system +
fixes r
assumes root_wf: "r ∈ V"
locale rtree = tree + rgraph
begin
definition subtrees :: "'a rpregraph set" where
"subtrees =
(let (V',E') = remove_vertex r
in (λC. (C, graph_system.induced_edges E' C, THE r'. r' ∈ C ∧ vert_adj r r')) ` ulgraph.connected_components V' E')"
lemma rtree_subtree:
assumes subtree: "(S,E⇩S,r⇩S) ∈ subtrees"
shows "rtree S E⇩S r⇩S"
proof-
obtain V' E' where remove_vertex: "remove_vertex r = (V', E')" by fastforce
interpret subg: ulsubgraph V' E' V E unfolding ulsubgraph_def using subgraph_remove_vertex subtree ulgraph_axioms remove_vertex by blast
interpret g': fin_ulgraph V' E'
by (simp add: fin_graph_system_axioms fin_ulgraph_def subg.is_finite_subgraph subg.is_subgraph_ulgraph ulgraph_axioms)
have conn_component: "S ∈ g'.connected_components" using subtree remove_vertex unfolding subtrees_def by auto
then interpret subg': subgraph S E⇩S V' E' using g'.connected_component_subgraph subtree remove_vertex unfolding subtrees_def by auto
interpret subg': ulsubgraph S E⇩S V' E' by unfold_locales
interpret S: connected_ulgraph S E⇩S using g'.connected_components_connected_ulgraphs conn_component subtree remove_vertex unfolding subtrees_def by auto
interpret S: fin_connected_ulgraph S E⇩S using subg'.verts_ss g'.finV by unfold_locales (simp add: finite_subset)
interpret S: tree S E⇩S using subg.is_cycle2 subg'.is_cycle2 no_cycles by (unfold_locales, blast)
show ?thesis using theI'[OF unique_adj_vert_removed[OF root_wf remove_vertex conn_component]]
subtree remove_vertex by unfold_locales (auto simp: subtrees_def)
qed
lemma finite_subtrees: "finite subtrees"
proof-
obtain V' E' where remove_vertex: "remove_vertex r = (V', E')" by fastforce
then interpret subg: subgraph V' E' V E using subgraph_remove_vertex by auto
interpret g': fin_ulgraph V' E'
by (simp add: fin_graph_system_axioms fin_ulgraph_def subg.is_finite_subgraph subg.is_subgraph_ulgraph ulgraph_axioms)
show ?thesis using g'.finite_connected_components remove_vertex unfolding subtrees_def by simp
qed
lemma remove_root_subtrees:
assumes remove_vertex: "remove_vertex r = (V',E')"
and conn_component: "C ∈ ulgraph.connected_components V' E'"
shows "rtree C (graph_system.induced_edges E' C) (THE r'. r' ∈ C ∧ vert_adj r r')"
proof-
interpret subg: ulsubgraph V' E' V E unfolding ulsubgraph_def using subgraph_remove_vertex remove_vertex ulgraph_axioms by blast
interpret g': fin_ulgraph V' E'
by (simp add: fin_graph_system_axioms fin_ulgraph_def subg.is_finite_subgraph subg.is_subgraph_ulgraph ulgraph_axioms)
interpret subg': ulsubgraph C "graph_system.induced_edges E' C" V' E'
by (simp add: conn_component g'.connected_component_subgraph g'.ulgraph_axioms ulsubgraph.intro)
interpret C: fin_connected_ulgraph C "graph_system.induced_edges E' C"
by (simp add: fin_connected_ulgraph.intro fin_ulgraph.intro g'.fin_graph_system_axioms
g'.ulgraph_axioms subg'.is_finite_subgraph subg'.is_subgraph_ulgraph conn_component
g'.connected_components_connected_ulgraphs)
interpret C: tree C "graph_system.induced_edges E' C" using subg.is_cycle2 subg'.is_cycle2 no_cycles by (unfold_locales, blast)
show ?thesis using theI'[OF unique_adj_vert_removed[OF root_wf remove_vertex conn_component]] by unfold_locales simp
qed
end
subsection ‹Rooted Graph Isomorphism›
fun app_rgraph_isomorphism :: "('a ⇒ 'b) ⇒ 'a rpregraph ⇒ 'b rpregraph" where
"app_rgraph_isomorphism f (V,E,r) = (f ` V, ((`) f) ` E, f r)"
locale rgraph_isomorphism =
G: rgraph V⇩G E⇩G r⇩G + graph_isomorphism V⇩G E⇩G V⇩H E⇩H f for V⇩G E⇩G r⇩G V⇩H E⇩H r⇩H f +
assumes root_preserving: "f r⇩G = r⇩H"
begin
interpretation H: graph_system V⇩H E⇩H using graph_system_H .
lemma rgraph_H: "rgraph V⇩H E⇩H r⇩H"
using root_preserving bij_f G.root_wf V⇩H_def by unfold_locales blast
interpretation H: rgraph V⇩H E⇩H r⇩H using rgraph_H .
lemma rgraph_isomorphism_inv: "rgraph_isomorphism V⇩H E⇩H r⇩H V⇩G E⇩G r⇩G inv_iso"
proof-
interpret iso: graph_isomorphism V⇩H E⇩H V⇩G E⇩G inv_iso using graph_isomorphism_inv .
show ?thesis using G.root_wf inj_f inv_iso_def root_preserving the_inv_into_f_f
by unfold_locales fastforce
qed
end
fun rgraph_isomorph :: "'a rpregraph ⇒ 'b rpregraph ⇒ bool" (infix ‹≃⇩r› 50) where
"(V⇩G,E⇩G,r⇩G) ≃⇩r (V⇩H,E⇩H,r⇩H) ⟷ (∃f. rgraph_isomorphism V⇩G E⇩G r⇩G V⇩H E⇩H r⇩H f)"
lemma (in rgraph) rgraph_isomorphism_id: "rgraph_isomorphism V E r V E r id"
using graph_isomorphism_id rgraph_isomorphism.intro rgraph_axioms
unfolding rgraph_isomorphism_axioms_def by fastforce
lemma (in rgraph) rgraph_isomorph_refl: "(V,E,r) ≃⇩r (V,E,r)"
using rgraph_isomorphism_id by auto
lemma rgraph_isomorph_sym: "G ≃⇩r H ⟹ H ≃⇩r G"
using rgraph_isomorphism.rgraph_isomorphism_inv by (cases G, cases H) fastforce
lemma rgraph_isomorphism_trans: "rgraph_isomorphism V⇩G E⇩G r⇩G V⇩H E⇩H r⇩H f ⟹ rgraph_isomorphism V⇩H E⇩H r⇩H V⇩F E⇩F r⇩F g ⟹ rgraph_isomorphism V⇩G E⇩G r⇩G V⇩F E⇩F r⇩F (g o f)"
using graph_isomorphism_trans unfolding rgraph_isomorphism_def rgraph_isomorphism_axioms_def by fastforce
lemma rgraph_isomorph_trans: "transp (≃⇩r)"
using rgraph_isomorphism_trans unfolding transp_def by fastforce
lemma (in rtree) rgraph_isomorphis_app_iso: "inj_on f V ⟹ app_rgraph_isomorphism f (V,E,r) = (V',E',r') ⟹ rgraph_isomorphism V E r V' E' r' f"
by unfold_locales (auto simp: bij_betw_def)
lemma (in rtree) rgraph_isomorph_app_iso: "inj_on f V ⟹ (V, E, r) ≃⇩r app_rgraph_isomorphism f (V, E, r)"
using rgraph_isomorphis_app_iso by fastforce
subsection ‹Conversion between unlabeled, ordered, rooted trees and tree graphs›