diff --git a/src/HOL/Data_Structures/Interval_Tree.thy b/src/HOL/Data_Structures/Interval_Tree.thy --- a/src/HOL/Data_Structures/Interval_Tree.thy +++ b/src/HOL/Data_Structures/Interval_Tree.thy @@ -1,298 +1,298 @@ (* Author: Bohua Zhan, with modifications by Tobias Nipkow *) section \Interval Trees\ theory Interval_Tree imports "HOL-Data_Structures.Cmp" "HOL-Data_Structures.List_Ins_Del" "HOL-Data_Structures.Isin2" "HOL-Data_Structures.Set_Specs" begin subsection \Intervals\ text \The following definition of intervals uses the \<^bold>\typedef\ command to define the type of non-empty intervals as a subset of the type of pairs \p\ where @{prop "fst p \ snd p"}:\ typedef (overloaded) 'a::linorder ivl = "{p :: 'a \ 'a. fst p \ snd p}" by auto text \More precisely, @{typ "'a ivl"} is isomorphic with that subset via the function @{const Rep_ivl}. Hence the basic interval properties are not immediate but need simple proofs:\ definition low :: "'a::linorder ivl \ 'a" where "low p = fst (Rep_ivl p)" definition high :: "'a::linorder ivl \ 'a" where "high p = snd (Rep_ivl p)" lemma ivl_is_interval: "low p \ high p" by (metis Rep_ivl high_def low_def mem_Collect_eq) lemma ivl_inj: "low p = low q \ high p = high q \ p = q" by (metis Rep_ivl_inverse high_def low_def prod_eqI) text \Now we can forget how exactly intervals were defined.\ instantiation ivl :: (linorder) linorder begin definition ivl_less: "(x < y) = (low x < low y | (low x = low y \ high x < high y))" definition ivl_less_eq: "(x \ y) = (low x < low y | (low x = low y \ high x \ high y))" instance proof fix x y z :: "'a ivl" show a: "(x < y) = (x \ y \ \ y \ x)" using ivl_less ivl_less_eq by force show b: "x \ x" by (simp add: ivl_less_eq) show c: "x \ y \ y \ z \ x \ z" by (smt ivl_less_eq dual_order.trans less_trans) show d: "x \ y \ y \ x \ x = y" using ivl_less_eq a ivl_inj ivl_less by fastforce show e: "x \ y \ y \ x" by (meson ivl_less_eq leI not_less_iff_gr_or_eq) qed end definition overlap :: "('a::linorder) ivl \ 'a ivl \ bool" where "overlap x y \ (high x \ low y \ high y \ low x)" definition has_overlap :: "('a::linorder) ivl set \ 'a ivl \ bool" where "has_overlap S y \ (\x\S. overlap x y)" subsection \Interval Trees\ type_synonym 'a ivl_tree = "('a ivl * 'a) tree" fun max_hi :: "('a::order_bot) ivl_tree \ 'a" where "max_hi Leaf = bot" | "max_hi (Node _ (_,m) _) = m" definition max3 :: "('a::linorder) ivl \ 'a \ 'a \ 'a" where "max3 a m n = max (high a) (max m n)" fun inv_max_hi :: "('a::{linorder,order_bot}) ivl_tree \ bool" where "inv_max_hi Leaf \ True" | -"inv_max_hi (Node l (a, m) r) \ (inv_max_hi l \ inv_max_hi r \ m = max3 a (max_hi l) (max_hi r))" +"inv_max_hi (Node l (a, m) r) \ (m = max3 a (max_hi l) (max_hi r) \ inv_max_hi l \ inv_max_hi r)" lemma max_hi_is_max: "inv_max_hi t \ a \ set_tree t \ high a \ max_hi t" by (induct t, auto simp add: max3_def max_def) lemma max_hi_exists: "inv_max_hi t \ t \ Leaf \ \a\set_tree t. high a = max_hi t" proof (induction t rule: tree2_induct) case Leaf then show ?case by auto next case N: (Node l v m r) then show ?case proof (cases l rule: tree2_cases) case Leaf then show ?thesis using N.prems(1) N.IH(2) by (cases r, auto simp add: max3_def max_def le_bot) next case Nl: Node then show ?thesis proof (cases r rule: tree2_cases) case Leaf then show ?thesis using N.prems(1) N.IH(1) Nl by (auto simp add: max3_def max_def le_bot) next case Nr: Node obtain p1 where p1: "p1 \ set_tree l" "high p1 = max_hi l" using N.IH(1) N.prems(1) Nl by auto obtain p2 where p2: "p2 \ set_tree r" "high p2 = max_hi r" using N.IH(2) N.prems(1) Nr by auto then show ?thesis using p1 p2 N.prems(1) by (auto simp add: max3_def max_def) qed qed qed subsection \Insertion and Deletion\ definition node where [simp]: "node l a r = Node l (a, max3 a (max_hi l) (max_hi r)) r" fun insert :: "'a::{linorder,order_bot} ivl \ 'a ivl_tree \ 'a ivl_tree" where "insert x Leaf = Node Leaf (x, high x) Leaf" | "insert x (Node l (a, m) r) = (case cmp x a of EQ \ Node l (a, m) r | LT \ node (insert x l) a r | GT \ node l a (insert x r))" lemma inorder_insert: "sorted (inorder t) \ inorder (insert x t) = ins_list x (inorder t)" by (induct t rule: tree2_induct) (auto simp: ins_list_simps) lemma inv_max_hi_insert: "inv_max_hi t \ inv_max_hi (insert x t)" by (induct t rule: tree2_induct) (auto simp add: max3_def) fun split_min :: "'a::{linorder,order_bot} ivl_tree \ 'a ivl \ 'a ivl_tree" where "split_min (Node l (a, m) r) = (if l = Leaf then (a, r) else let (x,l') = split_min l in (x, node l' a r))" fun delete :: "'a::{linorder,order_bot} ivl \ 'a ivl_tree \ 'a ivl_tree" where "delete x Leaf = Leaf" | "delete x (Node l (a, m) r) = (case cmp x a of LT \ node (delete x l) a r | GT \ node l a (delete x r) | EQ \ if r = Leaf then l else let (a', r') = split_min r in node l a' r')" lemma split_minD: "split_min t = (x,t') \ t \ Leaf \ x # inorder t' = inorder t" by (induct t arbitrary: t' rule: split_min.induct) (auto simp: sorted_lems split: prod.splits if_splits) lemma inorder_delete: "sorted (inorder t) \ inorder (delete x t) = del_list x (inorder t)" by (induct t) (auto simp: del_list_simps split_minD Let_def split: prod.splits) lemma inv_max_hi_split_min: "\ t \ Leaf; inv_max_hi t \ \ inv_max_hi (snd (split_min t))" by (induct t) (auto split: prod.splits) lemma inv_max_hi_delete: "inv_max_hi t \ inv_max_hi (delete x t)" apply (induct t) apply simp using inv_max_hi_split_min by (fastforce simp add: Let_def split: prod.splits) subsection \Search\ text \Does interval \x\ overlap with any interval in the tree?\ fun search :: "'a::{linorder,order_bot} ivl_tree \ 'a ivl \ bool" where "search Leaf x = False" | "search (Node l (a, m) r) x = (if overlap x a then True else if l \ Leaf \ max_hi l \ low x then search l x else search r x)" lemma search_correct: "inv_max_hi t \ sorted (inorder t) \ search t x = has_overlap (set_tree t) x" proof (induction t rule: tree2_induct) case Leaf then show ?case by (auto simp add: has_overlap_def) next case (Node l a m r) have search_l: "search l x = has_overlap (set_tree l) x" using Node.IH(1) Node.prems by (auto simp: sorted_wrt_append) have search_r: "search r x = has_overlap (set_tree r) x" using Node.IH(2) Node.prems by (auto simp: sorted_wrt_append) show ?case proof (cases "overlap a x") case True thus ?thesis by (auto simp: overlap_def has_overlap_def) next case a_disjoint: False then show ?thesis proof cases assume [simp]: "l = Leaf" have search_eval: "search (Node l (a, m) r) x = search r x" using a_disjoint overlap_def by auto show ?thesis unfolding search_eval search_r by (auto simp add: has_overlap_def a_disjoint) next assume "l \ Leaf" then show ?thesis proof (cases "max_hi l \ low x") case max_hi_l_ge: True have "inv_max_hi l" using Node.prems(1) by auto then obtain p where p: "p \ set_tree l" "high p = max_hi l" using \l \ Leaf\ max_hi_exists by auto have search_eval: "search (Node l (a, m) r) x = search l x" using a_disjoint \l \ Leaf\ max_hi_l_ge by (auto simp: overlap_def) show ?thesis proof (cases "low p \ high x") case True have "overlap p x" unfolding overlap_def using True p(2) max_hi_l_ge by auto then show ?thesis unfolding search_eval search_l using p(1) by(auto simp: has_overlap_def overlap_def) next case False have "\overlap x rp" if asm: "rp \ set_tree r" for rp proof - have "low p \ low rp" using asm p(1) Node(4) by(fastforce simp: sorted_wrt_append ivl_less) then show ?thesis using False by (auto simp: overlap_def) qed then show ?thesis unfolding search_eval search_l using a_disjoint by (auto simp: has_overlap_def overlap_def) qed next case False have search_eval: "search (Node l (a, m) r) x = search r x" using a_disjoint False by (auto simp: overlap_def) have "\overlap x lp" if asm: "lp \ set_tree l" for lp using asm False Node.prems(1) max_hi_is_max by (fastforce simp: overlap_def) then show ?thesis unfolding search_eval search_r using a_disjoint by (auto simp: has_overlap_def overlap_def) qed qed qed qed definition empty :: "'a ivl_tree" where "empty = Leaf" subsection \Specification\ locale Interval_Set = Set + fixes has_overlap :: "'t \ 'a::linorder ivl \ bool" assumes set_overlap: "invar s \ has_overlap s x = Interval_Tree.has_overlap (set s) x" interpretation S: Interval_Set where empty = Leaf and insert = insert and delete = delete and has_overlap = search and isin = isin and set = set_tree and invar = "\t. inv_max_hi t \ sorted (inorder t)" proof (standard, goal_cases) case 1 then show ?case by auto next case 2 then show ?case by (simp add: isin_set_inorder) next case 3 then show ?case by(simp add: inorder_insert set_ins_list flip: set_inorder) next case 4 then show ?case by(simp add: inorder_delete set_del_list flip: set_inorder) next case 5 then show ?case by auto next case 6 then show ?case by (simp add: inorder_insert inv_max_hi_insert sorted_ins_list) next case 7 then show ?case by (simp add: inorder_delete inv_max_hi_delete sorted_del_list) next case 8 then show ?case by (simp add: search_correct) qed end diff --git a/src/HOL/Data_Structures/RBT_Set.thy b/src/HOL/Data_Structures/RBT_Set.thy --- a/src/HOL/Data_Structures/RBT_Set.thy +++ b/src/HOL/Data_Structures/RBT_Set.thy @@ -1,322 +1,322 @@ (* Author: Tobias Nipkow *) section \Red-Black Tree Implementation of Sets\ theory RBT_Set imports Complex_Main RBT Cmp Isin2 begin definition empty :: "'a rbt" where "empty = Leaf" fun ins :: "'a::linorder \ 'a rbt \ 'a rbt" where "ins x Leaf = R Leaf x Leaf" | "ins x (B l a r) = (case cmp x a of LT \ baliL (ins x l) a r | GT \ baliR l a (ins x r) | EQ \ B l a r)" | "ins x (R l a r) = (case cmp x a of LT \ R (ins x l) a r | GT \ R l a (ins x r) | EQ \ R l a r)" definition insert :: "'a::linorder \ 'a rbt \ 'a rbt" where "insert x t = paint Black (ins x t)" fun color :: "'a rbt \ color" where "color Leaf = Black" | "color (Node _ (_, c) _) = c" fun del :: "'a::linorder \ 'a rbt \ 'a rbt" where "del x Leaf = Leaf" | "del x (Node l (a, _) r) = (case cmp x a of LT \ if l \ Leaf \ color l = Black then baldL (del x l) a r else R (del x l) a r | GT \ if r \ Leaf\ color r = Black then baldR l a (del x r) else R l a (del x r) | EQ \ join l r)" definition delete :: "'a::linorder \ 'a rbt \ 'a rbt" where "delete x t = paint Black (del x t)" subsection "Functional Correctness Proofs" lemma inorder_paint: "inorder(paint c t) = inorder t" by(cases t) (auto) lemma inorder_baliL: "inorder(baliL l a r) = inorder l @ a # inorder r" by(cases "(l,a,r)" rule: baliL.cases) (auto) lemma inorder_baliR: "inorder(baliR l a r) = inorder l @ a # inorder r" by(cases "(l,a,r)" rule: baliR.cases) (auto) lemma inorder_ins: "sorted(inorder t) \ inorder(ins x t) = ins_list x (inorder t)" by(induction x t rule: ins.induct) (auto simp: ins_list_simps inorder_baliL inorder_baliR) lemma inorder_insert: "sorted(inorder t) \ inorder(insert x t) = ins_list x (inorder t)" by (simp add: insert_def inorder_ins inorder_paint) lemma inorder_baldL: "inorder(baldL l a r) = inorder l @ a # inorder r" by(cases "(l,a,r)" rule: baldL.cases) (auto simp: inorder_baliL inorder_baliR inorder_paint) lemma inorder_baldR: "inorder(baldR l a r) = inorder l @ a # inorder r" by(cases "(l,a,r)" rule: baldR.cases) (auto simp: inorder_baliL inorder_baliR inorder_paint) lemma inorder_join: "inorder(join l r) = inorder l @ inorder r" by(induction l r rule: join.induct) (auto simp: inorder_baldL inorder_baldR split: tree.split color.split) lemma inorder_del: "sorted(inorder t) \ inorder(del x t) = del_list x (inorder t)" by(induction x t rule: del.induct) (auto simp: del_list_simps inorder_join inorder_baldL inorder_baldR) lemma inorder_delete: "sorted(inorder t) \ inorder(delete x t) = del_list x (inorder t)" by (auto simp: delete_def inorder_del inorder_paint) subsection \Structural invariants\ lemma neq_Black[simp]: "(c \ Black) = (c = Red)" by (cases c) auto text\The proofs are due to Markus Reiter and Alexander Krauss.\ fun bheight :: "'a rbt \ nat" where "bheight Leaf = 0" | "bheight (Node l (x, c) r) = (if c = Black then bheight l + 1 else bheight l)" fun invc :: "'a rbt \ bool" where "invc Leaf = True" | "invc (Node l (a,c) r) = - (invc l \ invc r \ (c = Red \ color l = Black \ color r = Black))" + ((c = Red \ color l = Black \ color r = Black) \ invc l \ invc r)" text \Weaker version:\ abbreviation invc2 :: "'a rbt \ bool" where "invc2 t \ invc(paint Black t)" fun invh :: "'a rbt \ bool" where "invh Leaf = True" | -"invh (Node l (x, c) r) = (invh l \ invh r \ bheight l = bheight r)" +"invh (Node l (x, c) r) = (bheight l = bheight r \ invh l \ invh r)" lemma invc2I: "invc t \ invc2 t" by (cases t rule: tree2_cases) simp+ definition rbt :: "'a rbt \ bool" where "rbt t = (invc t \ invh t \ color t = Black)" lemma color_paint_Black: "color (paint Black t) = Black" by (cases t) auto lemma paint2: "paint c2 (paint c1 t) = paint c2 t" by (cases t) auto lemma invh_paint: "invh t \ invh (paint c t)" by (cases t) auto lemma invc_baliL: "\invc2 l; invc r\ \ invc (baliL l a r)" by (induct l a r rule: baliL.induct) auto lemma invc_baliR: "\invc l; invc2 r\ \ invc (baliR l a r)" by (induct l a r rule: baliR.induct) auto lemma bheight_baliL: "bheight l = bheight r \ bheight (baliL l a r) = Suc (bheight l)" by (induct l a r rule: baliL.induct) auto lemma bheight_baliR: "bheight l = bheight r \ bheight (baliR l a r) = Suc (bheight l)" by (induct l a r rule: baliR.induct) auto lemma invh_baliL: "\ invh l; invh r; bheight l = bheight r \ \ invh (baliL l a r)" by (induct l a r rule: baliL.induct) auto lemma invh_baliR: "\ invh l; invh r; bheight l = bheight r \ \ invh (baliR l a r)" by (induct l a r rule: baliR.induct) auto text \All in one:\ lemma inv_baliR: "\ invh l; invh r; invc l; invc2 r; bheight l = bheight r \ \ invc (baliR l a r) \ invh (baliR l a r) \ bheight (baliR l a r) = Suc (bheight l)" by (induct l a r rule: baliR.induct) auto lemma inv_baliL: "\ invh l; invh r; invc2 l; invc r; bheight l = bheight r \ \ invc (baliL l a r) \ invh (baliL l a r) \ bheight (baliL l a r) = Suc (bheight l)" by (induct l a r rule: baliL.induct) auto subsubsection \Insertion\ lemma invc_ins: "invc t \ invc2 (ins x t) \ (color t = Black \ invc (ins x t))" by (induct x t rule: ins.induct) (auto simp: invc_baliL invc_baliR invc2I) lemma invh_ins: "invh t \ invh (ins x t) \ bheight (ins x t) = bheight t" by(induct x t rule: ins.induct) (auto simp: invh_baliL invh_baliR bheight_baliL bheight_baliR) theorem rbt_insert: "rbt t \ rbt (insert x t)" by (simp add: invc_ins invh_ins color_paint_Black invh_paint rbt_def insert_def) text \All in one:\ lemma inv_ins: "\ invc t; invh t \ \ invc2 (ins x t) \ (color t = Black \ invc (ins x t)) \ invh(ins x t) \ bheight (ins x t) = bheight t" by (induct x t rule: ins.induct) (auto simp: inv_baliL inv_baliR invc2I) theorem rbt_insert2: "rbt t \ rbt (insert x t)" by (simp add: inv_ins color_paint_Black invh_paint rbt_def insert_def) subsubsection \Deletion\ lemma bheight_paint_Red: "color t = Black \ bheight (paint Red t) = bheight t - 1" by (cases t) auto lemma invh_baldL_invc: "\ invh l; invh r; bheight l + 1 = bheight r; invc r \ \ invh (baldL l a r) \ bheight (baldL l a r) = bheight r" by (induct l a r rule: baldL.induct) (auto simp: invh_baliR invh_paint bheight_baliR bheight_paint_Red) lemma invh_baldL_Black: "\ invh l; invh r; bheight l + 1 = bheight r; color r = Black \ \ invh (baldL l a r) \ bheight (baldL l a r) = bheight r" by (induct l a r rule: baldL.induct) (auto simp add: invh_baliR bheight_baliR) lemma invc_baldL: "\invc2 l; invc r; color r = Black\ \ invc (baldL l a r)" by (induct l a r rule: baldL.induct) (simp_all add: invc_baliR) lemma invc2_baldL: "\ invc2 l; invc r \ \ invc2 (baldL l a r)" by (induct l a r rule: baldL.induct) (auto simp: invc_baliR paint2 invc2I) lemma invh_baldR_invc: "\ invh l; invh r; bheight l = bheight r + 1; invc l \ \ invh (baldR l a r) \ bheight (baldR l a r) = bheight l" by(induct l a r rule: baldR.induct) (auto simp: invh_baliL bheight_baliL invh_paint bheight_paint_Red) lemma invc_baldR: "\invc l; invc2 r; color l = Black\ \ invc (baldR l a r)" by (induct l a r rule: baldR.induct) (simp_all add: invc_baliL) lemma invc2_baldR: "\ invc l; invc2 r \ \invc2 (baldR l a r)" by (induct l a r rule: baldR.induct) (auto simp: invc_baliL paint2 invc2I) lemma invh_join: "\ invh l; invh r; bheight l = bheight r \ \ invh (join l r) \ bheight (join l r) = bheight l" by (induct l r rule: join.induct) (auto simp: invh_baldL_Black split: tree.splits color.splits) lemma invc_join: "\ invc l; invc r \ \ (color l = Black \ color r = Black \ invc (join l r)) \ invc2 (join l r)" by (induct l r rule: join.induct) (auto simp: invc_baldL invc2I split: tree.splits color.splits) text \All in one:\ lemma inv_baldL: "\ invh l; invh r; bheight l + 1 = bheight r; invc2 l; invc r \ \ invh (baldL l a r) \ bheight (baldL l a r) = bheight r \ invc2 (baldL l a r) \ (color r = Black \ invc (baldL l a r))" by (induct l a r rule: baldL.induct) (auto simp: inv_baliR invh_paint bheight_baliR bheight_paint_Red paint2 invc2I) lemma inv_baldR: "\ invh l; invh r; bheight l = bheight r + 1; invc l; invc2 r \ \ invh (baldR l a r) \ bheight (baldR l a r) = bheight l \ invc2 (baldR l a r) \ (color l = Black \ invc (baldR l a r))" by (induct l a r rule: baldR.induct) (auto simp: inv_baliL invh_paint bheight_baliL bheight_paint_Red paint2 invc2I) lemma inv_join: "\ invh l; invh r; bheight l = bheight r; invc l; invc r \ \ invh (join l r) \ bheight (join l r) = bheight l \ invc2 (join l r) \ (color l = Black \ color r = Black \ invc (join l r))" by (induct l r rule: join.induct) (auto simp: invh_baldL_Black inv_baldL invc2I split: tree.splits color.splits) lemma neq_LeafD: "t \ Leaf \ \l x c r. t = Node l (x,c) r" by(cases t rule: tree2_cases) auto lemma inv_del: "\ invh t; invc t \ \ invh (del x t) \ (color t = Red \ bheight (del x t) = bheight t \ invc (del x t) \ color t = Black \ bheight (del x t) = bheight t - 1 \ invc2 (del x t))" by(induct x t rule: del.induct) (auto simp: inv_baldL inv_baldR inv_join dest!: neq_LeafD) theorem rbt_delete: "rbt t \ rbt (delete x t)" by (metis delete_def rbt_def color_paint_Black inv_del invc2I invh_paint) text \Overall correctness:\ interpretation S: Set_by_Ordered where empty = empty and isin = isin and insert = insert and delete = delete and inorder = inorder and inv = rbt proof (standard, goal_cases) case 1 show ?case by (simp add: empty_def) next case 2 thus ?case by(simp add: isin_set_inorder) next case 3 thus ?case by(simp add: inorder_insert) next case 4 thus ?case by(simp add: inorder_delete) next case 5 thus ?case by (simp add: rbt_def empty_def) next case 6 thus ?case by (simp add: rbt_insert) next case 7 thus ?case by (simp add: rbt_delete) qed subsection \Height-Size Relation\ lemma rbt_height_bheight_if: "invc t \ invh t \ height t \ 2 * bheight t + (if color t = Black then 0 else 1)" by(induction t) (auto split: if_split_asm) lemma rbt_height_bheight: "rbt t \ height t / 2 \ bheight t " by(auto simp: rbt_def dest: rbt_height_bheight_if) lemma bheight_size_bound: "invc t \ invh t \ 2 ^ (bheight t) \ size1 t" by (induction t) auto lemma rbt_height_le: assumes "rbt t" shows "height t \ 2 * log 2 (size1 t)" proof - have "2 powr (height t / 2) \ 2 powr bheight t" using rbt_height_bheight[OF assms] by (simp) also have "\ \ size1 t" using assms by (simp add: powr_realpow bheight_size_bound rbt_def) finally have "2 powr (height t / 2) \ size1 t" . hence "height t / 2 \ log 2 (size1 t)" by (simp add: le_log_iff size1_size del: divide_le_eq_numeral1(1)) thus ?thesis by simp qed end diff --git a/src/HOL/Data_Structures/Tree2.thy b/src/HOL/Data_Structures/Tree2.thy --- a/src/HOL/Data_Structures/Tree2.thy +++ b/src/HOL/Data_Structures/Tree2.thy @@ -1,42 +1,42 @@ section \Augmented Tree (Tree2)\ theory Tree2 imports "HOL-Library.Tree" begin text \This theory provides the basic infrastructure for the type @{typ \('a * 'b) tree\} of augmented trees where @{typ 'a} is the key and @{typ 'b} some additional information.\ text \IMPORTANT: Inductions and cases analyses on augmented trees need to use the following two rules explicitly. They generate nodes of the form @{term "Node l (a,b) r"} rather than @{term "Node l a r"} for trees of type @{typ "'a tree"}.\ lemmas tree2_induct = tree.induct[where 'a = "'a * 'b", split_format(complete)] lemmas tree2_cases = tree.exhaust[where 'a = "'a * 'b", split_format(complete)] fun inorder :: "('a*'b)tree \ 'a list" where "inorder Leaf = []" | "inorder (Node l (a,_) r) = inorder l @ a # inorder r" fun set_tree :: "('a*'b) tree \ 'a set" where "set_tree Leaf = {}" | -"set_tree (Node l (a,_) r) = Set.insert a (set_tree l \ set_tree r)" +"set_tree (Node l (a,_) r) = {a} \ set_tree l \ set_tree r" fun bst :: "('a::linorder*'b) tree \ bool" where "bst Leaf = True" | -"bst (Node l (a, _) r) = (bst l \ bst r \ (\x \ set_tree l. x < a) \ (\x \ set_tree r. a < x))" +"bst (Node l (a, _) r) = ((\x \ set_tree l. x < a) \ (\x \ set_tree r. a < x) \ bst l \ bst r)" lemma finite_set_tree[simp]: "finite(set_tree t)" by(induction t) auto lemma eq_set_tree_empty[simp]: "set_tree t = {} \ t = Leaf" by (cases t) auto lemma set_inorder[simp]: "set (inorder t) = set_tree t" by (induction t) auto lemma length_inorder[simp]: "length (inorder t) = size t" by (induction t) auto end diff --git a/src/HOL/Data_Structures/Tree23.thy b/src/HOL/Data_Structures/Tree23.thy --- a/src/HOL/Data_Structures/Tree23.thy +++ b/src/HOL/Data_Structures/Tree23.thy @@ -1,46 +1,46 @@ (* Author: Tobias Nipkow *) section \2-3 Trees\ theory Tree23 imports Main begin class height = fixes height :: "'a \ nat" datatype 'a tree23 = Leaf ("\\") | Node2 "'a tree23" 'a "'a tree23" ("\_, _, _\") | Node3 "'a tree23" 'a "'a tree23" 'a "'a tree23" ("\_, _, _, _, _\") fun inorder :: "'a tree23 \ 'a list" where "inorder Leaf = []" | "inorder(Node2 l a r) = inorder l @ a # inorder r" | "inorder(Node3 l a m b r) = inorder l @ a # inorder m @ b # inorder r" instantiation tree23 :: (type)height begin fun height_tree23 :: "'a tree23 \ nat" where "height Leaf = 0" | "height (Node2 l _ r) = Suc(max (height l) (height r))" | "height (Node3 l _ m _ r) = Suc(max (height l) (max (height m) (height r)))" instance .. end text \Completeness:\ fun complete :: "'a tree23 \ bool" where "complete Leaf = True" | -"complete (Node2 l _ r) = (complete l & complete r & height l = height r)" | +"complete (Node2 l _ r) = (height l = height r \ complete l & complete r)" | "complete (Node3 l _ m _ r) = - (complete l & complete m & complete r & height l = height m & height m = height r)" + (height l = height m & height m = height r & complete l & complete m & complete r)" lemma ht_sz_if_complete: "complete t \ 2 ^ height t \ size t + 1" by (induction t) auto end diff --git a/src/HOL/Library/Tree.thy b/src/HOL/Library/Tree.thy --- a/src/HOL/Library/Tree.thy +++ b/src/HOL/Library/Tree.thy @@ -1,455 +1,455 @@ (* Author: Tobias Nipkow *) (* Todo: minimal ipl of almost complete trees *) section \Binary Tree\ theory Tree imports Main begin datatype 'a tree = Leaf ("\\") | Node "'a tree" ("value": 'a) "'a tree" ("(1\_,/ _,/ _\)") datatype_compat tree primrec left :: "'a tree \ 'a tree" where "left (Node l v r) = l" | "left Leaf = Leaf" primrec right :: "'a tree \ 'a tree" where "right (Node l v r) = r" | "right Leaf = Leaf" text\Counting the number of leaves rather than nodes:\ fun size1 :: "'a tree \ nat" where "size1 \\ = 1" | "size1 \l, x, r\ = size1 l + size1 r" fun subtrees :: "'a tree \ 'a tree set" where "subtrees \\ = {\\}" | -"subtrees (\l, a, r\) = insert \l, a, r\ (subtrees l \ subtrees r)" +"subtrees (\l, a, r\) = {\l, a, r\} \ subtrees l \ subtrees r" fun mirror :: "'a tree \ 'a tree" where "mirror \\ = Leaf" | "mirror \l,x,r\ = \mirror r, x, mirror l\" class height = fixes height :: "'a \ nat" instantiation tree :: (type)height begin fun height_tree :: "'a tree => nat" where "height Leaf = 0" | "height (Node l a r) = max (height l) (height r) + 1" instance .. end fun min_height :: "'a tree \ nat" where "min_height Leaf = 0" | "min_height (Node l _ r) = min (min_height l) (min_height r) + 1" fun complete :: "'a tree \ bool" where "complete Leaf = True" | -"complete (Node l x r) = (complete l \ complete r \ height l = height r)" +"complete (Node l x r) = (height l = height r \ complete l \ complete r)" text \Almost complete:\ definition acomplete :: "'a tree \ bool" where "acomplete t = (height t - min_height t \ 1)" text \Weight balanced:\ fun wbalanced :: "'a tree \ bool" where "wbalanced Leaf = True" | "wbalanced (Node l x r) = (abs(int(size l) - int(size r)) \ 1 \ wbalanced l \ wbalanced r)" text \Internal path length:\ fun ipl :: "'a tree \ nat" where "ipl Leaf = 0 " | "ipl (Node l _ r) = ipl l + size l + ipl r + size r" fun preorder :: "'a tree \ 'a list" where "preorder \\ = []" | "preorder \l, x, r\ = x # preorder l @ preorder r" fun inorder :: "'a tree \ 'a list" where "inorder \\ = []" | "inorder \l, x, r\ = inorder l @ [x] @ inorder r" text\A linear version avoiding append:\ fun inorder2 :: "'a tree \ 'a list \ 'a list" where "inorder2 \\ xs = xs" | "inorder2 \l, x, r\ xs = inorder2 l (x # inorder2 r xs)" fun postorder :: "'a tree \ 'a list" where "postorder \\ = []" | "postorder \l, x, r\ = postorder l @ postorder r @ [x]" text\Binary Search Tree:\ fun bst_wrt :: "('a \ 'a \ bool) \ 'a tree \ bool" where "bst_wrt P \\ \ True" | "bst_wrt P \l, a, r\ \ - bst_wrt P l \ bst_wrt P r \ (\x\set_tree l. P x a) \ (\x\set_tree r. P a x)" + (\x\set_tree l. P x a) \ (\x\set_tree r. P a x) \ bst_wrt P l \ bst_wrt P r" abbreviation bst :: "('a::linorder) tree \ bool" where "bst \ bst_wrt (<)" fun (in linorder) heap :: "'a tree \ bool" where "heap Leaf = True" | "heap (Node l m r) = - (heap l \ heap r \ (\x \ set_tree l \ set_tree r. m \ x))" + ((\x \ set_tree l \ set_tree r. m \ x) \ heap l \ heap r)" subsection \\<^const>\map_tree\\ lemma eq_map_tree_Leaf[simp]: "map_tree f t = Leaf \ t = Leaf" by (rule tree.map_disc_iff) lemma eq_Leaf_map_tree[simp]: "Leaf = map_tree f t \ t = Leaf" by (cases t) auto subsection \\<^const>\size\\ lemma size1_size: "size1 t = size t + 1" by (induction t) simp_all lemma size1_ge0[simp]: "0 < size1 t" by (simp add: size1_size) lemma eq_size_0[simp]: "size t = 0 \ t = Leaf" by(cases t) auto lemma eq_0_size[simp]: "0 = size t \ t = Leaf" by(cases t) auto lemma neq_Leaf_iff: "(t \ \\) = (\l a r. t = \l, a, r\)" by (cases t) auto lemma size_map_tree[simp]: "size (map_tree f t) = size t" by (induction t) auto lemma size1_map_tree[simp]: "size1 (map_tree f t) = size1 t" by (simp add: size1_size) subsection \\<^const>\set_tree\\ lemma eq_set_tree_empty[simp]: "set_tree t = {} \ t = Leaf" by (cases t) auto lemma eq_empty_set_tree[simp]: "{} = set_tree t \ t = Leaf" by (cases t) auto lemma finite_set_tree[simp]: "finite(set_tree t)" by(induction t) auto subsection \\<^const>\subtrees\\ lemma neq_subtrees_empty[simp]: "subtrees t \ {}" by (cases t)(auto) lemma neq_empty_subtrees[simp]: "{} \ subtrees t" by (cases t)(auto) lemma size_subtrees: "s \ subtrees t \ size s \ size t" by(induction t)(auto) lemma set_treeE: "a \ set_tree t \ \l r. \l, a, r\ \ subtrees t" by (induction t)(auto) lemma Node_notin_subtrees_if[simp]: "a \ set_tree t \ Node l a r \ subtrees t" by (induction t) auto lemma in_set_tree_if: "\l, a, r\ \ subtrees t \ a \ set_tree t" by (metis Node_notin_subtrees_if) subsection \\<^const>\height\ and \<^const>\min_height\\ lemma eq_height_0[simp]: "height t = 0 \ t = Leaf" by(cases t) auto lemma eq_0_height[simp]: "0 = height t \ t = Leaf" by(cases t) auto lemma height_map_tree[simp]: "height (map_tree f t) = height t" by (induction t) auto lemma height_le_size_tree: "height t \ size (t::'a tree)" by (induction t) auto lemma size1_height: "size1 t \ 2 ^ height (t::'a tree)" proof(induction t) case (Node l a r) show ?case proof (cases "height l \ height r") case True have "size1(Node l a r) = size1 l + size1 r" by simp also have "\ \ 2 ^ height l + 2 ^ height r" using Node.IH by arith also have "\ \ 2 ^ height r + 2 ^ height r" using True by simp also have "\ = 2 ^ height (Node l a r)" using True by (auto simp: max_def mult_2) finally show ?thesis . next case False have "size1(Node l a r) = size1 l + size1 r" by simp also have "\ \ 2 ^ height l + 2 ^ height r" using Node.IH by arith also have "\ \ 2 ^ height l + 2 ^ height l" using False by simp finally show ?thesis using False by (auto simp: max_def mult_2) qed qed simp corollary size_height: "size t \ 2 ^ height (t::'a tree) - 1" using size1_height[of t, unfolded size1_size] by(arith) lemma height_subtrees: "s \ subtrees t \ height s \ height t" by (induction t) auto lemma min_height_le_height: "min_height t \ height t" by(induction t) auto lemma min_height_map_tree[simp]: "min_height (map_tree f t) = min_height t" by (induction t) auto lemma min_height_size1: "2 ^ min_height t \ size1 t" proof(induction t) case (Node l a r) have "(2::nat) ^ min_height (Node l a r) \ 2 ^ min_height l + 2 ^ min_height r" by (simp add: min_def) also have "\ \ size1(Node l a r)" using Node.IH by simp finally show ?case . qed simp subsection \\<^const>\complete\\ lemma complete_iff_height: "complete t \ (min_height t = height t)" apply(induction t) apply simp apply (simp add: min_def max_def) by (metis le_antisym le_trans min_height_le_height) lemma size1_if_complete: "complete t \ size1 t = 2 ^ height t" by (induction t) auto lemma size_if_complete: "complete t \ size t = 2 ^ height t - 1" using size1_if_complete[simplified size1_size] by fastforce lemma size1_height_if_incomplete: "\ complete t \ size1 t < 2 ^ height t" proof(induction t) case Leaf thus ?case by simp next case (Node l x r) have 1: ?case if h: "height l < height r" using h size1_height[of l] size1_height[of r] power_strict_increasing[OF h, of "2::nat"] by(auto simp: max_def simp del: power_strict_increasing_iff) have 2: ?case if h: "height l > height r" using h size1_height[of l] size1_height[of r] power_strict_increasing[OF h, of "2::nat"] by(auto simp: max_def simp del: power_strict_increasing_iff) have 3: ?case if h: "height l = height r" and c: "\ complete l" using h size1_height[of r] Node.IH(1)[OF c] by(simp) have 4: ?case if h: "height l = height r" and c: "\ complete r" using h size1_height[of l] Node.IH(2)[OF c] by(simp) from 1 2 3 4 Node.prems show ?case apply (simp add: max_def) by linarith qed lemma complete_iff_min_height: "complete t \ (height t = min_height t)" by(auto simp add: complete_iff_height) lemma min_height_size1_if_incomplete: "\ complete t \ 2 ^ min_height t < size1 t" proof(induction t) case Leaf thus ?case by simp next case (Node l x r) have 1: ?case if h: "min_height l < min_height r" using h min_height_size1[of l] min_height_size1[of r] power_strict_increasing[OF h, of "2::nat"] by(auto simp: max_def simp del: power_strict_increasing_iff) have 2: ?case if h: "min_height l > min_height r" using h min_height_size1[of l] min_height_size1[of r] power_strict_increasing[OF h, of "2::nat"] by(auto simp: max_def simp del: power_strict_increasing_iff) have 3: ?case if h: "min_height l = min_height r" and c: "\ complete l" using h min_height_size1[of r] Node.IH(1)[OF c] by(simp add: complete_iff_min_height) have 4: ?case if h: "min_height l = min_height r" and c: "\ complete r" using h min_height_size1[of l] Node.IH(2)[OF c] by(simp add: complete_iff_min_height) from 1 2 3 4 Node.prems show ?case by (fastforce simp: complete_iff_min_height[THEN iffD1]) qed lemma complete_if_size1_height: "size1 t = 2 ^ height t \ complete t" using size1_height_if_incomplete by fastforce lemma complete_if_size1_min_height: "size1 t = 2 ^ min_height t \ complete t" using min_height_size1_if_incomplete by fastforce lemma complete_iff_size1: "complete t \ size1 t = 2 ^ height t" using complete_if_size1_height size1_if_complete by blast subsection \\<^const>\acomplete\\ lemma acomplete_subtreeL: "acomplete (Node l x r) \ acomplete l" by(simp add: acomplete_def) lemma acomplete_subtreeR: "acomplete (Node l x r) \ acomplete r" by(simp add: acomplete_def) lemma acomplete_subtrees: "\ acomplete t; s \ subtrees t \ \ acomplete s" using [[simp_depth_limit=1]] by(induction t arbitrary: s) (auto simp add: acomplete_subtreeL acomplete_subtreeR) text\Balanced trees have optimal height:\ lemma acomplete_optimal: fixes t :: "'a tree" and t' :: "'b tree" assumes "acomplete t" "size t \ size t'" shows "height t \ height t'" proof (cases "complete t") case True have "(2::nat) ^ height t \ 2 ^ height t'" proof - have "2 ^ height t = size1 t" using True by (simp add: size1_if_complete) also have "\ \ size1 t'" using assms(2) by(simp add: size1_size) also have "\ \ 2 ^ height t'" by (rule size1_height) finally show ?thesis . qed thus ?thesis by (simp) next case False have "(2::nat) ^ min_height t < 2 ^ height t'" proof - have "(2::nat) ^ min_height t < size1 t" by(rule min_height_size1_if_incomplete[OF False]) also have "\ \ size1 t'" using assms(2) by (simp add: size1_size) also have "\ \ 2 ^ height t'" by(rule size1_height) finally have "(2::nat) ^ min_height t < (2::nat) ^ height t'" . thus ?thesis . qed hence *: "min_height t < height t'" by simp have "min_height t + 1 = height t" using min_height_le_height[of t] assms(1) False by (simp add: complete_iff_height acomplete_def) with * show ?thesis by arith qed subsection \\<^const>\wbalanced\\ lemma wbalanced_subtrees: "\ wbalanced t; s \ subtrees t \ \ wbalanced s" using [[simp_depth_limit=1]] by(induction t arbitrary: s) auto subsection \\<^const>\ipl\\ text \The internal path length of a tree:\ lemma ipl_if_complete_int: "complete t \ int(ipl t) = (int(height t) - 2) * 2^(height t) + 2" apply(induction t) apply simp apply simp apply (simp add: algebra_simps size_if_complete of_nat_diff) done subsection "List of entries" lemma eq_inorder_Nil[simp]: "inorder t = [] \ t = Leaf" by (cases t) auto lemma eq_Nil_inorder[simp]: "[] = inorder t \ t = Leaf" by (cases t) auto lemma set_inorder[simp]: "set (inorder t) = set_tree t" by (induction t) auto lemma set_preorder[simp]: "set (preorder t) = set_tree t" by (induction t) auto lemma set_postorder[simp]: "set (postorder t) = set_tree t" by (induction t) auto lemma length_preorder[simp]: "length (preorder t) = size t" by (induction t) auto lemma length_inorder[simp]: "length (inorder t) = size t" by (induction t) auto lemma length_postorder[simp]: "length (postorder t) = size t" by (induction t) auto lemma preorder_map: "preorder (map_tree f t) = map f (preorder t)" by (induction t) auto lemma inorder_map: "inorder (map_tree f t) = map f (inorder t)" by (induction t) auto lemma postorder_map: "postorder (map_tree f t) = map f (postorder t)" by (induction t) auto lemma inorder2_inorder: "inorder2 t xs = inorder t @ xs" by (induction t arbitrary: xs) auto subsection \Binary Search Tree\ lemma bst_wrt_mono: "(\x y. P x y \ Q x y) \ bst_wrt P t \ bst_wrt Q t" by (induction t) (auto) lemma bst_wrt_le_if_bst: "bst t \ bst_wrt (\) t" using bst_wrt_mono less_imp_le by blast lemma bst_wrt_le_iff_sorted: "bst_wrt (\) t \ sorted (inorder t)" apply (induction t) apply(simp) by (fastforce simp: sorted_append intro: less_imp_le less_trans) lemma bst_iff_sorted_wrt_less: "bst t \ sorted_wrt (<) (inorder t)" apply (induction t) apply simp apply (fastforce simp: sorted_wrt_append) done subsection \\<^const>\heap\\ subsection \\<^const>\mirror\\ lemma mirror_Leaf[simp]: "mirror t = \\ \ t = \\" by (induction t) simp_all lemma Leaf_mirror[simp]: "\\ = mirror t \ t = \\" using mirror_Leaf by fastforce lemma size_mirror[simp]: "size(mirror t) = size t" by (induction t) simp_all lemma size1_mirror[simp]: "size1(mirror t) = size1 t" by (simp add: size1_size) lemma height_mirror[simp]: "height(mirror t) = height t" by (induction t) simp_all lemma min_height_mirror [simp]: "min_height (mirror t) = min_height t" by (induction t) simp_all lemma ipl_mirror [simp]: "ipl (mirror t) = ipl t" by (induction t) simp_all lemma inorder_mirror: "inorder(mirror t) = rev(inorder t)" by (induction t) simp_all lemma map_mirror: "map_tree f (mirror t) = mirror (map_tree f t)" by (induction t) simp_all lemma mirror_mirror[simp]: "mirror(mirror t) = t" by (induction t) simp_all end