theory BTree_Set imports BTree "HOL-Data_Structures.Set_Specs" begin
section"Set interpretation"
subsection"Auxiliary functions"
fun split_half:: "('a btree×'a) list ==> (('a btree×'a) list × ('a btree×'a) list)"where "split_half xs = (take (length xs div 2) xs, drop (length xs div 2) xs)"
lemma drop_not_empty: "xs ≠ [] ==> drop (length xs div 2) xs ≠ []" apply(induction xs) apply(auto split!: list.splits) done
lemma split_half_not_empty: "length xs ≥ 1 ==>∃ls sub sep rs. split_half xs = (ls,(sub,sep)#rs)" using drop_not_empty by (metis (no_types, opaque_lifting) drop0 drop_eq_Nil eq_snd_iff hd_Cons_tl le_trans not_one_le_zero split_half.simps)
subsection"The split function locale"
text"Here, we abstract away the inner workings of the split function for B-tree operations."
(* TODO what if we define a function "list_split" that returns asplitlistformappingarbitraryf(separators)andg(subtrees) s.th.f::'a\<Rightarrow>('b::linorder)andg::'a\<Rightarrow>'abtree
this would allow for key,pointer pairs to be inserted into the tree *) (* TODO what if the keys are the pointers? *) locale split = fixes split :: "('a btree×'a::linorder) list ==> 'a ==> (('a btree×'a) list × ('a btree×'a) list)" assumes split_req: "[split xs p = (ls,rs)]==> xs = ls @ rs" "[split xs p = (ls@[(sub,sep)],rs); sorted_less (separators xs)]==> sep < p" "[split xs p = (ls,(sub,sep)#rs); sorted_less (separators xs)]==> p ≤ sep" begin
lemma [termination_simp]:"(ls, (sub, sep) # rs) = split ts y ==> size sub < Suc (size_list (λx. Suc (size (fst x))) ts + size l)" using split_conc[of ts y ls "(sub,sep)#rs"] by auto
fun invar_inorder where"invar_inorder k t = (bal t ∧ root_order k t)"
definition"empty_btree = Leaf"
subsection"Membership"
fun isin:: "'a btree ==> 'a ==> bool"where "isin (Leaf) y = False" | "isin (Node ts t) y = ( case split ts y of (_,(sub,sep)#rs) ==> ( if y = sep then True else isin sub y ) | (_,[]) ==> isin t y )"
subsection"Insertion"
text"The insert function requires an auxiliary data structure and auxiliary invariant functions."
fun order_upiwhere "order_upi k (Ti sub) = order k sub" | "order_upi k (Upi l a r) = (order k l ∧ order k r)"
fun root_order_upiwhere "root_order_upi k (Ti sub) = root_order k sub" | "root_order_upi k (Upi l a r) = (order k l ∧ order k r)"
fun height_upiwhere "height_upi (Ti t) = height t" | "height_upi (Upi l a r) = max (height l) (height r)"
fun bal_upiwhere "bal_upi (Ti t) = bal t" | "bal_upi (Upi l a r) = (height l = height r ∧ bal l ∧ bal r)"
fun inorder_upiwhere "inorder_upi (Ti t) = inorder t" | "inorder_upi (Upi l a r) = inorder l @ [a] @ inorder r"
text"The following function merges two nodes and returns separately split nodes if an overflow occurs"
fun nodei:: "nat ==> ('a btree × 'a) list ==> 'a btree ==> 'a upi"where "nodei k ts t = ( if length ts ≤ 2*k then Ti (Node ts t) else ( case split_half ts of (ls, (sub,sep)#rs) ==> Upi (Node ls sub) sep (Node rs t) ) )"
lemma nodei_ti_simp: "nodei k ts t = Ti x ==> x = Node ts t" apply (cases "length ts ≤ 2*k") apply (auto split!: list.splits) done
fun ins:: "nat ==> 'a ==> 'a btree ==> 'a upi"where "ins k x Leaf = (Upi Leaf x Leaf)" | "ins k x (Node ts t) = ( case split ts x of (ls,(sub,sep)#rs) ==> (if sep = x then Ti (Node ts t) else (case ins k x sub of Upi l a r ==> nodei k (ls @ (l,a)#(r,sep)#rs) t | Ti a ==> Ti (Node (ls @ (a,sep) # rs) t))) | (ls, []) ==> (case ins k x t of Upi l a r ==> nodei k (ls@[(l,a)]) r | Ti a ==> Ti (Node ls a) ) )"
fun treei::"'a upi==> 'a btree"where "treei (Ti sub) = sub" | "treei (Upi l a r) = (Node [(l,a)] r)"
fun insert::"nat ==> 'a ==> 'a btree ==> 'a btree"where "insert k x t = treei (ins k x t)"
subsection"Deletion"
text"The following deletion method is inspired by Bayer (70) and Fielding (80). Rather than stealing only a single node from the neighbour, the neighbour is fully merged with the potentially underflowing node. If the resulting node is still larger than allowed, the merged node is split again, using the rules known from insertion splits. If the resulting node has admissable size, it is simply kept in the tree."
fun rebalance_middle_tree where "rebalance_middle_tree k ls Leaf sep rs Leaf = ( Node (ls@(Leaf,sep)#rs) Leaf )" | "rebalance_middle_tree k ls (Node mts mt) sep rs (Node tts tt) = ( if length mts ≥ k ∧ length tts ≥ k then Node (ls@(Node mts mt,sep)#rs) (Node tts tt) else ( case rs of [] ==> ( case nodei k (mts@(mt,sep)#tts) tt of Ti u ==> Node ls u | Upi l a r ==> Node (ls@[(l,a)]) r) | (Node rts rt,rsep)#rs ==> ( case nodei k (mts@(mt,sep)#rts) rt of Ti u ==> Node (ls@(u,rsep)#rs) (Node tts tt) | Upi l a r ==> Node (ls@(l,a)#(r,rsep)#rs) (Node tts tt)) ))"
text"Deletion"
text"All trees are merged with the right neighbour on underflow. Obviously for the last tree this would not work since it has no right neighbour. Therefore this tree, as the only exception, is merged with the left neighbour. However since we it does not make a difference, we treat the situation as if the second to last tree underflowed."
fun rebalance_last_tree where "rebalance_last_tree k ts t = ( case last ts of (sub,sep) ==> rebalance_middle_tree k (butlast ts) sub sep [] t )"
text"Rather than deleting the minimal key from the right subtree, we remove the maximal key of the left subtree. This is due to the fact that the last tree can easily be accessed and the left neighbour is way easier to access than the right neighbour, it resides in the same pair as the separating element to be removed."
fun split_max where "split_max k (Node ts t) = (case t of Leaf ==> ( let (sub,sep) = last ts in (Node (butlast ts) sub, sep) )| _ ==> case split_max k t of (sub, sep) ==> (rebalance_last_tree k ts sub, sep) )"
fun del where "del k x Leaf = Leaf" | "del k x (Node ts t) = ( case split ts x of (ls,[]) ==> rebalance_last_tree k ls (del k x t) | (ls,(sub,sep)#rs) ==> ( if sep ≠ x then rebalance_middle_tree k ls (del k x sub) sep rs t else if sub = Leaf then Node (ls@rs) t else let (sub_s, max_s) = split_max k sub in rebalance_middle_tree k ls sub_s max_s rs t ) )"
fun reduce_root where "reduce_root Leaf = Leaf" | "reduce_root (Node ts t) = (case ts of [] ==> t | _ ==> (Node ts t) )"
fun delete where"delete k x t = reduce_root (del k x t)"
text"An invariant for intermediate states at deletion. In particular we allow for an underflow to 0 subtrees."
fun almost_order where "almost_order k Leaf = True" | "almost_order k (Node ts t) = ( (length ts ≤ 2*k) ∧ (∀s ∈ set (subtrees ts). order k s) ∧ order k t )"
text"A recursive property of the \"spine\" we want to walk along for splitting off the maximum of the left subtree."
fun nonempty_lasttreebal where "nonempty_lasttreebal Leaf = True" | "nonempty_lasttreebal (Node ts t) = ( (∃ls tsub tsep. ts = (ls@[(tsub,tsep)]) ∧ height tsub = height t) ∧ nonempty_lasttreebal t )"
subsection"Proofs of functional correctness"
lemma split_set: assumes"split ts z = (ls,(a,b)#rs)" shows"(a,b) ∈ set ts" and"(x,y) ∈ set ls ==> (x,y) ∈ set ts" and"(x,y) ∈ set rs ==> (x,y) ∈ set ts" and"set ls ∪ set rs ∪ {(a,b)} = set ts" and"∃x ∈ set ts. b ∈ Basic_BNFs.snds x" using split_conc assms by fastforce+
lemma split_length: "split ts x = (ls, rs) ==> length ls + length rs = length ts" by (auto dest: split_conc)
text"Isin proof"
thm isin_simps (* copied from comment in List_Ins_Del *) lemma sorted_ConsD: "sorted_less (y # xs) ==> x ≤ y ==> x ∉ set xs" by (auto simp: sorted_Cons_iff)
lemma sorted_snocD: "sorted_less (xs @ [y]) ==> y ≤ x ==> x ∉ set xs" by (auto simp: sorted_snoc_iff)
lemma isin_sorted: "sorted_less (xs@a#ys) ==> (x ∈ set (xs@a#ys)) = (if x < a then x ∈ set xs else x ∈ set (a#ys))" by (auto simp: isin_simps2)
(* lift to split *)
lemma isin_sorted_split: assumes"sorted_less (inorder (Node ts t))" and"split ts x = (ls, rs)" shows"x ∈ set (inorder (Node ts t)) = (x ∈ set (inorder_list rs @ inorder t))" proof (cases ls) case Nil thenhave"ts = rs" using assms by (auto dest!: split_conc) thenshow ?thesis by simp next case Cons thenobtain ls' sub sep where ls_tail_split: "ls = ls' @ [(sub,sep)]" by (metis list.simps(3) rev_exhaust surj_pair) thenhave"sep < x" using split_req(2)[of ts x ls' sub sep rs] using sorted_inorder_separators[OF assms(1)] using assms by simp thenshow ?thesis using assms(1) split_conc[OF assms(2)] ls_tail_split using isin_sorted[of "inorder_list ls' @ inorder sub" sep "inorder_list rs @ inorder t" x] by auto qed
lemma isin_sorted_split_right: assumes"split ts x = (ls, (sub,sep)#rs)" and"sorted_less (inorder (Node ts t))" and"sep ≠ x" shows"x ∈ set (inorder_list ((sub,sep)#rs) @ inorder t) = (x ∈ set (inorder sub))" proof - from assms have"x < sep" proof - from assms have"sorted_less (separators ts)" by (simp add: sorted_inorder_separators) thenshow ?thesis using split_req(3) using assms by fastforce qed moreoverhave"sorted_less (inorder_list ((sub,sep)#rs) @ inorder t)" using assms sorted_wrt_append split_conc by fastforce ultimatelyshow ?thesis using isin_sorted[of "inorder sub""sep""inorder_list rs @ inorder t" x] by simp qed
theorem isin_set_inorder: "sorted_less (inorder t) ==> isin t x = (x ∈ set (inorder t))" proof(induction t x rule: isin.induct) case (2 ts t x) thenobtain ls rs where list_split: "split ts x = (ls, rs)" by (meson surj_pair) thenhave list_conc: "ts = ls @ rs" using split_conc by auto show ?case proof (cases rs) case Nil thenhave"isin (Node ts t) x = isin t x" by (simp add: list_split) alsohave"… = (x ∈ set (inorder t))" using"2.IH"(1) list_split Nil using"2.prems" sorted_inorder_induct_last by auto alsohave"… = (x ∈ set (inorder (Node ts t)))" using isin_sorted_split[of ts t x ls rs] using"2.prems" list_split list_conc Nil by simp finallyshow ?thesis . next case (Cons a list) thenobtain sub sep where a_split: "a = (sub,sep)" by (cases a) thenshow ?thesis proof (cases "x = sep") case True thenshow ?thesis using list_conc Cons a_split list_split by auto next case False thenhave"isin (Node ts t) x = isin sub x" using list_split Cons a_split False by auto alsohave"… = (x ∈ set (inorder sub))" using"2.IH"(2) using"2.prems" False a_split list_conc list_split local.Cons sorted_inorder_induct_subtree by fastforce alsohave"… = (x ∈ set (inorder (Node ts t)))" using isin_sorted_split[OF "2.prems" list_split] using isin_sorted_split_right "2.prems" list_split Cons a_split False by simp finallyshow ?thesis . qed qed qed auto
(* TODO way to use this for custom case distinction? *) lemma nodei_cases: "length xs ≤ k ∨ (∃ls sub sep rs. split_half xs = (ls,(sub,sep)#rs))" proof - have"¬ length xs ≤ k ==> length xs ≥ 1" by linarith thenshow ?thesis using split_half_not_empty by blast qed
lemma root_order_treei: "root_order_upi (Suc k) t = root_order (Suc k) (treei t)" apply (cases t) apply auto done
lemma nodei_root_order: assumes"length ts > 0" and"length ts ≤ 4*k+1" and"∀x ∈ set (subtrees ts). order k x" and"order k t" shows"root_order_upi k (nodei k ts t)" proof (cases "length ts ≤ 2*k") case True thenshow ?thesis using assms by (simp add: nodei.simps) next case False thenobtain ls sub sep rs where split_half_ts: "take (length ts div 2) ts = ls" "drop (length ts div 2) ts = (sub,sep)#rs" using split_half_not_empty[of ts] by auto thenhave length_rs: "length rs = length ts - (length ts div 2) - 1" using length_drop by (metis One_nat_def add_diff_cancel_right' list.size(4)) alsohave"…≤ 4*k - ((4*k + 1) div 2)" using assms(2) by simp alsohave"… = 2*k" by auto finallyhave"length rs ≤ 2*k" by simp moreoverhave"length rs ≥ k" using False length_rs by simp moreoverhave"set ((sub,sep)#rs) ⊆ set ts" by (metis split_half_ts(2) set_drop_subset) ultimatelyhave o_r: "order k sub""order k (Node rs t)" using split_half_ts assms by auto moreoverhave"length ls ≥ k" using length_take assms split_half_ts False by auto moreoverhave"length ls ≤ 2*k" using assms(2) split_half_ts by auto ultimatelyhave o_l: "order k (Node ls sub)" using set_take_subset assms split_half_ts by fastforce from o_r o_l show ?thesis by (simp add: nodei.simps False split_half_ts) qed
lemma nodei_order_helper: assumes"length ts ≥ k" and"length ts ≤ 4*k+1" and"∀x ∈ set (subtrees ts). order k x" and"order k t" shows"case (nodei k ts t) of Ti t ==> order k t | _ ==> True" proof (cases "length ts ≤ 2*k") case True thenshow ?thesis using assms by (simp add: nodei.simps) next case False thenobtain sub sep rs where "drop (length ts div 2) ts = (sub,sep)#rs" using split_half_not_empty[of ts] by auto thenshow ?thesis using assms by (simp add: nodei.simps) qed
lemma nodei_order: assumes"length ts ≥ k" and"length ts ≤ 4*k+1" and"∀x ∈ set (subtrees ts). order k x" and"order k t" shows"order_upi k (nodei k ts t)"
(* explicit proof *) lemma ins_order: "order k t ==> order_upi k (ins k x t)" proof(induction k x t rule: ins.induct) case (2 k x ts t) thenobtain ls rs where split_res: "split ts x = (ls, rs)" by (meson surj_pair) thenhave split_app: "ls@rs = ts" using split_conc by simp
show ?case proof (cases rs) case Nil thenhave"order_upi k (ins k x t)" using2 split_res by simp thenshow ?thesis using Nil 2 split_app split_res Nil nodei_order by (auto split!: upi.splits simp del: nodei.simps) next case (Cons a list) thenobtain sub sep where a_prod: "a = (sub, sep)" by (cases a) thenshow ?thesis proof (cases "x = sep") case True thenshow ?thesis using2 a_prod Cons split_res by simp next case False thenhave"order_upi k (ins k x sub)" using"2.IH"(2) "2.prems" a_prod local.Cons split_app split_res by auto thenshow ?thesis using2 split_app Cons length_append nodei_order a_prod split_res by (auto split!: upi.splits simp del: nodei.simps simp add: order_impl_root_order) qed qed qed simp
(* notice this is almost a duplicate of ins_order *) lemma ins_root_order: assumes"root_order k t" shows"root_order_upi k (ins k x t)" proof(cases t) case (Node ts t) thenobtain ls rs where split_res: "split ts x = (ls, rs)" by (meson surj_pair) thenhave split_app: "ls@rs = ts" using split_conc by fastforce
show ?thesis proof (cases rs) case Nil thenhave"order_upi k (ins k x t)"using Node assms split_res by (simp add: ins_order) thenshow ?thesis using Nil Node split_app split_res assms nodei_root_order by (auto split!: upi.splits simp del: nodei.simps simp add: order_impl_root_order) next case (Cons a list) thenobtain sub sep where a_prod: "a = (sub, sep)" by (cases a) thenshow ?thesis proof (cases "x = sep") case True thenshow ?thesis using assms Node a_prod Cons split_res by simp next case False thenhave"order_upi k (ins k x sub)" using Node a_prod assms ins_order local.Cons split_app by auto thenshow ?thesis using assms split_app Cons length_append Node nodei_root_order a_prod split_res by (auto split!: upi.splits simp del: nodei.simps simp add: order_impl_root_order) qed qed qed simp
lemma height_list_split: "height_upi (Upi (Node ls a) b (Node rs t)) = height (Node (ls@(a,b)#rs) t) " by (induction ls) (auto simp add: max.commute)
lemma nodei_height: "height_upi (nodei k ts t) = height (Node ts t)" proof(cases "length ts ≤ 2*k") case False thenobtain ls sub sep rs where
split_half_ts: "split_half ts = (ls, (sub, sep) # rs)" by (meson nodei_cases) thenhave"nodei k ts t = Upi (Node ls (sub)) sep (Node rs t)" using False by simp thenshow ?thesis using split_half_ts by (metis append_take_drop_id fst_conv height_list_split snd_conv split_half.elims) qed simp
lemma bal_upi_tree: "bal_upi t = bal (treei t)" apply(cases t) apply auto done
lemma bal_list_split: "bal (Node (ls@(a,b)#rs) t) ==> bal_upi (Upi (Node ls a) b (Node rs t))" by (auto simp add: image_constant_conv)
lemma nodei_bal: assumes"bal (Node ts t)" shows"bal_upi (nodei k ts t)" using assms proof(cases "length ts ≤ 2*k") case False thenobtain ls sub sep rs where
split_half_ts: "split_half ts = (ls, (sub, sep) # rs)" by (meson nodei_cases) thenhave"bal (Node (ls@(sub,sep)#rs) t)" using assms append_take_drop_id[where n="length ts div 2"and xs=ts] by auto thenshow ?thesis using split_half_ts assms False by (auto simp del: bal.simps bal_upi.simps dest!: bal_list_split[of ls sub sep rs t]) qed simp
lemma height_upi_merge: "height_upi (Upi l a r) = height t ==> height (Node (ls@(t,x)#rs) tt) = height (Node (ls@(l,a)#(r,x)#rs) tt)" by simp
lemma ins_height: "height_upi (ins k x t) = height t" proof(induction k x t rule: ins.induct) case (2 k x ts t) thenobtain ls rs where split_list: "split ts x = (ls,rs)" by (meson surj_pair) thenhave split_append: "ls@rs = ts" using split_conc by auto thenshow ?case proof (cases rs) case Nil thenhave height_sub: "height_upi (ins k x t) = height t" using2by (simp add: split_list) thenshow ?thesis proof (cases "ins k x t") case (Ti a) thenhave"height (Node ts t) = height (Node ts a)" using height_sub by simp thenshow ?thesis using Ti Nil split_list split_append by simp next case (Upi l a r) thenhave"height (Node ls t) = height (Node (ls@[(l,a)]) r)" using height_btree_order height_sub by (induction ls) auto thenshow ?thesis using2 Nil split_list Upi split_append by (simp del: nodei.simps add: nodei_height) qed next case (Cons a list) thenobtain sub sep where a_split: "a = (sub,sep)" by (cases a) thenshow ?thesis proof (cases "x = sep") case True thenshow ?thesis using Cons a_split 2 split_list by (simp del: height_btree.simps) next case False thenhave height_sub: "height_upi (ins k x sub) = height sub" by (metis "2.IH"(2) a_split Cons split_list) thenshow ?thesis proof (cases "ins k x sub") case (Ti a) thenhave"height a = height sub" using height_sub by auto thenhave"height (Node (ls@(sub,sep)#rs) t) = height (Node (ls@(a,sep)#rs) t)" by auto thenshow ?thesis using Ti height_sub False Cons 2 split_list a_split split_append by (auto simp add: image_Un max.commute finite_set_ins_swap) next case (Upi l a r) thenhave"height (Node (ls@(sub,sep)#list) t) = height (Node (ls@(l,a)#(r,sep)#list) t)" using height_upi_merge height_sub by fastforce thenshow ?thesis using Upi False Cons 2 split_list a_split split_append by (auto simp del: nodei.simps simp add: nodei_height image_Un max.commute finite_set_ins_swap) qed qed qed qed simp
(* the below proof is overly complicated as a number of lemmas regarding height are missing *) lemma ins_bal: "bal t ==> bal_upi (ins k x t)" proof(induction k x t rule: ins.induct) case (2 k x ts t) thenobtain ls rs where split_res: "split ts x = (ls, rs)" by (meson surj_pair) thenhave split_app: "ls@rs = ts" using split_conc by fastforce
show ?case proof (cases rs) case Nil thenshow ?thesis proof (cases "ins k x t") case (Ti a) thenhave"bal (Node ls a)"unfolding bal.simps by (metis "2.IH"(1) "2.prems" append_Nil2 bal.simps(2) bal_upi.simps(1) height_upi.simps(1) ins_height local.Nil split_app split_res) thenshow ?thesis using Nil Ti2 split_res by simp next case (Upi l a r) thenhave "(∀x∈set (subtrees (ls@[(l,a)])). bal x)" "(∀x∈set (subtrees ls). height r = height x)" using2 Upi Nil split_res split_app by simp_all (metis height_upi.simps(2) ins_height max_def) thenshow ?thesis unfolding ins.simps using Upi Nil 2 split_res by (simp del: nodei.simps add: nodei_bal) qed next case (Cons a list) thenobtain sub sep where a_prod: "a = (sub, sep)"by (cases a) thenshow ?thesis proof (cases "x = sep") case True thenshow ?thesis using a_prod 2 split_res Cons by simp next case False thenhave"bal_upi (ins k x sub)"using2 split_res using a_prod local.Cons split_app by auto show ?thesis proof (cases "ins k x sub") case (Ti x1) thenhave"height x1 = height t" by (metis "2.prems" a_prod add_diff_cancel_left' bal_split_left(1) bal_split_left(2) height_bal_tree height_upi.simps(1) ins_height local.Cons plus_1_eq_Suc split_app) thenshow ?thesis using split_app Cons Ti2 split_res a_prod by auto next case (Upi l a r) (* The only case where explicit reasoning is required - likely due to the insertion of 2 elements in the list *) thenhave "∀x ∈ set (subtrees (ls@(l,a)#(r,sep)#list)). bal x" using Upi split_app Cons 2‹bal_upi (ins k x sub)›by auto moreoverhave"∀x ∈ set (subtrees (ls@(l,a)#(r,sep)#list)). height x = height t" using False Upi split_app Cons 2‹bal_upi (ins k x sub)› ins_height split_res a_prod apply auto by (metis height_upi.simps(2) sup.idem sup_nat_def) ultimatelyshow ?thesis using Upi Cons 2 split_res a_prod by (simp del: nodei.simps add: nodei_bal) qed qed qed qed simp
(* ins acts as ins_list wrt inorder *)
(* "simple enough" to be automatically solved *) lemma nodei_inorder: "inorder_upi (nodei k ts t) = inorder (Node ts t)" apply(cases "length ts ≤ 2*k") apply (auto split!: list.splits) (* we want to only transform in one direction here.. *)
supply R = sym[OF append_take_drop_id, of "map _ ts""(length ts div 2)"] thm R apply(subst R) apply (simp del: append_take_drop_id add: take_map drop_map) done
corollary nodei_inorder_simps: "nodei k ts t = Ti t' ==> inorder t' = inorder (Node ts t)" "nodei k ts t = Upi l a r ==> inorder l @ a # inorder r = inorder (Node ts t)" apply (metis inorder_upi.simps(1) nodei_inorder) by (metis append_Cons inorder_upi.simps(2) nodei_inorder self_append_conv2)
lemma ins_sorted_inorder: "sorted_less (inorder t) ==> (inorder_upi (ins k (x::('a::linorder)) t)) = ins_list x (inorder t)" apply(induction k x t rule: ins.induct) using split_axioms apply (auto split!: prod.splits list.splits upi.splits simp del: nodei.simps
simp add: nodei_inorder nodei_inorder_simps) (* from here on we prefer an explicit proof, showing how to apply the IH *) oops
(* specialize ins_list_sorted since it is cumbersome to express
"inorder_list ts" as "xs @ [a]" and always having to use the implicit properties of split*)
lemma ins_list_split: assumes"split ts x = (ls, rs)" and"sorted_less (inorder (Node ts t))" shows"ins_list x (inorder (Node ts t)) = inorder_list ls @ ins_list x (inorder_list rs @ inorder t)" proof (cases ls) case Nil thenshow ?thesis using assms by (auto dest!: split_conc) next case Cons thenobtain ls' sub sep where ls_tail_split: "ls = ls' @ [(sub,sep)]" by (metis list.distinct(1) rev_exhaust surj_pair) moreoverhave"sep < x" using split_req(2)[of ts x ls' sub sep rs] using sorted_inorder_separators using assms(1) assms(2) ls_tail_split by auto moreoverhave"sorted_less (inorder_list ls)" using assms sorted_wrt_append split_conc by fastforce ultimatelyshow ?thesis using assms(2) split_conc[OF assms(1)] using ins_list_sorted[of "inorder_list ls' @ inorder sub" sep] by auto qed
lemma ins_list_split_right_general: assumes"split ts x = (ls, (sub,sep)#rs)" and"sorted_less (inorder_list ts)" and"sep ≠ x" shows"ins_list x (inorder_list ((sub,sep)#rs) @ zs) = ins_list x (inorder sub) @ sep # inorder_list rs @ zs" proof - from assms have"x < sep" proof - from assms have"sorted_less (separators ts)" by (simp add: sorted_inorder_list_separators) thenshow ?thesis using split_req(3) using assms by fastforce qed moreoverhave"sorted_less (inorder_pair (sub,sep))" by (metis (no_types, lifting) assms(1) assms(2) concat.simps(2) concat_append list.simps(9) map_append sorted_wrt_append split_conc) ultimatelyshow ?thesis using ins_list_sorted[of "inorder sub""sep"] by auto qed
(* this fits the actual use cases better *) corollary ins_list_split_right: assumes"split ts x = (ls, (sub,sep)#rs)" and"sorted_less (inorder (Node ts t))" and"sep ≠ x" shows"ins_list x (inorder_list ((sub,sep)#rs) @ inorder t) = ins_list x (inorder sub) @ sep # inorder_list rs @ inorder t" using assms sorted_wrt_append split.ins_list_split_right_general split_axioms by fastforce
(* a simple lemma, missing from the standard as of now *) lemma ins_list_idem_eq_isin: "sorted_less xs ==> x ∈ set xs ⟷ (ins_list x xs = xs)" apply(induction xs) apply auto done
lemma ins_list_contains_idem: "[sorted_less xs; x ∈ set xs]==> (ins_list x xs = xs)" using ins_list_idem_eq_isin by auto
lemma ins_inorder: "sorted_less (inorder t) ==> (inorder_upi (ins k x t)) = ins_list x (inorder t)" proof(induction k x t rule: ins.induct) case (1 k x) thenshow ?caseby auto next case (2 k x ts t) thenobtain ls rs where list_split: "split ts x = (ls,rs)" by (cases "split ts x") thenhave list_conc: "ts = ls@rs" using split.split_conc split_axioms by blast thenshow ?case proof (cases rs) case Nil thenshow ?thesis proof (cases "ins k x t") case (Ti a) thenhave IH:"inorder a = ins_list x (inorder t)" using"2.IH"(1) "2.prems" list_split local.Nil sorted_inorder_induct_last by auto
have"inorder_upi (ins k x (Node ts t)) = inorder_list ls @ inorder a" using list_split Ti Nil by (auto simp add: list_conc) alsohave"… = inorder_list ls @ (ins_list x (inorder t))" by (simp add: IH) alsohave"… = ins_list x (inorder (Node ts t))" using ins_list_split using"2.prems" list_split Nil by auto finallyshow ?thesis . next case (Upi l a r) thenhave IH:"inorder_upi (Upi l a r) = ins_list x (inorder t)" using"2.IH"(1) "2.prems" list_split local.Nil sorted_inorder_induct_last by auto
have"inorder_upi (ins k x (Node ts t)) = inorder_list ls @ inorder_upi (Upi l a r)" using list_split Upi Nil by (auto simp add: list_conc) alsohave"… = inorder_list ls @ ins_list x (inorder t)" using IH by simp alsohave"… = ins_list x (inorder (Node ts t))" using ins_list_split using"2.prems" list_split local.Nil by auto finallyshow ?thesis . qed next case (Cons h list) thenobtain sub sep where h_split: "h = (sub,sep)" by (cases h)
thenhave sorted_inorder_sub: "sorted_less (inorder sub)" using"2.prems" list_conc local.Cons sorted_inorder_induct_subtree by fastforce thenshow ?thesis proof(cases "x = sep") case True thenhave"x ∈ set (inorder (Node ts t))" using list_conc h_split Cons by simp thenhave"ins_list x (inorder (Node ts t)) = inorder (Node ts t)" using"2.prems" ins_list_contains_idem by blast alsohave"… = inorder_upi (ins k x (Node ts t))" using list_split h_split Cons True by auto finallyshow ?thesis by simp next case False thenshow ?thesis proof (cases "ins k x sub") case (Ti a) thenhave IH:"inorder a = ins_list x (inorder sub)" using"2.IH"(2) "2.prems" list_split Cons sorted_inorder_sub h_split False by auto have"inorder_upi (ins k x (Node ts t)) = inorder_list ls @ inorder a @ sep # inorder_list list @ inorder t" using h_split False list_split Ti Cons by simp alsohave"… = inorder_list ls @ ins_list x (inorder sub) @ sep # inorder_list list @ inorder t" using IH by simp alsohave"… = ins_list x (inorder (Node ts t))" using ins_list_split ins_list_split_right using list_split "2.prems" Cons h_split False by auto finallyshow ?thesis . next case (Upi l a r) thenhave IH:"inorder_upi (Upi l a r) = ins_list x (inorder sub)" using"2.IH"(2) False h_split list_split local.Cons sorted_inorder_sub by auto have"inorder_upi (ins k x (Node ts t)) = inorder_list ls @ inorder l @ a # inorder r @ sep # inorder_list list @ inorder t" using h_split False list_split Upi Cons by simp alsohave"… = inorder_list ls @ ins_list x (inorder sub) @ sep # inorder_list list @ inorder t" using IH by simp alsohave"… = ins_list x (inorder (Node ts t))" using ins_list_split ins_list_split_right using list_split "2.prems" Cons h_split False by auto finallyshow ?thesis . qed qed qed qed
lemma treei_bal: "bal_upi u ==> bal (treei u)" apply(cases u) apply(auto) done
lemma treei_order: "[k > 0; root_order_upi k u]==> root_order k (treei u)" apply(cases u) apply(auto simp add: order_impl_root_order) done
lemma treei_inorder: "inorder_upi u = inorder (treei u)" apply (cases u) apply auto done
lemma insert_bal: "bal t ==> bal (insert k x t)" using ins_bal by (simp add: treei_bal)
lemma insert_order: "[k > 0; root_order k t]==> root_order k (insert k x t)" using ins_root_order by (simp add: treei_order)
lemma insert_inorder: "sorted_less (inorder t) ==> inorder (insert k x t) = ins_list x (inorder t)" using ins_inorder by (simp add: treei_inorder)
text"Deletion proofs"
thm list.simps
lemma rebalance_middle_tree_height: assumes"height t = height sub" and"case rs of (rsub,rsep) # list ==> height rsub = height t | [] ==> True" shows"height (rebalance_middle_tree k ls sub sep rs t) = height (Node (ls@(sub,sep)#rs) t)" proof (cases "height t") case0 thenhave"t = Leaf""sub = Leaf"using height_Leaf assms by auto thenshow ?thesis by simp next case (Suc nat) thenobtain tts tt where t_node: "t = Node tts tt" using height_Leaf by (cases t) simp thenobtain mts mt where sub_node: "sub = Node mts mt" using assms by (cases sub) simp thenshow ?thesis proof (cases "length mts ≥ k ∧ length tts ≥ k") case False thenshow ?thesis proof (cases rs) case Nil thenhave"height_upi (nodei k (mts@(mt,sep)#tts) tt) = height (Node (mts@(mt,sep)#tts) tt)" using nodei_heightby blast alsohave"… = max (height t) (height sub)" by (metis assms(1) height_upi.simps(2) height_list_split sub_node t_node) finallyhave height_max: "height_upi (nodei k (mts @ (mt, sep) # tts) tt) = max (height t) (height sub)"by simp thenshow ?thesis proof (cases "nodei k (mts@(mt,sep)#tts) tt") case (Ti u) thenhave"height u = max (height t) (height sub)"using height_max by simp thenhave"height (Node ls u) = height (Node (ls@[(sub,sep)]) t)" by (induction ls) (auto simp add: max.commute) thenshow ?thesis using Nil False Ti by (simp add: sub_node t_node) next case (Upi l a r) thenhave"height (Node (ls@[(sub,sep)]) t) = height (Node (ls@[(l,a)]) r)" using assms(1) height_max by (induction ls) auto thenshow ?thesis using Upi Nil sub_node t_node by auto qed next case (Cons a list) thenobtain rsub rsep where a_split: "a = (rsub, rsep)" by (cases a) thenobtain rts rt where r_node: "rsub = Node rts rt" using assms(2) Cons height_Leaf Suc by (cases rsub) simp_all
thenhave"height_upi (nodei k (mts@(mt,sep)#rts) rt) = height (Node (mts@(mt,sep)#rts) rt)" using nodei_heightby blast alsohave"… = max (height rsub) (height sub)" by (metis r_node height_upi.simps(2) height_list_split max.commute sub_node) finallyhave height_max: "height_upi (nodei k (mts @ (mt, sep) # rts) rt) = max (height rsub) (height sub)"by simp thenshow ?thesis proof (cases "nodei k (mts@(mt,sep)#rts) rt") case (Ti u) thenhave"height u = max (height rsub) (height sub)" using height_max by simp thenshow ?thesis using Ti False Cons r_node a_split sub_node t_node by auto next case (Upi l a r) thenhave height_max: "max (height l) (height r) = max (height rsub) (height sub)" using height_max by auto thenshow ?thesis using Cons a_split r_node Upi sub_node t_node by auto qed qed qed (simp add: sub_node t_node) qed
lemma rebalance_last_tree_height: assumes"height t = height sub" and"ts = list@[(sub,sep)]" shows"height (rebalance_last_tree k ts t) = height (Node ts t)" using rebalance_middle_tree_height assms by auto
lemma split_max_height: assumes"split_max k t = (sub,sep)" and"nonempty_lasttreebal t" and"t ≠ Leaf" shows"height sub = height t" using assms proof(induction t arbitrary: k sub sep) case Node1: (Node tts tt) thenobtain ls tsub tsep where tts_split: "tts = ls@[(tsub,tsep)]"by auto thenshow ?case proof (cases tt) case Leaf thenhave"height (Node (ls@[(tsub,tsep)]) tt) = max (height (Node ls tsub)) (Suc (height tt))" using height_btree_last height_btree_order by metis moreoverhave"split_max k (Node tts tt) = (Node ls tsub, tsep)" using Leaf Node1 tts_split by auto ultimatelyshow ?thesis using Leaf Node1 height_Leaf max_def by auto next case Node2: (Node l a) thenobtain subsub subsep where sub_split: "split_max k tt = (subsub,subsep)"by (cases "split_max k tt") thenhave"height subsub = height tt"using Node1 Node2 by auto moreoverhave"split_max k (Node tts tt) = (rebalance_last_tree k tts subsub, subsep)" using Node1 Node2 tts_split sub_split by auto ultimatelyshow ?thesis using rebalance_last_tree_height Node1 Node2 by auto qed qed auto
lemma order_bal_nonempty_lasttreebal: "[k > 0; root_order k t; bal t]==> nonempty_lasttreebal t" proof(induction k t rule: order.induct) case (2 k ts t) thenhave"length ts > 0"by auto thenobtain ls tsub tsep where ts_split: "ts = (ls@[(tsub,tsep)])" by (metis eq_fst_iff length_greater_0_conv snoc_eq_iff_butlast) moreoverhave"height tsub = height t" using"2.prems"(3) ts_split by auto moreoverhave"nonempty_lasttreebal t"using2 order_impl_root_order by auto ultimatelyshow ?caseby simp qed simp
lemma bal_sub_height: "bal (Node (ls@a#rs) t) ==> (case rs of [] ==> True | (sub,sep)#_ ==> height sub = height t)" by (cases rs) (auto)
lemma del_height: "[k > 0; root_order k t; bal t]==> height (del k x t) = height t" proof(induction k x t rule: del.induct) case (2 k x ts t) thenobtain ls list where list_split: "split ts x = (ls, list)"by (cases "split ts x") thenshow ?case proof(cases list) case Nil thenhave"height (del k x t) = height t" using2 list_split order_bal_nonempty_lasttreebal by (simp add: order_impl_root_order) moreoverobtain lls sub sep where"ls = lls@[(sub,sep)]" using split_conc 2 list_split Nil by (metis append_Nil2 nonempty_lasttreebal.simps(2) order_bal_nonempty_lasttreebal) moreoverhave"Node ls t = Node ts t"using split_conc Nil list_split by auto ultimatelyshow ?thesis using rebalance_last_tree_height 2 list_split Nil split_conc by (auto simp add: max.assoc sup_nat_def max_def) next case (Cons a rs) thenhave rs_height: "case rs of [] ==> True | (rsub,rsep)#_ ==> height rsub = height t"(* notice the difference if rsub and t are switched *) using"2.prems"(3) bal_sub_height list_split split_conc by blast from Cons obtain sub sep where a_split: "a = (sub,sep)"by (cases a)
consider (sep_n_x) "sep ≠ x" |
(sep_x_Leaf) "sep = x ∧ sub = Leaf" |
(sep_x_Node) "sep = x ∧ (∃ts t. sub = Node ts t)" using btree.exhaust by blast thenshow ?thesis proof cases case sep_n_x have height_t_sub: "height t = height sub" using"2.prems"(3) a_split list_split local.Cons split.split_set(1) split_axioms by fastforce have height_t_del: "height (del k x sub) = height t" by (metis "2.IH"(2) "2.prems"(1) "2.prems"(2) "2.prems"(3) a_split bal.simps(2) list_split local.Cons order_impl_root_order root_order.simps(2) sep_n_x some_child_sub(1) split_set(1)) thenhave"height (rebalance_middle_tree k ls (del k x sub) sep rs t) = height (Node (ls@((del k x sub),sep)#rs) t)" using rs_height rebalance_middle_tree_height by simp alsohave"… = height (Node (ls@(sub,sep)#rs) t)" using height_t_sub "2.prems" height_t_del by auto alsohave"… = height (Node ts t)" using2 a_split sep_n_x list_split Cons split_set(1) split_conc by auto finallyshow ?thesis using sep_n_x Cons a_split list_split 2 by simp next case sep_x_Leaf thenhave"height (Node ts t) = height (Node (ls@rs) t)" using bal_split_last(2) "2.prems"(3) a_split list_split Cons split_conc by metis thenshow ?thesis using a_split list_split Cons sep_x_Leaf 2by auto next case sep_x_Node thenobtain sts st where sub_node: "sub = Node sts st"by blast obtain sub_s max_s where sub_split: "split_max k sub = (sub_s, max_s)" by (cases "split_max k sub") thenhave"height sub_s = height t" by (metis "2.prems"(1) "2.prems"(2) "2.prems"(3) a_split bal.simps(2) btree.distinct(1) list_split Cons order_bal_nonempty_lasttreebal order_impl_root_order root_order.simps(2) some_child_sub(1) split_set(1) split_max_height sub_node) thenhave"height (rebalance_middle_tree k ls sub_s max_s rs t) = height (Node (ls@(sub_s,sep)#rs) t)" using rs_height rebalance_middle_tree_height by simp alsohave"… = height (Node ts t)" using2 a_split sep_x_Node list_split Cons split_set(1) ‹height sub_s = height t› by (auto simp add: split_conc[of ts]) finallyshow ?thesis using sep_x_Node Cons a_split list_split 2 sub_node sub_split by auto qed qed qed simp
(* proof for inorders *)
(* note: this works (as it should, since there is not even recursion involved)
automatically. *yay* *) lemma rebalance_middle_tree_inorder: assumes"height t = height sub" and"case rs of (rsub,rsep) # list ==> height rsub = height t | [] ==> True" shows"inorder (rebalance_middle_tree k ls sub sep rs t) = inorder (Node (ls@(sub,sep)#rs) t)" apply(cases sub; cases t) using assms apply (auto
split!: btree.splits upi.splits list.splits
simp del: nodei.simps
simp add: nodei_inorder_simps
) done
lemma rebalance_last_tree_inorder: assumes"height t = height sub" and"ts = list@[(sub,sep)]" shows"inorder (rebalance_last_tree k ts t) = inorder (Node ts t)" using rebalance_middle_tree_inorder assms by auto
lemma butlast_inorder_app_id: "xs = xs' @ [(sub,sep)] ==> inorder_list xs' @ inorder sub @ [sep] = inorder_list xs" by simp
lemma split_max_inorder: assumes"nonempty_lasttreebal t" and"t ≠ Leaf" shows"inorder_pair (split_max k t) = inorder t" using assms proof (induction k t rule: split_max.induct) case (1 k ts t) thenshow ?case proof (cases t) case Leaf thenhave"ts = butlast ts @ [last ts]" using"1.prems"(1) by auto moreoverobtain sub sep where"last ts = (sub,sep)" by fastforce ultimatelyshow ?thesis using Leaf apply (auto split!: prod.splits btree.splits) by (simp add: butlast_inorder_app_id) next case (Node tts tt) thenhave IH: "inorder_pair (split_max k t) = inorder t" using"1.IH""1.prems"(1) by auto obtain sub sep where split_sub_sep: "split_max k t = (sub,sep)" by fastforce thenhave height_sub: "height sub = height t" by (metis "1.prems"(1) Node btree.distinct(1) nonempty_lasttreebal.simps(2) split_max_height) have"inorder_pair (split_max k (Node ts t)) = inorder (rebalance_last_tree k ts sub) @ [sep]" using Node 1 split_sub_sep by auto alsohave"… = inorder_list ts @ inorder sub @ [sep]" using rebalance_last_tree_inorder height_sub "1.prems" by (auto simp del: rebalance_last_tree.simps) alsohave"… = inorder (Node ts t)" using IH split_sub_sep by simp finallyshow ?thesis . qed qed simp
lemma height_bal_subtrees_merge: "[height (Node as a) = height (Node bs b); bal (Node as a); bal (Node bs b)] ==>∀x ∈ set (subtrees as) ∪ {a}. height x = height b" by (metis Suc_inject Un_iff bal.simps(2) height_bal_tree singletonD)
lemma bal_list_merge: assumes"bal_upi (Upi (Node as a) x (Node bs b))" shows"bal (Node (as@(a,x)#bs) b)" proof - have"∀x∈set (subtrees (as @ (a, x) # bs)). bal x" using subtrees_split assms by auto moreoverhave"bal b" using assms by auto moreoverhave"∀x∈set (subtrees as) ∪ {a} ∪ set (subtrees bs). height x = height b" using assms height_bal_subtrees_merge unfolding bal_upi.simps by blast ultimatelyshow ?thesis by auto qed
lemma nodei_bal_upi: assumes"bal_upi (nodei k ts t)" shows"bal (Node ts t)" using assms proof(cases "length ts ≤ 2*k") case False thenobtain ls sub sep rs where split_list: "split_half ts = (ls, (sub,sep)#rs)" using nodei_casesby blast thenhave"nodei k ts t = Upi (Node ls sub) sep (Node rs t)" using False by auto moreoverhave"ts = ls@(sub,sep)#rs" by (metis append_take_drop_id fst_conv local.split_list snd_conv split_half.elims) ultimatelyshow ?thesis using bal_list_merge[of ls sub sep rs t] assms by (simp del: bal.simps bal_upi.simps) qed simp
lemma nodei_bal_simp: "bal_upi (nodei k ts t) = bal (Node ts t)" using nodei_bal nodei_bal_upiby blast
lemma rebalance_middle_tree_bal: "bal (Node (ls@(sub,sep)#rs) t) ==> bal (rebalance_middle_tree k ls sub sep rs t)" proof (cases t) case t_node: (Node tts tt) assume assms: "bal (Node (ls @ (sub, sep) # rs) t)" thenobtain mts mt where sub_node: "sub = Node mts mt" by (cases sub) (auto simp add: t_node) have sub_heights: "height sub = height t""bal sub""bal t" using assms by auto show ?thesis proof (cases "length mts ≥ k ∧ length tts ≥ k") case True thenshow ?thesis using t_node sub_node assms by (auto simp del: bal.simps) next case False thenshow ?thesis proof (cases rs) case Nil have"height_upi (nodei k (mts@(mt,sep)#tts) tt) = height (Node (mts@(mt,sep)#tts) tt)" using nodei_heightby blast alsohave"… = Suc (height tt)" by (metis height_bal_tree height_upi.simps(2) height_list_split max.idem sub_heights(1) sub_heights(3) sub_node t_node) alsohave"… = height t" using height_bal_tree sub_heights(3) t_node by fastforce finallyhave"height_upi (nodei k (mts@(mt,sep)#tts) tt) = height t"by simp moreoverhave"bal_upi (nodei k (mts@(mt,sep)#tts) tt)" by (metis bal_list_merge bal_upi.simps(2) nodei_bal sub_heights(1) sub_heights(2) sub_heights(3) sub_node t_node) ultimatelyshow ?thesis apply (cases "nodei k (mts@(mt,sep)#tts) tt") using assms Nil sub_node t_node by auto next case (Cons r rs) thenobtain rsub rsep where r_split: "r = (rsub,rsep)"by (cases r) thenhave rsub_height: "height rsub = height t""bal rsub" using assms Cons by auto thenobtain rts rt where r_node: "rsub = (Node rts rt)" apply(cases rsub) using t_node by simp have"height_upi (nodei k (mts@(mt,sep)#rts) rt) = height (Node (mts@(mt,sep)#rts) rt)" using nodei_heightby blast alsohave"… = Suc (height rt)" by (metis Un_iff ‹height rsub = height t› assms bal.simps(2) bal_split_last(1) height_bal_tree height_upi.simps(2) height_list_split list.set_intros(1) Cons max.idem r_node r_split set_append some_child_sub(1) sub_heights(1) sub_node) alsohave"… = height rsub" using height_bal_tree r_node rsub_height(2) by fastforce finallyhave1: "height_upi (nodei k (mts@(mt,sep)#rts) rt) = height rsub" . moreoverhave2: "bal_upi (nodei k (mts@(mt,sep)#rts) rt)" by (metis bal_list_merge bal_upi.simps(2) nodei_bal r_node rsub_height(1) rsub_height(2) sub_heights(1) sub_heights(2) sub_node) ultimatelyshow ?thesis proof (cases "nodei k (mts@(mt,sep)#rts) rt") case (Ti u) thenhave"bal (Node (ls@(u,rsep)#rs) t)" using12 Cons assms t_node subtrees_split sub_heights r_split rsub_height unfolding bal.simps by (auto simp del: height_btree.simps) thenshow ?thesis using Cons assms t_node sub_node r_split r_node False Ti by (auto simp del: nodei.simps bal.simps) next case (Upi l a r) thenhave"bal (Node (ls@(l,a)#(r,rsep)#rs) t)" using12 Cons assms t_node subtrees_split sub_heights r_split rsub_height unfolding bal.simps by (auto simp del: height_btree.simps) thenshow ?thesis using Cons assms t_node sub_node r_split r_node False Upi by (auto simp del: nodei.simps bal.simps) qed qed qed qed (simp add: height_Leaf)
lemma rebalance_last_tree_bal: "[bal (Node ts t); ts ≠ []]==> bal (rebalance_last_tree k ts t)" using rebalance_middle_tree_bal append_butlast_last_id[of ts] apply(cases "last ts") apply(auto simp del: bal.simps rebalance_middle_tree.simps) done
lemma split_max_bal: assumes"bal t" and"t ≠ Leaf" and"nonempty_lasttreebal t" shows"bal (fst (split_max k t))" using assms proof(induction k t rule: split_max.induct) case (1 k ts t) thenshow ?case proof (cases t) case Leaf thenobtain sub sep where last_split: "last ts = (sub,sep)" using1by auto thenhave"height sub = height t"using1by auto thenhave"bal (Node (butlast ts) sub)"using1 last_split by auto thenshow ?thesis using1 Leaf last_split by auto next case (Node tts tt) thenobtain sub sep where t_split: "split_max k t = (sub,sep)"by (cases "split_max k t") thenhave"height sub = height t"using1 Node by (metis btree.distinct(1) nonempty_lasttreebal.simps(2) split_max_height) moreoverhave"bal sub" using"1.IH""1.prems"(1) "1.prems"(3) Node t_split by fastforce ultimatelyhave"bal (Node ts sub)" using1 t_split Node by auto thenshow ?thesis using rebalance_last_tree_bal t_split Node 1 by (auto simp del: bal.simps rebalance_middle_tree.simps) qed qed simp
lemma del_bal: assumes"k > 0" and"root_order k t" and"bal t" shows"bal (del k x t)" using assms proof(induction k x t rule: del.induct) case (2 k x ts t) thenobtain ls rs where list_split: "split ts x = (ls,rs)" by (cases "split ts x") thenshow ?case proof (cases rs) case Nil thenhave"bal (del k x t)"using2 list_split by (simp add: order_impl_root_order) moreoverhave"height (del k x t) = height t" using2 del_height by (simp add: order_impl_root_order) moreoverhave"ts ≠ []"using2by auto ultimatelyhave"bal (rebalance_last_tree k ts (del k x t))" using2 Nil order_bal_nonempty_lasttreebal rebalance_last_tree_bal by simp thenhave"bal (rebalance_last_tree k ls (del k x t))" using list_split split_conc Nil by fastforce thenshow ?thesis using2 list_split Nil by auto next case (Cons r rs) thenobtain sub sep where r_split: "r = (sub,sep)"by (cases r) thenhave sub_height: "height sub = height t""bal sub" using2 Cons list_split split_set(1) by fastforce+
consider (sep_n_x) "sep ≠ x" |
(sep_x_Leaf) "sep = x ∧ sub = Leaf" |
(sep_x_Node) "sep = x ∧ (∃ts t. sub = Node ts t)" using btree.exhaust by blast thenshow ?thesis proof cases case sep_n_x thenhave"bal (del k x sub)""height (del k x sub) = height sub"using sub_height apply (metis "2.IH"(2) "2.prems"(1) "2.prems"(2) list_split local.Cons order_impl_root_order r_split root_order.simps(2) some_child_sub(1) split_set(1)) by (metis "2.prems"(1) "2.prems"(2) list_split Cons order_impl_root_order r_split root_order.simps(2) some_child_sub(1) del_height split_set(1) sub_height(2)) moreoverhave"bal (Node (ls@(sub,sep)#rs) t)" using"2.prems"(3) list_split Cons r_split split_conc by blast ultimatelyhave"bal (Node (ls@(del k x sub,sep)#rs) t)" using bal_substitute_subtree[of ls sub sep rs t "del k x sub"] by metis thenhave"bal (rebalance_middle_tree k ls (del k x sub) sep rs t)" using rebalance_middle_tree_bal[of ls "del k x sub" sep rs t k] by metis thenshow ?thesis using2 list_split Cons r_split sep_n_x by auto next case sep_x_Leaf moreoverhave"bal (Node (ls@rs) t)" using bal_split_last(1) list_split split_conc r_split by (metis "2.prems"(3) Cons) ultimatelyshow ?thesis using2 list_split Cons r_split by auto next case sep_x_Node thenobtain sts st where sub_node: "sub = Node sts st"by auto thenobtain sub_s max_s where sub_split: "split_max k sub = (sub_s, max_s)" by (cases "split_max k sub") thenhave"height sub_s = height sub" using split_max_height by (metis "2.prems"(1) "2.prems"(2) btree.distinct(1) list_split Cons order_bal_nonempty_lasttreebal order_impl_root_order r_split root_order.simps(2) some_child_sub(1) split_set(1) sub_height(2) sub_node) moreoverhave"bal sub_s" using split_max_bal by (metis "2.prems"(1) "2.prems"(2) btree.distinct(1) fst_conv list_split local.Cons order_bal_nonempty_lasttreebal order_impl_root_order r_split root_order.simps(2) some_child_sub(1) split_set(1) sub_height(2) sub_node sub_split) moreoverhave"bal (Node (ls@(sub,sep)#rs) t)" using"2.prems"(3) list_split Cons r_split split_conc by blast ultimatelyhave"bal (Node (ls@(sub_s,sep)#rs) t)" using bal_substitute_subtree[of ls sub sep rs t "sub_s"] by metis thenhave"bal (Node (ls@(sub_s,max_s)#rs) t)" using bal_substitute_separator by metis thenhave"bal (rebalance_middle_tree k ls sub_s max_s rs t)" using rebalance_middle_tree_bal[of ls sub_s max_s rs t k] by metis thenshow ?thesis using2 list_split Cons r_split sep_x_Node sub_node sub_split by auto qed qed qed simp
lemma rebalance_middle_tree_order: assumes"almost_order k sub" and"∀s ∈ set (subtrees (ls@rs)). order k s""order k t" and"case rs of (rsub,rsep) # list ==> height rsub = height t | [] ==> True" and"length (ls@(sub,sep)#rs) ≤ 2*k" and"height sub = height t" shows"almost_order k (rebalance_middle_tree k ls sub sep rs t)" proof(cases t) case Leaf thenhave"sub = Leaf"using height_Leaf assms by auto thenshow ?thesis using Leaf assms by auto next case t_node: (Node tts tt) thenobtain mts mt where sub_node: "sub = Node mts mt" using assms by (cases sub) (auto) thenshow ?thesis proof(cases "length mts ≥ k ∧ length tts ≥ k") case True thenhave"order k sub"using assms by (simp add: sub_node) thenshow ?thesis using True t_node sub_node assms by auto next case False thenshow ?thesis proof (cases rs) case Nil have"order_upi k (nodei k (mts@(mt,sep)#tts) tt)" using nodei_order[of k "mts@(mt,sep)#tts" tt] assms(1,3) t_node sub_node by (auto simp del: order_upi.simps nodei.simps) thenshow ?thesis apply(cases "nodei k (mts@(mt,sep)#tts) tt") using assms t_node sub_node False Nil apply (auto simp del: nodei.simps) done next case (Cons r rs) thenobtain rsub rsep where r_split: "r = (rsub,rsep)"by (cases r) thenhave rsub_height: "height rsub = height t" using assms Cons by auto thenobtain rts rt where r_node: "rsub = (Node rts rt)" apply(cases rsub) using t_node by simp have"order_upi k (nodei k (mts@(mt,sep)#rts) rt)" using nodei_order[of k "mts@(mt,sep)#rts" rt] assms(1,2) t_node sub_node r_node r_split Cons by (auto simp del: order_upi.simps nodei.simps) thenshow ?thesis apply(cases "nodei k (mts@(mt,sep)#rts) rt") using assms t_node sub_node False Cons r_split r_node apply (auto simp del: nodei.simps) done qed qed qed
(* we have to proof the order invariant once for an underflowing last tree *) lemma rebalance_middle_tree_last_order: assumes"almost_order k t" and"∀s ∈ set (subtrees (ls@(sub,sep)#rs)). order k s" and"rs = []" and"length (ls@(sub,sep)#rs) ≤ 2*k" and"height sub = height t" shows"almost_order k (rebalance_middle_tree k ls sub sep rs t)" proof (cases t) case Leaf thenhave"sub = Leaf"using height_Leaf assms by auto thenshow ?thesis using Leaf assms by auto next case t_node: (Node tts tt) thenobtain mts mt where sub_node: "sub = Node mts mt" using assms by (cases sub) (auto) thenshow ?thesis proof(cases "length mts ≥ k ∧ length tts ≥ k") case True thenhave"order k sub"using assms by (simp add: sub_node) thenshow ?thesis using True t_node sub_node assms by auto next case False have"order_upi k (nodei k (mts@(mt,sep)#tts) tt)" using nodei_order[of k "mts@(mt,sep)#tts" tt] assms t_node sub_node by (auto simp del: order_upi.simps nodei.simps) thenshow ?thesis apply(cases "nodei k (mts@(mt,sep)#tts) tt") using assms t_node sub_node False Nil apply (auto simp del: nodei.simps) done qed qed
lemma rebalance_last_tree_order: assumes"ts = ls@[(sub,sep)]" and"∀s ∈ set (subtrees (ts)). order k s""almost_order k t" and"length ts ≤ 2*k" and"height sub = height t" shows"almost_order k (rebalance_last_tree k ts t)" using rebalance_middle_tree_last_order assms by auto
lemma split_max_order: assumes"order k t" and"t ≠ Leaf" and"nonempty_lasttreebal t" shows"almost_order k (fst (split_max k t))" using assms proof(induction k t rule: split_max.induct) case (1 k ts t) thenobtain ls sub sep where ts_not_empty: "ts = ls@[(sub,sep)]" by auto thenshow ?case proof (cases t) case Leaf thenshow ?thesis using ts_not_empty 1by auto next case (Node) thenobtain s_sub s_max where sub_split: "split_max k t = (s_sub, s_max)" by (cases "split_max k t") moreoverhave"height sub = height s_sub" by (metis "1.prems"(3) Node Pair_inject append1_eq_conv btree.distinct(1) nonempty_lasttreebal.simps(2) split_max_height sub_split ts_not_empty) ultimatelyhave"almost_order k (rebalance_last_tree k ts s_sub)" using rebalance_last_tree_order[of ts ls sub sep k s_sub] 1 ts_not_empty Node sub_split by force thenshow ?thesis using Node 1 sub_split by auto qed qed simp
lemma del_order: assumes"k > 0" and"root_order k t" and"bal t" shows"almost_order k (del k x t)" using assms proof (induction k x t rule: del.induct) case (2 k x ts t) thenobtain ls list where list_split: "split ts x = (ls, list)"by (cases "split ts x") thenshow ?case proof (cases list) case Nil thenhave"almost_order k (del k x t)"using2 list_split by (simp add: order_impl_root_order) moreoverobtain lls lsub lsep where ls_split: "ls = lls@[(lsub,lsep)]" using2 Nil list_split by (metis append_Nil2 nonempty_lasttreebal.simps(2) order_bal_nonempty_lasttreebal split_conc) moreoverhave"height t = height (del k x t)"using del_height 2 by (simp add: order_impl_root_order) moreoverhave"length ls = length ts" using Nil list_split by (auto dest: split_length) ultimatelyhave"almost_order k (rebalance_last_tree k ls (del k x t))" using rebalance_last_tree_order[of ls lls lsub lsep k "del k x t"] by (metis "2.prems"(2) "2.prems"(3) Un_iff append_Nil2 bal.simps(2) list_split Nil root_order.simps(2) singletonI split_conc subtrees_split) thenshow ?thesis using2 list_split Nil by auto next case (Cons r rs)
from Cons obtain sub sep where r_split: "r = (sub,sep)"by (cases r)
have inductive_help: "case rs of [] ==> True | (rsub,rsep)#_ ==> height rsub = height t" "∀s∈set (subtrees (ls @ rs)). order k s" "Suc (length (ls @ rs)) ≤ 2 * k" "order k t" using Cons r_split "2.prems" list_split split_set by (auto dest: split_conc split!: list.splits)
consider (sep_n_x) "sep ≠ x" |
(sep_x_Leaf) "sep = x ∧ sub = Leaf" |
(sep_x_Node) "sep = x ∧ (∃ts t. sub = Node ts t)" using btree.exhaust by blast thenshow ?thesis proof cases case sep_n_x thenhave"almost_order k (del k x sub)"using2 list_split Cons r_split order_impl_root_order by (metis bal.simps(2) root_order.simps(2) some_child_sub(1) split_set(1)) moreoverhave"height (del k x sub) = height t" by (metis "2.prems"(1) "2.prems"(2) "2.prems"(3) bal.simps(2) list_split Cons order_impl_root_order r_split root_order.simps(2) some_child_sub(1) del_height split_set(1)) ultimatelyhave"almost_order k (rebalance_middle_tree k ls (del k x sub) sep rs t)" using rebalance_middle_tree_order[of k "del k x sub" ls rs t sep] using inductive_help using Cons r_split sep_n_x list_split by auto thenshow ?thesis using2 Cons r_split sep_n_x list_split by auto next case sep_x_Leaf thenhave"almost_order k (Node (ls@rs) t)"using inductive_help by auto thenshow ?thesis using2 Cons r_split sep_x_Leaf list_split by auto next case sep_x_Node thenobtain sts st where sub_node: "sub = Node sts st"by auto thenobtain sub_s max_s where sub_split: "split_max k sub = (sub_s, max_s)" by (cases "split_max k sub") thenhave"height sub_s = height t"using split_max_height by (metis "2.prems"(1) "2.prems"(2) "2.prems"(3) bal.simps(2) btree.distinct(1) list_split Cons order_bal_nonempty_lasttreebal order_impl_root_order r_split root_order.simps(2) some_child_sub(1) split_set(1) sub_node) moreoverhave"almost_order k sub_s"using split_max_order by (metis "2.prems"(1) "2.prems"(2) "2.prems"(3) bal.simps(2) btree.distinct(1) fst_conv list_split local.Cons order_bal_nonempty_lasttreebal order_impl_root_order r_split root_order.simps(2) some_child_sub(1) split_set(1) sub_node sub_split) ultimatelyhave"almost_order k (rebalance_middle_tree k ls sub_s max_s rs t)" using rebalance_middle_tree_order[of k sub_s ls rs t max_s] inductive_help by auto thenshow ?thesis using2 Cons r_split list_split sep_x_Node sub_split by auto qed qed qed simp
(* sortedness of delete by inorder *) (* generalize del_list_sorted since its cumbersome to express inorder_list ts as xs @ [a] notethattheproofschemeisalmostidenticaltoins_list_sorted
*) thm del_list_sorted
lemma del_list_split: assumes"split ts x = (ls, rs)" and"sorted_less (inorder (Node ts t))" shows"del_list x (inorder (Node ts t)) = inorder_list ls @ del_list x (inorder_list rs @ inorder t)" proof (cases ls) case Nil thenshow ?thesis using assms by (auto dest!: split_conc) next case Cons thenobtain ls' sub sep where ls_tail_split: "ls = ls' @ [(sub,sep)]" by (metis list.distinct(1) rev_exhaust surj_pair) moreoverhave"sep < x" using split_req(2)[of ts x ls' sub sep rs] using assms(1) assms(2) ls_tail_split sorted_inorder_separators by blast moreoverhave"sorted_less (inorder_list ls)" using assms sorted_wrt_append split_conc by fastforce ultimatelyshow ?thesis using assms(2) split_conc[OF assms(1)] using del_list_sorted[of "inorder_list ls' @ inorder sub" sep] by auto qed
(* del sorted requires sortedness of the full list so we need to change the right specialization a bit *)
lemma del_list_split_right: assumes"split ts x = (ls, (sub,sep)#rs)" and"sorted_less (inorder (Node ts t))" and"sep ≠ x" shows"del_list x (inorder_list ((sub,sep)#rs) @ inorder t) = del_list x (inorder sub) @ sep # inorder_list rs @ inorder t" proof - from assms have"x < sep" proof - from assms have"sorted_less (separators ts)" using sorted_inorder_separators by blast thenshow ?thesis using split_req(3) using assms by fastforce qed moreoverhave"sorted_less (inorder sub @ sep # inorder_list rs @ inorder t)" using assms sorted_wrt_append[where xs="inorder_list ls"] by (auto dest!: split_conc) ultimatelyshow ?thesis using del_list_sorted[of "inorder sub""sep"] by auto qed
thm del_list_idem
lemma del_inorder: assumes"k > 0" and"root_order k t" and"bal t" and"sorted_less (inorder t)" shows"inorder (del k x t) = del_list x (inorder t)" using assms proof (induction k x t rule: del.induct) case (2 k x ts t) thenobtain ls rs where list_split: "split ts x = (ls, rs)" by (meson surj_pair) thenhave list_conc: "ts = ls @ rs" using split.split_conc split_axioms by blast show ?case proof (cases rs) case Nil thenhave IH: "inorder (del k x t) = del_list x (inorder t)" by (metis "2.IH"(1) "2.prems" bal.simps(2) list_split order_impl_root_order root_order.simps(2) sorted_inorder_induct_last) have"inorder (del k x (Node ts t)) = inorder (rebalance_last_tree k ts (del k x t))" using list_split Nil list_conc by auto alsohave"… = inorder_list ts @ inorder (del k x t)" proof - obtain ts' sub sep where ts_split: "ts = ts' @ [(sub, sep)]" by (meson "2.prems"(1) "2.prems"(2) "2.prems"(3) nonempty_lasttreebal.simps(2) order_bal_nonempty_lasttreebal) thenhave"height sub = height t" using"2.prems"(3) by auto moreoverhave"height t = height (del k x t)" by (metis "2.prems"(1) "2.prems"(2) "2.prems"(3) bal.simps(2) del_height order_impl_root_order root_order.simps(2)) ultimatelyshow ?thesis using rebalance_last_tree_inorder using ts_split by auto qed alsohave"… = inorder_list ts @ del_list x (inorder t)" using IH by blast alsohave"… = del_list x (inorder (Node ts t))" using"2.prems"(4) list_conc list_split Nil del_list_split by auto finallyshow ?thesis . next case (Cons h rs) thenobtain sub sep where h_split: "h = (sub,sep)" by (cases h) thenhave node_sorted_split: "sorted_less (inorder (Node (ls@(sub,sep)#rs) t))" "root_order k (Node (ls@(sub,sep)#rs) t)" "bal (Node (ls@(sub,sep)#rs) t)" using"2.prems" h_split list_conc Cons by blast+
consider (sep_n_x) "sep ≠ x" | (sep_x_Leaf) "sep = x ∧ sub = Leaf" | (sep_x_Node) "sep = x ∧ (∃ts t. sub = Node ts t)" using btree.exhaust by blast thenshow ?thesis proof cases case sep_n_x thenhave IH: "inorder (del k x sub) = del_list x (inorder sub)" by (metis "2.IH"(2) "2.prems"(1) "2.prems"(2) bal.simps(2) bal_split_left(1) h_split list_split local.Cons node_sorted_split(1) node_sorted_split(3) order_impl_root_order root_order.simps(2) some_child_sub(1) sorted_inorder_induct_subtree split_set(1)) from sep_n_x have"inorder (del k x (Node ts t)) = inorder (rebalance_middle_tree k ls (del k x sub) sep rs t)" using list_split Cons h_split by auto alsohave"… = inorder (Node (ls@(del k x sub, sep)#rs) t)" proof - have"height t = height (del k x sub)" using del_height using order_impl_root_order "2.prems" by (auto simp add: order_impl_root_order Cons list_conc h_split) moreoverhave"case rs of [] ==> True | (rsub, rsep) # list ==> height rsub = height t" using"2.prems"(3) bal_sub_height list_conc Cons by blast ultimatelyshow ?thesis using rebalance_middle_tree_inorder by simp qed alsohave"… = inorder_list ls @ del_list x (inorder sub) @ sep # inorder_list rs @ inorder t" using IH by simp alsohave"… = del_list x (inorder (Node ts t))" using del_list_split[of ts x ls "(sub,sep)#rs" t] using del_list_split_right[of ts x ls sub sep rs t] using list_split list_conc h_split Cons "2.prems"(4) sep_n_x by auto finallyshow ?thesis . next case sep_x_Leaf thenhave"del_list x (inorder (Node ts t)) = inorder (Node (ls@rs) t)" using list_conc h_split Cons using del_list_split[OF list_split "2.prems"(4)] by simp alsohave"… = inorder (del k x (Node ts t))" using list_split sep_x_Leaf list_conc h_split Cons by auto finallyshow ?thesis by simp next case sep_x_Node obtain ssub ssep where split_split: "split_max k sub = (ssub, ssep)" by fastforce from sep_x_Node have"x = sep" by simp thenhave"del_list x (inorder (Node ts t)) = inorder_list ls @ inorder sub @ inorder_list rs @ inorder t" using list_split list_conc h_split Cons "2.prems"(4) using del_list_split[OF list_split "2.prems"(4)] using del_list_sorted1[of "inorder sub" sep "inorder_list rs @ inorder t" x]
sorted_wrt_append by auto alsohave"… = inorder_list ls @ inorder_pair (split_max k sub) @ inorder_list rs @ inorder t" using sym[OF split_max_inorder[of sub k]] using order_bal_nonempty_lasttreebal[of k sub] "2.prems"
list_conc h_split Cons sep_x_Node by (auto simp del: split_max.simps simp add: order_impl_root_order) alsohave"… = inorder_list ls @ inorder ssub @ ssep # inorder_list rs @ inorder t" using split_split by auto alsohave"… = inorder (rebalance_middle_tree k ls ssub ssep rs t)" proof - have"height t = height ssub" using split_max_height by (metis "2.prems"(1,2,3) bal.simps(2) btree.distinct(1) h_split list_split local.Cons order_bal_nonempty_lasttreebal order_impl_root_order root_order.simps(2) sep_x_Node some_child_sub(1) split_set(1) split_split) moreoverhave"case rs of [] ==> True | (rsub, rsep) # list ==> height rsub = height t" using"2.prems"(3) bal_sub_height list_conc local.Cons by blast ultimatelyshow ?thesis using rebalance_middle_tree_inorder by auto qed alsohave"… = inorder (del k x (Node ts t))" using list_split sep_x_Node list_conc h_split Cons split_split by auto finallyshow ?thesis by simp qed qed qed auto
lemma delete_order: "[k > 0; bal t; root_order k t]==> root_order k (delete k x t)" using del_order by (simp add: reduce_root_order)
lemma delete_bal: "[k > 0; bal t; root_order k t]==> bal (delete k x t)" using del_bal by (simp add: reduce_root_bal)
lemma delete_inorder: "[k > 0; bal t; root_order k t; sorted_less (inorder t)]==> inorder (delete k x t) = del_list x (inorder t)" using del_inorder by (simp add: reduce_root_inorder)
(* TODO (opt) runtime wrt runtime of split *)
(* we are interested in a) number of comparisons b) number of fetches c) number of writes *) (* a) is dependent on t_split, the remainder is not (we assume the number of fetches and writes
for split fun is 0 *)
(* TODO simpler induction schemes /less boilerplate isabelle/src/HOL/ex/Induction_Schema *)
subsection"Set specification by inorder"
interpretation S_ordered: Set_by_Ordered where
empty = empty_btree and
insert = "insert (Suc k)"and
delete = "delete (Suc k)"and
isin = "isin"and
inorder = "inorder"and
inv = "invar_inorder (Suc k)" proof (standard, goal_cases) case (2 s x) thenshow ?case by (simp add: isin_set_inorder) next case (3 s x) thenshow ?caseusing insert_inorder by simp next case (4 s x) thenshow ?caseusing delete_inorder by auto next case (6 s x) thenshow ?caseusing insert_order insert_bal by auto next case (7 s x) thenshow ?caseusing delete_order delete_bal by auto qed (simp add: empty_btree_def)+
(* if we remove this, it is not possible to remove the simp rules in subsequent contexts... *) declare nodei.simps[simp del]
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.