diff --git a/metadata/entries/BTree.toml b/metadata/entries/BTree.toml --- a/metadata/entries/BTree.toml +++ b/metadata/entries/BTree.toml @@ -1,42 +1,49 @@ title = "A Verified Imperative Implementation of B-Trees" date = 2021-02-24 topics = [ "Computer science/Data structures", ] abstract = """ In this work, we use the interactive theorem prover Isabelle/HOL to verify an imperative implementation of the classical B-tree data structure invented by Bayer and McCreight [ACM 1970]. The -implementation supports set membership, insertion and deletion queries with -efficient binary search for intra-node navigation. This is +implementation supports set membership, insertion, deletion, iteration and range queries with efficient binary search for intra-node navigation. This is accomplished by first specifying the structure abstractly in the functional modeling language HOL and proving functional correctness. Using manual refinement, we derive an imperative implementation in Imperative/HOL. We show the validity of this refinement using the separation logic utilities from the Isabelle Refinement Framework . The code can be exported to -the programming languages SML, OCaml and Scala. We examine the runtime of all -operations indirectly by reproducing results of the logarithmic -relationship between height and the number of nodes. The results are -discussed in greater detail in the corresponding +
B-Trees
+
This formalisation is discussed in greater detail in the corresponding Bachelor's -Thesis.""" +Thesis.
+
B+-Trees:
+
This formalisation also supports range queries and is discussed in a paper published at ICTAC 2022.
+ + +Change history: +[2022-08-16]: Added formalisations of B+-Trees +""" license = "bsd" note = "" [authors] [authors.muendler] email = "muendler_email" [contributors] [notify] muendler = "muendler_email" [history] [extra] [related] diff --git a/thys/BTree/Array_SBlit.thy b/thys/BTree/Array_SBlit.thy --- a/thys/BTree/Array_SBlit.thy +++ b/thys/BTree/Array_SBlit.thy @@ -1,305 +1,305 @@ theory Array_SBlit imports "Separation_Logic_Imperative_HOL.Array_Blit" begin (* Resolves TODO by Peter Lammich *) (* OCaml handles the case of len=0 correctly (i.e. as specified by the Hoare Triple in Array_Blit -not generating an exception if si+len \ array length and such) *) +not generating an exception if si+len \ array length and such) *) code_printing code_module "array_blit" \ (OCaml) \ - let array_blit src si dst di len = ( - if src=dst then - raise (Invalid_argument "array_blit: Same arrays") - else - Array.blit src (Z.to_int si) dst (Z.to_int di) (Z.to_int len) - ) +let array_blit src si dst di len = ( + if src=dst then + raise (Invalid_argument "array_blit: Same arrays") + else + Array.blit src (Z.to_int si) dst (Z.to_int di) (Z.to_int len) +);; \ code_printing constant blit' \ - (OCaml) "(fun () -> /array'_blit _ _ _ _ _)" + (OCaml) "(fun () -> /array'_blit _ _ _ _ _)" export_code blit checking OCaml section "Same array Blit" text "The standard framework already provides a function to copy array elements." term blit thm blit_rule thm blit.simps (* Same array BLIT *) definition "sblit a s d l \ blit a s a d l" text "When copying values within arrays, blit only works for moving elements to the left." lemma sblit_rule[sep_heap_rules]: assumes LEN: "si+len \ length lsrc" and DST_SM: "di \ si" shows "< src \\<^sub>a lsrc > sblit src si di len <\_. src \\<^sub>a (take di lsrc @ take len (drop si lsrc) @ drop (di+len) lsrc) >" unfolding sblit_def using LEN DST_SM proof (induction len arbitrary: lsrc si di) case 0 thus ?case by sep_auto next - case (Suc len) - note [sep_heap_rules] = Suc.IH + case (Suc len) + note [sep_heap_rules] = Suc.IH have [simp]: "\x. lsrc ! si # take len (drop (Suc si) lsrc) @ x = take (Suc len) (drop si lsrc) @ x" apply simp by (metis Suc.prems(1) add_Suc_right Cons_nth_drop_Suc - less_Suc_eq_le add.commute not_less_eq take_Suc_Cons + less_Suc_eq_le add.commute not_less_eq take_Suc_Cons Nat.trans_le_add2) from Suc.prems show ?case by (sep_auto simp: take_update_last drop_upd_irrelevant) qed subsection "A reverse blit" text "The function rblit may be used to copy elements a defined offset to the right" (* Right BLIT or Reverse BLIT *) primrec rblit :: "_ array \ nat \ _ array \ nat \ nat \ unit Heap" where "rblit _ _ _ _ 0 = return ()" | "rblit src si dst di (Suc l) = do { x \ Array.nth src (si+l); Array.upd (di+l) x dst; rblit src si dst di l }" text "For separated arrays it is equivalent to normal blit. The proof follows similarly to the corresponding proof for blit." lemma rblit_rule[sep_heap_rules]: assumes LEN: "si+len \ length lsrc" "di+len \ length ldst" shows - "< src \\<^sub>a lsrc + "< src \\<^sub>a lsrc * dst \\<^sub>a ldst > rblit src si dst di len - <\_. src \\<^sub>a lsrc + <\_. src \\<^sub>a lsrc * dst \\<^sub>a (take di ldst @ take len (drop si lsrc) @ drop (di+len) ldst) >" using LEN proof (induction len arbitrary: ldst) case 0 thus ?case by sep_auto next - case (Suc len) + case (Suc len) note [sep_heap_rules] = Suc.IH have [simp]: "drop (di + len) (ldst[di + len := lsrc ! (si + len)]) = lsrc ! (si + len) # drop (Suc (di + len)) ldst" by (metis Cons_nth_drop_Suc Suc.prems(2) Suc_le_eq add_Suc_right drop_upd_irrelevant length_list_update lessI nth_list_update_eq) have "take len (drop si lsrc) @ [lsrc ! (si + len)] = take (Suc len) (drop si lsrc)" proof - have "len < length (drop si lsrc)" using Suc.prems(1) by force then show "take len (drop si lsrc) @ [lsrc ! (si + len)] = take (Suc len) (drop si lsrc)" by (metis (no_types) Suc.prems(1) add_leD1 nth_drop take_Suc_conv_app_nth) qed then have [simp]: "\x. take len (drop si lsrc) @ lsrc ! (si + len) # x = take (Suc len) (drop si lsrc) @ x" by simp from Suc.prems show ?case by (sep_auto simp: take_update_last drop_upd_irrelevant) qed definition "srblit a s d l \ rblit a s a d l" text "However, within arrays we can now copy to the right." lemma srblit_rule[sep_heap_rules]: assumes LEN: "di+len \ length lsrc" and DST_GR: "di \ si" shows "< src \\<^sub>a lsrc > srblit src si di len <\_. src \\<^sub>a (take di lsrc @ take len (drop si lsrc) @ drop (di+len) lsrc) >" unfolding srblit_def using LEN DST_GR proof (induction len arbitrary: lsrc si di) case 0 thus ?case by sep_auto next - case (Suc len) + case (Suc len) note [sep_heap_rules] = Suc.IH have[simp]: "take len (drop si (lsrc[di + len := lsrc ! (si + len)])) = take len (drop si lsrc)" by (metis Suc.prems(2) ab_semigroup_add_class.add.commute add_le_cancel_right take_drop take_update_cancel) have [simp]: "drop (di + len) (lsrc[di + len := lsrc ! (si + len)]) = lsrc ! (si+len) # drop (Suc di + len) lsrc" by (metis Suc.prems(1) add_Suc_right add_Suc_shift add_less_cancel_left append_take_drop_id le_imp_less_Suc le_refl plus_1_eq_Suc same_append_eq take_update_cancel upd_conv_take_nth_drop) have "take len (drop si lsrc) @ [lsrc ! (si + len)] = take (Suc len) (drop si lsrc)" proof - have "len < length lsrc - si" using Suc.prems(1) Suc.prems(2) by linarith then show ?thesis by (metis (no_types) Suc.prems(1) Suc.prems(2) add_leD1 le_add_diff_inverse length_drop nth_drop take_Suc_conv_app_nth) qed then have [simp]: "\x. take len (drop si lsrc) @ lsrc ! (si + len) # x = take (Suc len) (drop si lsrc) @ x" by simp from Suc.prems show ?case by (sep_auto simp: take_update_last drop_upd_irrelevant) qed subsection "Modeling target language blit" text "For convenience, a function that is oblivious to the direction of the shift is defined." -definition "safe_sblit a s d l \ +definition "safe_sblit a s d l \ if s > d then sblit a s d l else srblit a s d l " text "We obtain a heap rule similar to the one of blit, but for copying within one array." lemma safe_sblit_rule[sep_heap_rules]: assumes LEN: "len > 0 \ di+len \ length lsrc \ si+len \ length lsrc" shows "< src \\<^sub>a lsrc > safe_sblit src si di len <\_. src \\<^sub>a (take di lsrc @ take len (drop si lsrc) @ drop (di+len) lsrc) >" unfolding safe_sblit_def using LEN apply(cases len) apply(sep_auto simp add: sblit_def srblit_def)[] apply sep_auto done (* Compare this to blit_rule *) thm blit_rule thm safe_sblit_rule subsection "Code Generator Setup" text "Note that the requirement for correctness is even weaker here than in SML/OCaml. In particular, if the length of the slice to copy is equal to 0, we will never throw an exception. We therefore manually handle this case, where nothing happens at all." code_printing code_module "array_sblit" \ (SML) \ fun array_sblit src si di len = ( if len > 0 then ArraySlice.copy { di = IntInf.toInt di, src = ArraySlice.slice (src,IntInf.toInt si,SOME (IntInf.toInt len)), dst = src} else () ) \ code_printing code_module "array_sblit" \ (OCaml) \ - let array_sblit src si di len = ( - if len > Z.zero then - (Array.blit src (Z.to_int si) src (Z.to_int di) (Z.to_int len)) - else () - ) +let array_sblit src si di len = ( + if len > Z.zero then + (Array.blit src (Z.to_int si) src (Z.to_int di) (Z.to_int len)) + else () +);; \ definition safe_sblit' where - [code del]: "safe_sblit' src si di len - = safe_sblit src (nat_of_integer si) (nat_of_integer di) + [code del]: "safe_sblit' src si di len + = safe_sblit src (nat_of_integer si) (nat_of_integer di) (nat_of_integer len)" lemma [code]: - "safe_sblit src si di len - = safe_sblit' src (integer_of_nat si) (integer_of_nat di) + "safe_sblit src si di len + = safe_sblit' src (integer_of_nat si) (integer_of_nat di) (integer_of_nat len)" by (simp add: safe_sblit'_def) (* TODO: Export to other languages: Haskell *) code_printing constant safe_sblit' \ (SML) "(fn/ ()/ => /array'_sblit _ _ _ _)" and (Scala) "{ ('_: Unit)/=>/ def safescopy(src: Array['_], srci: Int, dsti: Int, len: Int) = { if (len > 0) System.arraycopy(src, srci, src, dsti, len) else () } safescopy(_.array,_.toInt,_.toInt,_.toInt) }" code_printing constant safe_sblit' \ - (OCaml) "(fun () -> /array'_sblit _ _ _ _)" + (OCaml) "(fun () -> /array'_sblit _ _ _ _)" export_code safe_sblit checking SML Scala OCaml subsection "Derived operations" definition array_shr where "array_shr a i k \ do { l \ Array.len a; safe_sblit a i (i+k) (l-(i+k)) }" find_theorems "Array.len" lemma array_shr_rule[sep_heap_rules]: "< src \\<^sub>a lsrc > array_shr src i k <\_. src \\<^sub>a (take (i+k) lsrc @ take (length lsrc - (i+k)) (drop i lsrc)) >" unfolding array_shr_def by sep_auto lemma array_shr_rule_alt: "< src \\<^sub>a lsrc > array_shr src i k <\_. src \\<^sub>a (take (length lsrc) (take (i+k) lsrc @ (drop i lsrc))) >" by (sep_auto simp add: min_def) definition array_shl where "array_shl a i k \ do { l \ Array.len a; safe_sblit a i (i-k) (l-i) } " lemma array_shl_rule[sep_heap_rules]: " < src \\<^sub>a lsrc > array_shl src i k <\_. src \\<^sub>a (take (i-k) lsrc @ (drop i lsrc) @ drop (i - k + (length lsrc - i)) lsrc) >" unfolding array_shl_def by sep_auto lemma array_shl_rule_alt: " \i \ length lsrc; k \ i\ \ < src \\<^sub>a lsrc > array_shl src i k <\_. src \\<^sub>a (take (i-k) lsrc @ (drop i lsrc) @ drop (length lsrc - k) lsrc) >" by sep_auto end \ No newline at end of file diff --git a/thys/BTree/BPlusTree.thy b/thys/BTree/BPlusTree.thy new file mode 100644 --- /dev/null +++ b/thys/BTree/BPlusTree.thy @@ -0,0 +1,652 @@ +theory BPlusTree + imports Main "HOL-Data_Structures.Sorted_Less" "HOL-Data_Structures.Cmp" "HOL-Library.Multiset" +begin + +(* some setup to cover up the redefinition of sorted in Sorted_Less + but keep the lemmas *) +hide_const (open) Sorted_Less.sorted +abbreviation "sorted_less \ Sorted_Less.sorted" + +section "Definition of the B-Plus-Tree" + +subsection "Datatype definition" + +text "B-Plus-Trees are basically B-Trees, that don't have empty Leafs but Leafs that contain +the relevant data. " + + +datatype 'a bplustree = Leaf (vals: "'a list") | Node (keyvals: "('a bplustree * 'a) list") (lasttree: "'a bplustree") + +type_synonym 'a bplustree_list = "('a bplustree * 'a) list" +type_synonym 'a bplustree_pair = "('a bplustree * 'a)" + +abbreviation subtrees where "subtrees xs \ (map fst xs)" +abbreviation separators where "separators xs \ (map snd xs)" + +subsection "Inorder and Set" + +text "The set of B-Plus-tree needs to be manually defined, regarding only the leaves. +This overrides the default instantiation." + +fun set_nodes :: "'a bplustree \ 'a set" where + "set_nodes (Leaf ks) = {}" | + "set_nodes (Node ts t) = \(set (map set_nodes (subtrees ts))) \ (set (separators ts)) \ set_nodes t" + +fun set_leaves :: "'a bplustree \ 'a set" where + "set_leaves (Leaf ks) = set ks" | + "set_leaves (Node ts t) = \(set (map set_leaves (subtrees ts))) \ set_leaves t" + +text "The inorder is a view of only internal seperators" + +fun inorder :: "'a bplustree \ 'a list" where + "inorder (Leaf ks) = []" | + "inorder (Node ts t) = concat (map (\ (sub, sep). inorder sub @ [sep]) ts) @ inorder t" + +abbreviation "inorder_list ts \ concat (map (\ (sub, sep). inorder sub @ [sep]) ts)" + +text "The leaves view considers only its leafs." + +fun leaves :: "'a bplustree \ 'a list" where + "leaves (Leaf ks) = ks" | + "leaves (Node ts t) = concat (map leaves (subtrees ts)) @ leaves t" + +abbreviation "leaves_list ts \ concat (map leaves (subtrees ts))" + +fun leaf_nodes where +"leaf_nodes (Leaf xs) = [Leaf xs]" | +"leaf_nodes (Node ts t) = concat (map leaf_nodes (subtrees ts)) @ leaf_nodes t" + +abbreviation "leaf_nodes_list ts \ concat (map leaf_nodes (subtrees ts))" + + + +text "And the elems view contains all elements of the tree" +(* NOTE this doesn't help *) + +fun elems :: "'a bplustree \ 'a list" where + "elems (Leaf ks) = ks" | + "elems (Node ts t) = concat (map (\ (sub, sep). elems sub @ [sep]) ts) @ elems t" + +abbreviation "elems_list ts \ concat (map (\ (sub, sep). elems sub @ [sep]) ts)" + +(* this abbreviation makes handling the list much nicer *) +thm leaves.simps +thm inorder.simps +thm elems.simps + +value "leaves (Node [(Leaf [], (0::nat)), (Node [(Leaf [], 1), (Leaf [], 10)] (Leaf []), 12), ((Leaf []), 30), ((Leaf []), 100)] (Leaf []))" + +subsection "Height and Balancedness" + +class height = + fixes height :: "'a \ nat" + +instantiation bplustree :: (type) height +begin + +fun height_bplustree :: "'a bplustree \ nat" where + "height (Leaf ks) = 0" | + "height (Node ts t) = Suc (Max (height ` (set (subtrees ts@[t]))))" + +instance .. + +end + +text "Balancedness is defined is close accordance to the definition by Ernst" + +fun bal:: "'a bplustree \ bool" where + "bal (Leaf ks) = True" | + "bal (Node ts t) = ( + (\sub \ set (subtrees ts). height sub = height t) \ + (\sub \ set (subtrees ts). bal sub) \ bal t + )" + + +value "height (Node [(Leaf [], (0::nat)), (Node [(Leaf [], 1), (Leaf [], 10)] (Leaf []), 12), ((Leaf []), 30), ((Leaf []), 100)] (Leaf []))" +value "bal (Node [(Leaf [], (0::nat)), (Node [(Leaf [], 1), (Leaf [], 10)] (Leaf []), 12), ((Leaf []), 30), ((Leaf []), 100)] (Leaf []))" + + +subsection "Order" + +text "The order of a B-tree is defined just as in the original paper by Bayer." + +(* alt1: following knuths definition to allow for any + natural number as order and resolve ambiguity *) +(* alt2: use range [k,2*k] allowing for valid bplustrees + from k=1 onwards NOTE this is what I ended up implementing *) + +fun order:: "nat \ 'a bplustree \ bool" where + "order k (Leaf ks) = ((length ks \ k) \ (length ks \ 2*k))" | + "order k (Node ts t) = ( + (length ts \ k) \ + (length ts \ 2*k) \ + (\sub \ set (subtrees ts). order k sub) \ order k t +)" + +text \The special condition for the root is called \textit{root\_order}\ + +(* the invariant for the root of the bplustree *) +fun root_order:: "nat \ 'a bplustree \ bool" where + "root_order k (Leaf ks) = (length ks \ 2*k)" | + "root_order k (Node ts t) = ( + (length ts > 0) \ + (length ts \ 2*k) \ + (\s \ set (subtrees ts). order k s) \ order k t +)" + + +subsection "Auxiliary Lemmas" + +(* auxiliary lemmas when handling sets *) +lemma separators_split: + "set (separators (l@(a,b)#r)) = set (separators l) \ set (separators r) \ {b}" + by simp + +lemma subtrees_split: + "set (subtrees (l@(a,b)#r)) = set (subtrees l) \ set (subtrees r) \ {a}" + by simp + +(* height and set lemmas *) + + +lemma finite_set_ins_swap: + assumes "finite A" + shows "max a (Max (Set.insert b A)) = max b (Max (Set.insert a A))" + using Max_insert assms max.commute max.left_commute by fastforce + +lemma finite_set_in_idem: + assumes "finite A" + shows "max a (Max (Set.insert a A)) = Max (Set.insert a A)" + using Max_insert assms max.commute max.left_commute by fastforce + +lemma height_Leaf: "height t = 0 \ (\ks. t = (Leaf ks))" + by (induction t) (auto) + +lemma height_bplustree_order: + "height (Node (ls@[a]) t) = height (Node (a#ls) t)" + by simp + +lemma height_bplustree_sub: + "height (Node ((sub,x)#ls) t) = max (height (Node ls t)) (Suc (height sub))" + by simp + +lemma height_bplustree_last: + "height (Node ((sub,x)#ts) t) = max (height (Node ts sub)) (Suc (height t))" + by (induction ts) auto + + +lemma set_leaves_leaves: "set (leaves t) = set_leaves t" + apply(induction t) + apply(auto) + done + +lemma set_nodes_nodes: "set (inorder t) = set_nodes t" + apply(induction t) + apply(auto simp add: rev_image_eqI) + done + + +lemma child_subset_leaves: "p \ set t \ set_leaves (fst p) \ set_leaves (Node t n)" + apply(induction p arbitrary: t n) + apply(auto) + done + +lemma child_subset: "p \ set t \ set_nodes (fst p) \ set_nodes (Node t n)" + apply(induction p arbitrary: t n) + apply(auto) + done + +lemma some_child_sub: + assumes "(sub,sep) \ set t" + shows "sub \ set (subtrees t)" + and "sep \ set (separators t)" + using assms by force+ + +(* balancedness lemmas *) + + +lemma bal_all_subtrees_equal: "bal (Node ts t) \ (\s1 \ set (subtrees ts). \s2 \ set (subtrees ts). height s1 = height s2)" + by (metis BPlusTree.bal.simps(2)) + + +lemma fold_max_set: "\x \ set t. x = f \ fold max t f = f" + apply(induction t) + apply(auto simp add: max_def_raw) + done + +lemma height_bal_tree: "bal (Node ts t) \ height (Node ts t) = Suc (height t)" + by (induction ts) auto + + + +lemma bal_split_last: + assumes "bal (Node (ls@(sub,sep)#rs) t)" + shows "bal (Node (ls@rs) t)" + and "height (Node (ls@(sub,sep)#rs) t) = height (Node (ls@rs) t)" + using assms by auto + + +lemma bal_split_right: + assumes "bal (Node (ls@rs) t)" + shows "bal (Node rs t)" + and "height (Node rs t) = height (Node (ls@rs) t)" + using assms by (auto simp add: image_constant_conv) + +lemma bal_split_left: + assumes "bal (Node (ls@(a,b)#rs) t)" + shows "bal (Node ls a)" + and "height (Node ls a) = height (Node (ls@(a,b)#rs) t)" + using assms by (auto simp add: image_constant_conv) + + +lemma bal_substitute: "\bal (Node (ls@(a,b)#rs) t); height t = height c; bal c\ \ bal (Node (ls@(c,b)#rs) t)" + unfolding bal.simps + by auto + +lemma bal_substitute_subtree: "\bal (Node (ls@(a,b)#rs) t); height a = height c; bal c\ \ bal (Node (ls@(c,b)#rs) t)" + using bal_substitute + by auto + +lemma bal_substitute_separator: "bal (Node (ls@(a,b)#rs) t) \ bal (Node (ls@(a,c)#rs) t)" + unfolding bal.simps + by auto + +(* order lemmas *) + +lemma order_impl_root_order: "\k > 0; order k t\ \ root_order k t" + apply(cases t) + apply(auto) + done + + +(* sorted leaves implies that some sublists are sorted. This can be followed directly *) + +lemma sorted_inorder_list_separators: "sorted_less (inorder_list ts) \ sorted_less (separators ts)" + apply(induction ts) + apply (auto simp add: sorted_lems) + done + +corollary sorted_inorder_separators: "sorted_less (inorder (Node ts t)) \ sorted_less (separators ts)" + using sorted_inorder_list_separators sorted_wrt_append + by auto + + +lemma sorted_inorder_list_subtrees: + "sorted_less (inorder_list ts) \ \ sub \ set (subtrees ts). sorted_less (inorder sub)" + apply(induction ts) + apply (auto simp add: sorted_lems)+ + done + +corollary sorted_inorder_subtrees: "sorted_less (inorder (Node ts t)) \ \ sub \ set (subtrees ts). sorted_less (inorder sub)" + using sorted_inorder_list_subtrees sorted_wrt_append by auto + +lemma sorted_inorder_list_induct_subtree: + "sorted_less (inorder_list (ls@(sub,sep)#rs)) \ sorted_less (inorder sub)" + by (simp add: sorted_wrt_append) + +corollary sorted_inorder_induct_subtree: + "sorted_less (inorder (Node (ls@(sub,sep)#rs) t)) \ sorted_less (inorder sub)" + by (simp add: sorted_wrt_append) + +lemma sorted_inorder_induct_last: "sorted_less (inorder (Node ts t)) \ sorted_less (inorder t)" + by (simp add: sorted_wrt_append) + + +lemma sorted_leaves_list_subtrees: + "sorted_less (leaves_list ts) \ \ sub \ set (subtrees ts). sorted_less (leaves sub)" + apply(induction ts) + apply (auto simp add: sorted_wrt_append)+ + done + +corollary sorted_leaves_subtrees: "sorted_less (leaves (Node ts t)) \ \ sub \ set (subtrees ts). sorted_less (leaves sub)" + using sorted_leaves_list_subtrees sorted_wrt_append by auto + +lemma sorted_leaves_list_induct_subtree: + "sorted_less (leaves_list (ls@(sub,sep)#rs)) \ sorted_less (leaves sub)" + by (simp add: sorted_wrt_append) + +corollary sorted_leaves_induct_subtree: + "sorted_less (leaves (Node (ls@(sub,sep)#rs) t)) \ sorted_less (leaves sub)" + by (simp add: sorted_wrt_append) + +lemma sorted_leaves_induct_last: "sorted_less (leaves (Node ts t)) \ sorted_less (leaves t)" + by (simp add: sorted_wrt_append) + +text "Additional lemmas on the sortedness of the whole tree, which is +correct alignment of navigation structure and leave data" + +fun inbetween where +"inbetween f l Nil t u = f l t u" | +"inbetween f l ((sub,sep)#xs) t u = (f l sub sep \ inbetween f sep xs t u)" + +thm fold_cong + +lemma cong_inbetween[fundef_cong]: " +\a = b; xs = ys; \l' u' sub sep. (sub,sep) \ set ys \ f l' sub u' = g l' sub u'; \l' u'. f l' a u' = g l' b u'\ + \ inbetween f l xs a u = inbetween g l ys b u" + apply(induction ys arbitrary: l a b u xs) + apply auto + apply fastforce+ + done + +(* adding l < u makes sorted_less inorder not necessary anymore *) +fun aligned :: "'a ::linorder \ _" where +"aligned l (Leaf ks) u = (l < u \ (\x \ set ks. l < x \ x \ u))" | +"aligned l (Node ts t) u = (inbetween aligned l ts t u)" + +lemma sorted_less_merge: "sorted_less (as@[a]) \ sorted_less (a#bs) \ sorted_less (as@a#bs)" + using sorted_mid_iff by blast + + +thm aligned.simps + +lemma leaves_cases: "x \ set (leaves (Node ts t)) \ (\(sub,sep) \ set ts. x \ set (leaves sub)) \ x \ set (leaves t)" + apply (induction ts) + apply auto + done + +lemma align_sub: "aligned l (Node ts t) u \ (sub,sep) \ set ts \ \l' \ set (separators ts) \ {l}. aligned l' sub sep" + apply(induction ts arbitrary: l) + apply auto + done + +lemma align_last: "aligned l (Node (ts@[(sub,sep)]) t) u \ aligned sep t u" + apply(induction ts arbitrary: l) + apply auto + done + +lemma align_last': "aligned l (Node ts t) u \ \l' \ set (separators ts) \ {l}. aligned l' t u" + apply(induction ts arbitrary: l) + apply auto + done + +lemma aligned_sorted_inorder: "aligned l t u \ sorted_less (l#(inorder t)@[u])" +proof(induction l t u rule: aligned.induct) + case (2 l ts t u) + then show ?case + proof(cases ts) + case Nil + then show ?thesis + using 2 by auto + next + case Cons + then obtain ts' sub sep where ts_split: "ts = ts'@[(sub,sep)]" + by (metis list.distinct(1) rev_exhaust surj_pair) + moreover from 2 have "sorted_less (l#(inorder_list ts))" + proof (induction ts arbitrary: l) + case (Cons a ts') + then show ?case + proof (cases a) + case (Pair sub sep) + then have "aligned l sub sep" "inbetween aligned sep ts' t u" + using "Cons.prems" by simp+ + then have "aligned sep (Node ts' t) u" + by simp + then have "sorted_less (sep#inorder_list ts')" + using Cons + by (metis insert_iff list.set(2)) + moreover have "sorted_less (l#inorder sub@[sep])" + using Cons + by (metis Pair \aligned l sub sep\ list.set_intros(1)) + ultimately show ?thesis + using Pair sorted_less_merge[of "l#inorder sub" sep "inorder_list ts'"] + by simp + qed + qed simp + moreover have "sorted_less (sep#inorder t@[u])" + proof - + from 2 have "aligned sep t u" + using align_last ts_split by blast + then show ?thesis + using "2.IH" by blast + qed + ultimately show ?thesis + using sorted_less_merge[of "l#inorder_list ts'@inorder sub" sep "inorder t@[u]"] + by simp + qed +qed simp + +lemma separators_in_inorder_list: "set (separators ts) \ set (inorder_list ts)" + apply (induction ts) + apply auto + done + +lemma separators_in_inorder: "set (separators ts) \ set (inorder (Node ts t))" + by fastforce + +lemma aligned_sorted_separators: "aligned l (Node ts t) u \ sorted_less (l#(separators ts)@[u])" + by (smt (verit, ccfv_threshold) aligned_sorted_inorder separators_in_inorder sorted_inorder_separators sorted_lems(2) sorted_wrt.simps(2) sorted_wrt_append subset_eq) + +lemma aligned_leaves_inbetween: "aligned l t u \ \x \ set (leaves t). l < x \ x \ u" +proof (induction l t u rule: aligned.induct) + case (1 l ks u) + then show ?case by auto +next + case (2 l ts t u) + have *: "sorted_less (l#inorder (Node ts t)@[u])" + using "2.prems" aligned_sorted_inorder by blast + show ?case + proof + fix x assume "x \ set (leaves (Node ts t))" + then consider (sub) "\(sub,sep) \ set ts. x \ set (leaves sub)" | (last) "x \ set (leaves t)" + by fastforce + then show "l < x \ x \ u" + proof (cases) + case sub + then obtain sub sep where "(sub,sep) \ set ts" "x \ set (leaves sub)" by auto + then obtain l' where "aligned l' sub sep" "l' \ set (separators ts) \ {l}" + using "2.prems"(1) \(sub, sep) \ set ts\ align_sub by blast + then have "\x \ set (leaves sub). l' < x \ x \ sep" + using "2.IH"(1) \(sub,sep) \ set ts\ by auto + moreover from * have "l \ l'" + by (metis Un_insert_right \l' \ set (separators ts) \ {l}\ append_Cons boolean_algebra_cancel.sup0 dual_order.eq_iff insert_iff less_imp_le separators_in_inorder sorted_snoc sorted_wrt.simps(2) subset_eq) + moreover from * have "sep \ u" + by (metis \(sub, sep) \ set ts\ less_imp_le list.set_intros(1) separators_in_inorder some_child_sub(2) sorted_mid_iff2 sorted_wrt_append subset_eq) + ultimately show ?thesis + by (meson \x \ set (leaves sub)\ order.strict_trans1 order.trans) + next + case last + then obtain l' where "aligned l' t u" "l' \ set (separators ts) \ {l}" + using align_last' "2.prems" by blast + then have "\x \ set (leaves t). l' < x \ x \ u" + using "2.IH"(2) by auto + moreover from * have "l \ l'" + by (metis Un_insert_right \l' \ set (separators ts) \ {l}\ append_Cons boolean_algebra_cancel.sup0 dual_order.eq_iff insert_iff less_imp_le separators_in_inorder sorted_snoc sorted_wrt.simps(2) subset_eq) + ultimately show ?thesis + by (meson \x \ set (leaves t)\ order.strict_trans1 order.trans) + qed + qed +qed + +lemma aligned_leaves_list_inbetween: "aligned l (Node ts t) u \ \x \ set (leaves_list ts). l < x \ x \ u" + by (metis Un_iff aligned_leaves_inbetween leaves.simps(2) set_append) + +lemma aligned_split_left: "aligned l (Node (ls@(sub,sep)#rs) t) u \ aligned l (Node ls sub) sep" + apply(induction ls arbitrary: l) + apply auto + done + + +lemma aligned_split_right: "aligned l (Node (ls@(sub,sep)#rs) t) u \ aligned sep (Node rs t) u" + apply(induction ls arbitrary: l) + apply auto + done + +lemma aligned_subst: "aligned l (Node (ls@(sub', subl)#(sub,subsep)#rs) t) u \ aligned subl subsub subsep \ +aligned l (Node (ls@(sub',subl)#(subsub,subsep)#rs) t) u" + apply (induction ls arbitrary: l) + apply auto + done + +lemma aligned_subst_emptyls: "aligned l (Node ((sub,subsep)#rs) t) u \ aligned l subsub subsep \ +aligned l (Node ((subsub,subsep)#rs) t) u" + by auto + +lemma aligned_subst_last: "aligned l (Node (ts'@[(sub', sep')]) t) u \ aligned sep' t' u \ + aligned l (Node (ts'@[(sub', sep')]) t') u" + apply (induction ts' arbitrary: l) + apply auto + done + +fun Laligned :: "'a ::linorder bplustree \ _" where +"Laligned (Leaf ks) u = (\x \ set ks. x \ u)" | +"Laligned (Node ts t) u = (case ts of [] \ (Laligned t u) | + (sub,sep)#ts' \ ((Laligned sub sep) \ inbetween aligned sep ts' t u))" + +lemma Laligned_nonempty_Node: "Laligned (Node ((sub,sep)#ts') t) u = + ((Laligned sub sep) \ inbetween aligned sep ts' t u)" + by simp + +lemma aligned_imp_Laligned: "aligned l t u \ Laligned t u" + apply (induction l t u rule: aligned.induct) + apply simp + subgoal for l ts t u + apply(cases ts) + apply auto + apply blast + done + done + +lemma Laligned_split_left: "Laligned (Node (ls@(sub,sep)#rs) t) u \ Laligned (Node ls sub) sep" + apply(cases ls) + apply (auto dest!: aligned_imp_Laligned) + apply (meson aligned.simps(2) aligned_split_left) + done + +lemma Laligned_split_right: "Laligned (Node (ls@(sub,sep)#rs) t) u \ aligned sep (Node rs t) u" + apply(cases ls) + apply (auto split!: list.splits dest!: aligned_imp_Laligned) + apply (meson aligned.simps(2) aligned_split_right) + done + +lemma Lalign_sub: "Laligned (Node ((a,b)#ts) t) u \ (sub,sep) \ set ts \ \l' \ set (separators ts) \ {b}. aligned l' sub sep" + apply(induction ts arbitrary: a b) + apply (auto dest!: aligned_imp_Laligned) + done + +lemma Lalign_last: "Laligned (Node (ts@[(sub,sep)]) t) u \ aligned sep t u" + by (cases ts) (auto simp add: align_last) + +lemma Lalign_last': "Laligned (Node ((a,b)#ts) t) u \ \l' \ set (separators ts) \ {b}. aligned l' t u" + apply(induction ts arbitrary: a b) + apply (auto dest!: aligned_imp_Laligned) + done + +lemma Lalign_Llast: "Laligned (Node ts t) u \ Laligned t u" + apply(cases ts) + apply auto + using aligned_imp_Laligned Lalign_last' Laligned_nonempty_Node + by metis + + +lemma Laligned_sorted_inorder: "Laligned t u \ sorted_less ((inorder t)@[u])" +proof(induction t u rule: Laligned.induct) + case (1 ks u) + then show ?case by auto +next + case (2 ts t u) + then show ?case + apply (cases ts) + apply auto + by (metis aligned.simps(2) aligned_sorted_inorder append_assoc inorder.simps(2) sorted_less_merge) +qed + + +lemma Laligned_sorted_separators: "Laligned (Node ts t) u \ sorted_less ((separators ts)@[u])" + by (smt (verit, del_insts) Laligned_sorted_inorder separators_in_inorder sorted_inorder_separators sorted_wrt_append subset_eq) + +lemma Laligned_leaves_inbetween: "Laligned t u \ \x \ set (leaves t). x \ u" +proof (induction t u rule: Laligned.induct) + case (1 ks u) + then show ?case by auto +next + case (2 ts t u) + have *: "sorted_less (inorder (Node ts t)@[u])" + using "2.prems" Laligned_sorted_inorder by blast + show ?case + proof (cases ts) + case Nil + show ?thesis + proof + fix x assume "x \ set (leaves (Node ts t))" + then have "x \ set (leaves t)" + using Nil by auto + moreover have "Laligned t u" + using "2.prems" Nil by auto + ultimately show "x \ u" + using "2.IH"(1) Nil + by simp + qed + next + case (Cons h ts') + then obtain a b where h_split: "h = (a,b)" + by (cases h) + show ?thesis + proof + fix x assume "x \ set (leaves (Node ts t))" + then consider (first) "x \ set (leaves a)" | (sub) "\(sub,sep) \ set ts'. x \ set (leaves sub)" | (last) "x \ set (leaves t)" + using Cons h_split by fastforce + then show "x \ u" + proof (cases) + case first + moreover have "Laligned a b" + using "2.prems" Cons h_split by auto + moreover have "b \ u" + by (metis "*" h_split less_imp_le list.set_intros(1) local.Cons separators_in_inorder some_child_sub(2) sorted_wrt_append subsetD) + ultimately show ?thesis + using "2.IH"(2)[OF Cons sym[OF h_split]] + by auto + next + case sub + then obtain sub sep where "(sub,sep) \ set ts'" "x \ set (leaves sub)" by auto + then obtain l' where "aligned l' sub sep" "l' \ set (separators ts') \ {b}" + using "2.prems" Lalign_sub h_split local.Cons by blast + then have "\x \ set (leaves sub). l' < x \ x \ sep" + by (meson aligned_leaves_inbetween) + moreover from * have "sep \ u" + by (metis "2.prems" Laligned_sorted_separators \(sub, sep) \ set ts'\ insert_iff less_imp_le list.set(2) local.Cons some_child_sub(2) sorted_wrt_append) + ultimately show ?thesis + by (meson \x \ set (leaves sub)\ order.strict_trans1 order.trans) + next + case last + then obtain l' where "aligned l' t u" "l' \ set (separators ts') \ {b}" + using "2.prems" Lalign_last' h_split local.Cons by blast + then have "\x \ set (leaves t). l' < x \ x \ u" + by (meson aligned_leaves_inbetween) + then show ?thesis + by (meson \x \ set (leaves t)\ order.strict_trans1 order.trans) + qed + qed + qed +qed + +lemma Laligned_leaves_list_inbetween: "Laligned (Node ts t) u \ \x \ set (leaves_list ts). x \ u" + by (metis Un_iff Laligned_leaves_inbetween leaves.simps(2) set_append) + +lemma Laligned_subst_last: "Laligned (Node (ts'@[(sub', sep')]) t) u \ aligned sep' t' u \ + Laligned (Node (ts'@[(sub', sep')]) t') u" + apply (cases ts') + apply (auto) + by (meson aligned.simps(2) aligned_subst_last) + +lemma Laligned_subst: "Laligned (Node (ls@(sub', subl)#(sub,subsep)#rs) t) u \ aligned subl subsub subsep \ +Laligned (Node (ls@(sub',subl)#(subsub,subsep)#rs) t) u" + apply (induction ls) + apply auto + apply (meson aligned.simps(2) aligned_subst) + done + +lemma concat_leaf_nodes_leaves: "(concat (map leaves (leaf_nodes t))) = leaves t" + apply(induction t rule: leaf_nodes.induct) + subgoal by auto + subgoal for ts t + apply(induction ts) + apply simp + apply auto + done + done + +lemma leaf_nodes_not_empty: "leaf_nodes t \ []" + by (induction t) auto + +end \ No newline at end of file diff --git a/thys/BTree/BPlusTree_Imp.thy b/thys/BTree/BPlusTree_Imp.thy new file mode 100644 --- /dev/null +++ b/thys/BTree/BPlusTree_Imp.thy @@ -0,0 +1,109 @@ +theory BPlusTree_Imp + imports + BPlusTree + Partially_Filled_Array + Basic_Assn + Inst_Ex_Assn +begin + +lemma butlast_double_Cons: "butlast (x#y#xs) = x#(butlast (y#xs))" + by auto + +lemma last_double_Cons: "last (x#y#xs) = (last (y#xs))" + by auto + +section "Imperative B-tree Definition" + +text "The heap data type definition. Anything stored on the heap always contains data, +leafs are represented as None." + +(* Option as we need a default for non-initializeed entries *) +datatype 'a btnode = + Btleaf "'a pfarray" "'a btnode ref option" | + Btnode "('a btnode ref option *'a) pfarray" "'a btnode ref" + + +text \Selector Functions\ +primrec kvs :: "'a::heap btnode \ ('a btnode ref option * 'a) pfarray" where + [sep_dflt_simps]: "kvs (Btnode ts _) = ts" + +primrec lst :: "'a::heap btnode \ 'a btnode ref" where + [sep_dflt_simps]: "lst (Btnode _ t) = t" + +primrec vals :: "'a::heap btnode \ 'a pfarray" where + [sep_dflt_simps]: "vals (Btleaf ts _) = ts" + +primrec fwd :: "'a::heap btnode \ 'a btnode ref option" where + [sep_dflt_simps]: "fwd (Btleaf _ t) = t" + +text \Encoding to natural numbers, as required by Imperative/HOL\ + (* Note: should also work using the package "Deriving" *) +fun + btnode_encode :: "'a::heap btnode \ nat" + where + "btnode_encode (Btnode ts t) = to_nat (Some ts, Some t, None::'a pfarray option, None::'a btnode ref option option)" | + "btnode_encode (Btleaf ts t) = to_nat (None::('a btnode ref option * 'a) pfarray option, None::'a btnode ref option, Some ts, Some t)" + +instance btnode :: (heap) heap + apply (rule heap_class.intro) + apply (rule countable_classI [of "btnode_encode"]) + apply(elim btnode_encode.elims) + apply auto + .. + +text "The refinement relationship to abstract B-trees." + +text "The idea is: a refines the given node of degree k where the first leaf node of the subtree +of a is r and the forward pointer in the last leaf node is z" + +find_theorems list_assn +find_theorems id_assn + +fun bplustree_assn :: "nat \ ('a::heap) bplustree \ 'a btnode ref \ 'a btnode ref option \ 'a btnode ref option \ assn" where + "bplustree_assn k (Leaf xs) a r z = + (\\<^sub>A xsi fwd. + a \\<^sub>r Btleaf xsi fwd + * is_pfa (2*k) xs xsi + * \(fwd = z) + * \(r = Some a) + )" | + "bplustree_assn k (Node ts t) a r z = + (\\<^sub>A tsi ti tsi' tsi'' rs. + a \\<^sub>r Btnode tsi ti + * bplustree_assn k t ti (last (r#rs)) (last (rs@[z])) + * is_pfa (2*k) tsi' tsi + * \(length tsi' = length rs) + * \(tsi'' = zip (zip (map fst tsi') (zip (butlast (r#rs)) (butlast (rs@[z])))) (map snd tsi')) + * list_assn ((\ t (ti,r',z'). bplustree_assn k t (the ti) r' z') \\<^sub>a id_assn) ts tsi'' + )" + + +find_theorems "map _ (zip _ _)" +(* +rs = the list of pointers to the leaves of this subtree +TODO how to weave rs@[z] and a#rs into the list_assn most elegantly +*) + +text "With the current definition of deletion, we would +also need to directly reason on nodes and not only on references +to them." + +fun btnode_assn :: "nat \ ('a::heap) bplustree \ 'a btnode \ 'a btnode ref option \ 'a btnode ref option \ assn" where + "btnode_assn k (Leaf xs) (Btleaf xsi zi) r z = + (\\<^sub>A xsi zi. + is_pfa (2*k) xs xsi + * \(zi = z) + )" | + "btnode_assn k (Node ts t) (Btnode tsi ti) r z = + (\\<^sub>A tsi' tsi'' rs. + bplustree_assn k t ti (last (r#rs)) (last (rs@[z])) + * is_pfa (2*k) tsi' tsi + * \(length tsi' = length rs) + * \(tsi'' = zip (zip (map fst tsi') (zip (butlast (r#rs)) (butlast (rs@[z])))) (map snd tsi')) + * list_assn ((\ t (ti,r',z'). bplustree_assn k t (the ti) r' z') \\<^sub>a id_assn) ts tsi'' + )" | + "btnode_assn _ _ _ _ _ = false" + +abbreviation "blist_assn k ts tsi'' \ list_assn ((\ t (ti,r',z'). bplustree_assn k t (the ti) r' z') \\<^sub>a id_assn) ts tsi'' " + +end \ No newline at end of file diff --git a/thys/BTree/BPlusTree_ImpRange.thy b/thys/BTree/BPlusTree_ImpRange.thy new file mode 100644 --- /dev/null +++ b/thys/BTree/BPlusTree_ImpRange.thy @@ -0,0 +1,1059 @@ +theory BPlusTree_ImpRange +imports + BPlusTree_Iter + BPlusTree_Range + BPlusTree_ImpSplit +begin + +abbreviation "blist_leafs_assn k \ list_assn ((\ t (ti,r',z',lptrs). bplustree_assn_leafs k t (the ti) r' z' lptrs) \\<^sub>a id_assn)" + +context split\<^sub>i_tree +begin + +lemma list_induct5 [consumes 4, case_names Nil Cons]: + "length xs = length ys \ length ys = length zs \ length zs = length ws \ length ws = length vs \ + P [] [] [] [] [] \ (\x xs y ys z zs w ws v vs. length xs = length ys \ + length ys = length zs \ length zs = length ws \ length ws = length vs \ P xs ys zs ws vs \ + P (x#xs) (y#ys) (z#zs) (w#ws) (v#vs)) \ P xs ys zs ws vs" +proof (induct xs arbitrary: ys zs ws vs) + case Nil then show ?case by simp +next + case (Cons x xs ys zs ws) then show ?case by ((cases ys, simp_all), (cases zs,simp_all), (cases ws, simp_all)) (cases vs, simp_all) +qed + +declare butlast.simps[simp del] last.simps[simp del] +lemma blist_assn_extract_leafs: " +length ts = length tsi \ +length tsi = length rs \ +blist_assn k ts (zip (zip (map fst tsi) (zip (butlast (r#rs)) rs)) (map snd tsi)) += +(\\<^sub>Aspl. blist_leafs_assn k ts (zip (zip (map fst tsi) (zip (butlast (r#rs)) (zip rs spl))) (map snd tsi)) * \(length spl = length rs))" +proof(induction arbitrary: r rule: list_induct3) + case Nil + then show ?case + apply(intro ent_iffI) + by sep_auto+ +next + case (Cons x xs y ys z zs r) + show ?case + using Cons.hyps + using Cons.hyps + apply (sep_auto simp add: butlast_double_Cons last_double_Cons) + supply R= Cons.IH[simplified, of z] + thm R + apply(subst R) + proof(intro ent_iffI, goal_cases) + case 1 + then show ?case + apply(sep_auto eintros del: exI simp add: prod_assn_def bplustree_extract_leafs split!: prod.splits) + subgoal for _ _ spl lptrs + apply(inst_existentials "lptrs#spl") + apply auto + done + done + next + case 2 + then show ?case + apply(sep_auto eintros del: exI) + subgoal for spl + apply(cases spl) + apply simp + subgoal for hdspl tlspl + apply(inst_existentials tlspl) + apply (auto simp add: prod_assn_def bplustree_extract_leafs split!: prod.splits) + done + done + done + qed + qed +declare butlast.simps[simp add] last.simps[simp add] + +lemma blist_discard_leafs: + assumes +"length ts = length tsi" +"length tsi = length rs" +"length spl = length rs" +shows +"blist_leafs_assn k ts (zip (zip (map fst tsi) (zip (butlast (r#rs)) (zip rs spl))) (map snd tsi)) \\<^sub>A +blist_assn k ts (zip (zip (map fst tsi) (zip (butlast (r#rs)) rs)) (map snd tsi))" + apply (subst blist_assn_extract_leafs[OF assms(1,2)]) + using assms + by sep_auto + +declare butlast.simps[simp del] last.simps[simp del] +lemma split\<^sub>i_leafs_rule_help: +"sorted_less (separators ts) \ + length tsi = length rs \ + tsi' = (zip (zip (map fst tsi) (zip (butlast (r#rs)) (butlast (rs@[z]))))) (map snd tsi) \ + + split\<^sub>i (a,n) p + <\i. \\<^sub>Aspl. + is_pfa c tsi (a,n) + * blist_leafs_assn k ts (zip (zip (map fst tsi) (zip (butlast (r#rs)) (zip (butlast (rs@[z])) spl))) (map snd tsi)) + * \(split_relation ts (split ts p) i) + * \(length spl = length rs) >\<^sub>t" +proof(rule hoare_triple_preI, goal_cases) + case 1 + have ***: "length tsi' = length rs" + using 1 by auto + then have *: "length ts = length tsi'" + using 1 by (auto dest!: mod_starD list_assn_len) + then have **: "length ts = length tsi" + using 1 by (auto dest!: mod_starD list_assn_len) + note R = split\<^sub>i_rule[of ts tsi rs "zip (zip (subtrees tsi) (zip (butlast (r # rs)) rs)) (separators tsi)" r] + from 1 show ?thesis + apply(vcg) + using ** 1(2) + apply(simp add: blist_assn_extract_leafs) + find_theorems ex_assn entails + apply(rule ent_ex_preI) + subgoal for x spl + apply(inst_ex_assn spl) + apply sep_auto + done + done +qed +declare butlast.simps[simp add] last.simps[simp add] + +lemma fr_refl_rot: "P \\<^sub>A R \ F * P \\<^sub>A F * R" + using fr_refl[of P R F] by (simp add: mult.commute) + +declare butlast.simps[simp del] last.simps[simp del] +lemma split\<^sub>i_leafs_rule[sep_heap_rules]: + assumes "sorted_less (separators ts)" + and "length tsi = length rs" + and "length spl = length rs" + and "tsi' = zip (zip (map fst tsi) (zip (butlast (r#rs)) (zip (butlast (rs@[z])) spl))) (map snd tsi)" + shows " + + split\<^sub>i (a,n) p + <\i. \\<^sub>Aspl. + is_pfa c tsi (a,n) + * blist_leafs_assn k ts (zip (zip (map fst tsi) (zip (butlast (r#rs)) (zip (butlast (rs@[z])) spl))) (map snd tsi)) + * \(split_relation ts (split ts p) i) + * \(length spl = length rs) >\<^sub>t" +proof(rule hoare_triple_preI, goal_cases) + case 1 + have "length tsi' = length rs" + using assms by auto + then have *: "length ts = length tsi'" + using 1 by (auto dest!: mod_starD list_assn_len) + then have **: "length ts = length tsi" + using 1 assms by (auto dest!: mod_starD list_assn_len) + note R = split\<^sub>i_leafs_rule_help[ + OF assms(1,2), + of "zip (zip (subtrees tsi) (zip (butlast (r # rs)) (butlast (rs @ [z])))) (separators tsi)" r + z c a n k + ] + thm R + note R' = fi_rule[OF R, of "is_pfa c tsi (a,n) * blist_leafs_assn k ts tsi'" "emp"] + thm R' + show ?case + apply(vcg heap add: R') + subgoal + apply (simp add: assms) + apply(rule fr_refl_rot) + using blist_discard_leafs[OF ** assms(2,3)] + apply auto + done + subgoal by sep_auto + done +qed + +end + +(* Adding an actual range iterator based on the normal iterator +is trivial (just forward until we reach the first element \ and stop +as soon as we have an element <) +We now try to implement a search for the first element of the range efficiently + *) +subsection "The imperative split locale" + + +locale split\<^sub>i_range = abs_split_range: split_range split lrange_list + split\<^sub>i_tree split split\<^sub>i + for split:: + "('a bplustree \ 'a::{heap,default,linorder,order_top}) list \ 'a + \ ('a bplustree \ 'a) list \ ('a bplustree \ 'a) list" + and lrange_list :: "'a \ ('a::{heap,default,linorder,order_top}) list \ 'a list" + and split\<^sub>i :: "('a btnode ref option \ 'a::{heap,default,linorder,order_top}) pfarray \ 'a \ nat Heap" + + fixes lrange_list\<^sub>i:: "'a \ ('a::{heap,default,linorder,order_top}) pfarray \ 'a pfa_it Heap" + assumes lrange_list_rule [sep_heap_rules]:"sorted_less ks \ + + lrange_list\<^sub>i x (a',n') + \<^sub>t" +begin + +partial_function (heap) leaf_nodes_lrange\<^sub>i :: + "'a btnode ref \ 'a \ 'a btnode ref option Heap" + where + "leaf_nodes_lrange\<^sub>i p x = do { + node \ !p; + (case node of + Btleaf xs z \ do { + return (Some p) + } + | + Btnode ts t \ do { + i \ split\<^sub>i ts x; + tsl \ pfa_length ts; + if i < tsl then do { + s \ pfa_get ts i; + let (sub,sep) = s in + leaf_nodes_lrange\<^sub>i (the sub) x + } else + leaf_nodes_lrange\<^sub>i t x + } +)}" + + +(* HT when expressed on list of leaves +lemma leaf_nodes_lrange\<^sub>i_rule: + assumes "k > 0" "root_order k t" + shows " +leaf_nodes_lrange\<^sub>i ti x +<\p. (\\<^sub>A xs1 xs2 lptrs1 lptrs2 ps. + trunk_assn k t ti r z lptrs * + leaf_nodes_assn k xs1 r p lptrs1 * + list_assn leaf_node xs2 (map bplustree.vals xs2) * + list_assn (is_pfa (2 * k)) (map bplustree.vals xs2) ps * + leafs_assn ps lptrs2 p z * + \(concat (map bplustree.vals xs2) = abs_split_range.leaf_nodes_lrange\<^sub>i t x) * + \(lptrs = lptrs1@lptrs2) * + \(leaf_nodes t = xs1@xs2) +)>\<^sub>t" +sorry +*) + +lemma leaf_nodes_assn_split2: +"length xs = length xsi \ + leaf_nodes_assn k (xs @ ys) r z (xsi @ ysi) = (\\<^sub>Al. leaf_nodes_assn k xs r l xsi * leaf_nodes_assn k ys l z ysi)" +proof(induction arbitrary: r rule: list_induct2) + case (Nil r) + then show ?case + apply(cases r; cases ys) + apply clarsimp_all + subgoal + apply(rule ent_iffI) + by (sep_auto dest!: leaf_nodes_assn_impl_length)+ + subgoal + apply(rule ent_iffI) + by (sep_auto dest!: leaf_nodes_assn_impl_length)+ + subgoal + apply(rule ent_iffI) + by (sep_auto dest!: leaf_nodes_assn_impl_length)+ + subgoal for _ t _ + apply(cases t) + subgoal + apply clarsimp_all + apply(rule ent_iffI) + by (sep_auto dest!: leaf_nodes_assn_impl_length)+ + subgoal by clarsimp + done + done +next + case (Cons x xs xi xsi r) + show ?case + apply(cases r; cases x) + apply clarsimp_all + apply(rule ent_iffI) + subgoal for _ ts + apply(subst Cons.IH) + apply simp + apply(rule ent_ex_preI)+ + subgoal for tsi fwd l + apply(inst_ex_assn l tsi fwd) + apply sep_auto + done + done + subgoal for _ ts + apply(subst Cons.IH) + apply(simp) + apply(rule ent_ex_preI)+ + subgoal for l tsi fwd + apply(inst_ex_assn tsi fwd l) + apply sep_auto + done + done + done +qed + +lemma eq_preI: "(\h. h \ P \ Q = Q') \ P * Q = P * Q'" + apply(intro ent_iffI) + using entails_def mod_starD apply blast+ + done + +lemma simp_map_temp: "(map (leaf_nodes \ fst)) = map (\a. (leaf_nodes (fst a)))" + by (meson comp_apply) + + +declare last.simps[simp del] butlast.simps[simp del] +lemma blist_leafs_assn_split_help: +" length tsi' = length rrs \ + length rrs = length spl \ + length spl = length ts \ + (blist_leafs_assn k ts + (zip (zip (subtrees tsi') (zip (butlast (r # rrs)) (zip rrs spl))) (separators tsi')) + = + list_assn ((\t (ti, r', x, y). trunk_assn k t (the ti) r' x y) \\<^sub>a id_assn) ts + (zip (zip (subtrees tsi') (zip (butlast (r # rrs)) (zip rrs spl))) (separators tsi')) * + leaf_nodes_assn k (concat (map (leaf_nodes \ fst) ts)) r (last (r#rrs)) (concat spl) +) " +proof(induction tsi' rrs spl ts arbitrary: r rule: list_induct4) + case Nil + then show ?case + by (sep_auto simp add: last.simps butlast.simps) +next + case (Cons x xs y ys z zs w ws r) + show ?case + using Cons.hyps Cons.prems + apply(clarsimp simp add: butlast_double_Cons last_double_Cons) + apply(clarsimp simp add: prod_assn_def split!: prod.splits) + apply(simp add: bplustree_leaf_nodes_sep) + apply(subst Cons.IH[of y]) + subgoal for sub sep + apply(intro ent_iffI) + subgoal + apply(rule entails_preI) + apply(subst leaf_nodes_assn_split2) + subgoal by (auto dest!: mod_starD leaf_nodes_assn_impl_length) + apply (simp add: simp_map_temp) + apply(inst_ex_assn y) + apply(sep_auto) + done + subgoal + apply(rule entails_preI) + apply(cases ws) + proof(goal_cases) + case 1 + then show ?thesis + by (sep_auto simp add: last.simps) + next + case (2 _ a list) + then show ?thesis + apply(cases xs, simp) + apply(cases ys, simp) + apply(cases zs, simp) + subgoal for x' xs' y'' ys'' z' zs' + apply(clarsimp simp add: butlast_double_Cons last_double_Cons) + apply(clarsimp simp add: prod_assn_def split!: prod.splits) + subgoal for sub' sep' + apply(subgoal_tac "y = Some (hd z')") + prefer 2 + subgoal by (auto dest!: mod_starD trunk_assn_hd) + apply sep_auto + apply(subst leaf_nodes_assn_split[where yi="the y" and ysr="tl z'@concat zs'"]) + find_theorems trunk_assn length + subgoal by (auto dest!: mod_starD trunk_assn_leafs_len_imp) + apply(subgoal_tac "z' \ []") + prefer 2 + subgoal by (auto dest!: mod_starD trunk_assn_leafs_len_imp simp add: leaf_nodes_not_empty) + subgoal by simp + apply (simp add: simp_map_temp) + apply(sep_auto) + done + done + done + qed + done + done +qed +declare last.simps[simp add] butlast.simps[simp add] + +lemma blist_leafs_assn_split: +" length tsi' = length rrs \ + length rrs = length spl \ + (blist_leafs_assn k ts + (zip (zip (subtrees tsi') (zip (butlast (r # rrs)) (zip rrs spl))) (separators tsi')) + = + list_assn ((\t (ti, r', x, y). trunk_assn k t (the ti) r' x y) \\<^sub>a id_assn) ts + (zip (zip (subtrees tsi') (zip (butlast (r # rrs)) (zip rrs spl))) (separators tsi')) * + leaf_nodes_assn k (concat (map (leaf_nodes \ fst) ts)) r (last (r#rrs)) (concat spl) +) " +proof((intro ent_iffI; rule entails_preI), goal_cases) + case 1 + then have "length spl = length ts" + by (auto dest!: list_assn_len) + then show ?case + using blist_leafs_assn_split_help[OF 1(1,2)] + by auto +next + case 2 + then have "length spl = length ts" + by (auto dest!: mod_starD list_assn_len) + then show ?case + using blist_leafs_assn_split_help[OF 2(1,2)] + by auto +qed + +lemma split_list: "i < length ts \ ts ! i = x \ \ls rs. ts = ls@x#rs \ length ls = i" + by (metis id_take_nth_drop length_take min_simps(2)) + +lemma take_butlast_Suc: "i < length xs \ take i (butlast xs) = butlast (take (Suc i) xs)" + by (metis Suc_leI Suc_to_right take_butlast take_minus_one_conv_butlast) + +lemma inbetween_aligned_imp_Laligned: "inbetween aligned l (ls@(sub,sep)#rs) t u \ Laligned sub sep" + by (induction ls arbitrary: l) (auto simp add: aligned_imp_Laligned) + +lemma Laligned_sub: "Laligned (Node (ls@(sub,sep)#rs) t) u \ Laligned sub sep" + by (cases ls) (auto simp add: inbetween_aligned_imp_Laligned split!: prod.splits) + +(* much shorter when expressed on the nodes themselves *) +declare last.simps[simp del] butlast.simps[simp del] +lemma leaf_nodes_lrange\<^sub>i_rule: + assumes "k > 0" "root_order k t" "Laligned t u" + shows " +leaf_nodes_lrange\<^sub>i ti x +<\p. (\\<^sub>A lptrs xs1 lptrs1 lptrs2. + trunk_assn k t ti r z lptrs * + leaf_nodes_assn k xs1 r p lptrs1 * + leaf_nodes_assn k (abs_split_range.leaf_nodes_lrange t x) p z lptrs2 * + \(lptrs = lptrs1@lptrs2) * + \(leaf_nodes t = xs1@(abs_split_range.leaf_nodes_lrange t x)) +) +>\<^sub>t" + using assms +proof(induction t x arbitrary: ti r z u lptrs rule: abs_split_range.leaf_nodes_lrange.induct) + case (1 ks x) + then show ?case + apply(subst leaf_nodes_lrange\<^sub>i.simps) + apply (sep_auto eintros del: exI) + apply(inst_existentials "[ti]" "[]::'a bplustree list" "[]::'a btnode ref list" "[ti]") + apply sep_auto+ + done +next + case (2 ts t x ti r z u lptrs) + then have "sorted_less (separators ts)" + by (meson Laligned_sorted_separators sorted_wrt_append) + obtain ls rs where split_pair: "split ts x = (ls,rs)" + by (meson surj_pair) + show ?case + proof(cases rs) + case Nil + then show ?thesis + using split_pair + apply(subst leaf_nodes_lrange\<^sub>i.simps) + apply simp + apply(vcg) + apply simp + subgoal for tsi tii tsi' rrs spl + apply(cases tsi) + subgoal for tsia tsin + supply R = split\<^sub>i_leafs_rule[of ts tsi' rrs "butlast spl" "(zip (zip (subtrees tsi') (zip (butlast (r # rrs)) (zip rrs (butlast spl)))) + (separators tsi'))" r z] + thm R + apply (vcg heap add: R) + subgoal using \sorted_less (separators ts)\ by linarith + subgoal by simp + subgoal by simp + subgoal by (simp add: butlast.simps) + apply simp + apply(rule norm_pre_ex_rule) + apply(rule hoare_triple_preI) + apply(vcg) +(* discard wrong path *) + subgoal by (auto simp add: split_relation_alt is_pfa_def dest!: mod_starD list_assn_len)[] +(* correct path *) + subgoal for _ spl + supply R = "2.IH"(1)[OF split_pair[symmetric] Nil, of u] + thm R + apply(vcg heap add: R) + subgoal using "2.prems" by simp + subgoal + using "2.prems"(2) assms(1) order_impl_root_order root_order.simps(2) by blast + subgoal + using "2.prems"(3) Lalign_Llast by blast + apply (sep_auto eintros del: exI) + subgoal for y lptrs xs1 lptrs1 lptrs2 + apply(inst_existentials "concat (spl@[lptrs])" "concat (map (leaf_nodes \ fst) ts) @ xs1" "(concat spl) @ lptrs1" lptrs2 + tsia tsin tii tsi' "(zip (zip (subtrees tsi') (zip (butlast (r # rrs)) (zip rrs spl))) + (separators tsi'))" rrs "spl@[lptrs]") + (*apply(inst_existentials "concat (spl@[lptrs])" "concat (map (leaf_nodes \ fst) ts) @ xs1" "(concat (butlast spl)) @ lptrs1" lptrs2 + tsia tsin tii tsi' "(zip (zip (subtrees tsi') (zip (butlast (r # rrs)) (zip rrs (butlast spl)))) + (separators tsi'))" rrs spl)*) + subgoal + by (auto) + subgoal + apply sep_auto + apply(subst blist_leafs_assn_split) + subgoal by simp + subgoal + by (auto dest!: mod_starD list_assn_len) + apply(rule entails_preI) + apply(subst leaf_nodes_assn_split2) + subgoal + by (auto dest!: mod_starD leaf_nodes_assn_impl_length) + apply (sep_auto eintros del: exI) + apply(inst_existentials "(last (r # rrs))") + apply (sep_auto) + done + done + done + done + done + done + next + case (Cons subsep rrs) + then obtain sub sep where subsep_split[simp]:"subsep = (sub,sep)" + by (cases subsep) + then show ?thesis + apply(subst leaf_nodes_lrange\<^sub>i.simps) + using split_pair Cons apply (simp split!: list.splits prod.splits) + apply(vcg) + apply simp + subgoal for tsi tii tsi' rs' spl_first + apply(cases tsi) + subgoal for tsia tsin + supply R = split\<^sub>i_leafs_rule[of ts tsi' rs' "butlast spl_first" "(zip (zip (subtrees tsi') (zip (butlast (r # rs')) (zip rs' (butlast spl_first)))) + (separators tsi'))" r z] + thm R + apply (vcg heap add: R) + subgoal using \sorted_less (separators ts)\ by linarith + subgoal by simp + subgoal by simp + subgoal by (simp add: butlast.simps) + thm split_relation_alt + apply simp + apply(rule norm_pre_ex_rule) + apply(auto simp add: split_relation_alt list_assn_append_Cons_left dest!: mod_starD list_assn_len)[] + apply(rule norm_pre_ex_rule)+ + apply(rule hoare_triple_preI) + subgoal for spl lsi subsepi rsi + apply(cases subsepi) + subgoal for zz sepi + apply(cases zz) + subgoal for subi subp subfwd sublptrs + apply(vcg) +(* correct path *) + subgoal for _ _ suba sepa + apply(subgoal_tac "lsi = take (length ls) (zip (zip (subtrees tsi') (zip (butlast (r # rs')) (zip rs' spl))) + (separators tsi'))") + prefer 2 + subgoal proof (goal_cases) + case 1 + have *: "length lsi = length ls" + using 1 by (auto dest!: mod_starD list_assn_len) + then have "take (length ls) (zip (zip (subtrees tsi') (zip (butlast (r # rs')) (zip rs' spl))) (separators tsi')) = + take (length ls) (lsi @ ((subi, subp, subfwd, sublptrs), sepi) # rsi)" + using 1 by auto + also have "\ = lsi" + using * by auto + finally show ?case .. + qed + apply(subgoal_tac "rsi = drop (length ls+1) (zip (zip (subtrees tsi') (zip (butlast (r # rs')) (zip rs' spl))) + (separators tsi'))") + prefer 2 + subgoal proof (goal_cases) + case 1 + have *: "length lsi = length ls" + using 1 by (auto dest!: mod_starD list_assn_len) + then have "drop (length ls+1) (zip (zip (subtrees tsi') (zip (butlast (r # rs')) (zip rs' spl))) (separators tsi')) = + drop (length ls+1) (lsi @ ((subi, subp, subfwd, sublptrs), sepi) # rsi)" + using 1 by auto + also have "\ = rsi" + using * by auto + finally show ?case .. + qed + apply(subgoal_tac "subtrees tsi' = (take (length ls) (subtrees tsi'))@subi#(drop (length ls+1) (subtrees tsi'))") + prefer 2 + subgoal proof (goal_cases) + case 1 + have "length spl = length tsi'" "length tsi' = length rs'" + using 1 by auto + then have "subtrees tsi' = map fst (map fst ((zip (zip (subtrees tsi') (zip (butlast (r # rs')) (zip rs' spl))) + (separators tsi'))))" + by simp + also have "\ = map fst (map fst (lsi @ ((subi, subp, subfwd, sublptrs), sepi) # rsi))" + using 1 by simp + also have "\ = map fst (map fst (lsi)) @ subi # map fst (map fst (rsi))" + by auto + also have "\ = (take (length ls) (subtrees tsi')) @ subi # (drop (length ls +1) (subtrees tsi'))" + using 1 by (auto simp add: take_map[symmetric] drop_map[symmetric]) + finally show ?case . + qed + apply(subgoal_tac "separators tsi' = (take (length ls) (separators tsi'))@sepi#(drop (length ls+1) (separators tsi'))") + prefer 2 + subgoal proof (goal_cases) + case 1 + have "length spl = length tsi'" "length tsi' = length rs'" + using 1 by auto + then have "separators tsi' = map snd ((zip (zip (subtrees tsi') (zip (butlast (r # rs')) (zip rs' spl))) + (separators tsi')))" + by simp + also have "\ = map snd (lsi @ ((subi, subp, subfwd, sublptrs), sepi) # rsi)" + using 1 by simp + also have "\ = map snd (lsi) @ sepi # map snd (rsi)" + by auto + also have "\ = (take (length ls) (separators tsi')) @ sepi # (drop (length ls +1) (separators tsi'))" + using 1 by (auto simp add: take_map[symmetric] drop_map[symmetric]) + finally show ?case . + qed + apply(subgoal_tac "spl = (take (length ls) spl)@sublptrs#(drop (length ls+1) spl)") + prefer 2 + subgoal proof (goal_cases) + case 1 + have "length spl = length tsi'" "length tsi' = length rs'" + using 1 by auto + then have "spl = map snd (map snd (map snd (map fst ((zip (zip (subtrees tsi') (zip (butlast (r # rs')) (zip rs' spl))) + (separators tsi'))))))" + by simp + also have "\ = map snd (map snd (map snd (map fst (lsi @ ((subi, subp, subfwd, sublptrs), sepi) # rsi))))" + using 1 by simp + also have "\ = map snd (map snd (map snd (map fst (lsi)))) @ sublptrs # map snd (map snd (map snd (map fst (rsi))))" + by auto + also have "\ = (take (length ls) spl) @ sublptrs # (drop (length ls +1) spl)" + using 1 by (auto simp add: take_map[symmetric] drop_map[symmetric]) + finally show ?case . + qed + apply(subgoal_tac "rs' = (take (length ls) rs')@subfwd#(drop (length ls+1) rs')") + prefer 2 + subgoal proof (goal_cases) + case 1 + have "length spl = length tsi'" "length tsi' = length rs'" + using 1 by auto + then have "rs' = map fst (map snd (map snd (map fst ((zip (zip (subtrees tsi') (zip (butlast (r # rs')) (zip rs' spl))) + (separators tsi'))))))" + by simp + also have "\ = map fst (map snd (map snd (map fst (lsi @ ((subi, subp, subfwd, sublptrs), sepi) # rsi))))" + using 1 by simp + also have "\ = map fst (map snd (map snd (map fst (lsi)))) @ subfwd # map fst (map snd (map snd (map fst (rsi))))" + by auto + also have "\ = (take (length ls) rs') @ subfwd # (drop (length ls +1) rs')" + using 1 by (auto simp add: take_map[symmetric] drop_map[symmetric]) + finally show ?case . + qed + apply(subgoal_tac "butlast (r#rs') = (take (length ls) (butlast (r#rs')))@subp#(drop (length ls+1) (butlast (r#rs')))") + prefer 2 + subgoal proof (goal_cases) + case 1 + have "length spl = length tsi'" "length tsi' = length rs'" + using 1 by auto + then have "butlast (r#rs') = (map fst (map snd (map fst ((zip (zip (subtrees tsi') (zip (butlast (r # rs')) (zip rs' spl))) + (separators tsi'))))))" + by simp + also have "\ = map fst (map snd (map fst (lsi @ ((subi, subp, subfwd, sublptrs), sepi) # rsi)))" + using 1 by simp + also have "\ = map fst (map snd (map fst (lsi))) @ subp # map fst (map snd (map fst (rsi)))" + by auto + also have "\ = (take (length ls) (butlast (r#rs'))) @ subp # (drop (length ls +1) (butlast (r#rs')))" + using 1 by (auto simp add: take_map[symmetric] drop_map[symmetric]) + finally show ?case . + qed + apply(subgoal_tac "subsepi = ((suba, subp, subfwd, sublptrs), sepa)", simp) + prefer 2 + subgoal proof (goal_cases) + case assms: 1 + have "subi = suba" "sepi = sepa" + proof(goal_cases) + case 1 + have "subtrees tsi' ! (length ls) = subi" + by (metis append_take_drop_id assms(20) nth_via_drop same_append_eq) + moreover have "subtrees tsi' ! (length ls) = suba" + using assms by simp + ultimately show ?case by simp + next + case 2 + have "separators tsi' ! (length ls) = sepi" + by (metis append_take_drop_id assms(21) nth_via_drop same_append_eq) + moreover have "separators tsi' ! (length ls) = sepa" + using assms by simp + ultimately show ?case by simp + qed + then show ?case + using assms by auto + qed + supply R = "2.IH"(2)[OF split_pair[symmetric] Cons subsep_split[symmetric], of sep] + thm R + apply(vcg heap add: R) + subgoal using "2.prems" by simp + subgoal + using "2.prems"(2) assms(1) root_order.simps(2) + by (auto dest!: order_impl_root_order[of k sub, OF assms(1)]) + subgoal + using "2.prems"(3) split_pair Cons subsep_split Laligned_sub[of ls sub sep rrs] + by simp + apply (sep_auto eintros del: exI) + subgoal for y lptrs xs1 lptrs1 lptrs2 + thm blist_leafs_assn_split + apply(inst_existentials "concat ((take (length ls) spl)@lptrs#(drop (Suc (length ls)) spl)@[last spl_first])" "concat (map (leaf_nodes \ fst) ls) @ xs1" +"concat (take (length ls) spl) @ lptrs1" "lptrs2 @ (concat (drop (Suc (length ls)) spl))@last spl_first" +tsia tsin tii tsi' "zip (zip (subtrees tsi') (zip (butlast (r # rs')) (zip rs' (butlast ((take (length ls) spl)@lptrs#(drop (Suc (length ls)) spl)@[last spl_first]))))) + (separators tsi')" rs' "(take (length ls) spl)@lptrs#(drop (Suc (length ls)) spl)@[last spl_first]" "(take (length ls) + (zip (zip (subtrees tsi') (zip (butlast (r # rs')) (zip rs' spl))) + (separators tsi')))" subi subp subfwd lptrs sepi "(drop (Suc (length ls)) + (zip (zip (subtrees tsi') (zip (butlast (r # rs')) (zip rs' ((take (length ls) spl)@lptrs#(drop (length ls+1) spl))))) + (separators tsi')))") + (*apply(inst_existentials "concat (spl@[lptrs])" "concat (map (leaf_nodes \ fst) ts) @ xs1" "(concat (butlast spl)) @ lptrs1" lptrs2 + tsia tsin tii tsi' "(zip (zip (subtrees tsi') (zip (butlast (r # rrs)) (zip rrs (butlast spl)))) + (separators tsi'))" rrs spl)*) + subgoal + find_theorems "butlast" "_@[_]" + apply (auto) + proof (goal_cases) + case (1 a b) + have *: "(take (length ls) spl @ (lptrs1 @ lptrs2) # drop (Suc (length ls)) spl @ [last spl_first]) + = ((take (length ls) spl @ (lptrs1 @ lptrs2) # drop (Suc (length ls)) spl) @ [last spl_first])" + by auto + have **: + "subtrees tsi' = take (length ls) (subtrees tsi') @ subi # drop (Suc (length ls)) (subtrees tsi')" + "separators tsi' = take (length ls) (separators tsi') @ sepi # drop (Suc (length ls)) (separators tsi')" + "spl = take (length ls) spl @ sublptrs # drop (Suc (length ls)) spl" + "rs' = take (length ls) rs' @ subfwd # drop (Suc (length ls)) rs'" + "butlast (r # rs') = + take (length ls) (butlast (r # rs')) @ + subp # drop (Suc (length ls)) (butlast (r # rs'))" + using 1 by simp_all + have drop_sep_tsi': "drop (length ls) (separators tsi') = sepi#(drop (length ls+1) (separators tsi'))" + proof - + have "take (length ls) (separators tsi') @ drop (length ls) (separators tsi') = take (length ls) (separators tsi')@sepi#(drop (length ls+1) (separators tsi'))" + using 1 by auto + then show ?thesis + by (meson same_append_eq) + qed + have drop_sub_tsi': "drop (length ls) (subtrees tsi') = subi#(drop (length ls+1) (subtrees tsi'))" + proof - + have "take (length ls) (subtrees tsi') @ drop (length ls) (subtrees tsi') = take (length ls) (subtrees tsi')@subi#(drop (length ls+1) (subtrees tsi'))" + using 1 by auto + then show ?thesis + by (meson same_append_eq) + qed + have drop_rs': "drop (length ls) rs' = subfwd#(drop (length ls+1) rs')" + proof - + have "take (length ls) rs' @ drop (length ls) rs' = take (length ls) rs'@subfwd#(drop (length ls+1) rs')" + using 1 by auto + then show ?thesis + by (meson same_append_eq) + qed + have drop_butlastrs': "drop (length ls) (butlast (r#rs')) = subp#(drop (length ls+1) (butlast (r#rs')))" + proof - + have "take (length ls) (butlast (r#rs')) @ drop (length ls) (butlast (r#rs')) = take (length ls) (butlast (r#rs'))@subp#(drop (length ls+1) (butlast (r#rs')))" + using 1 by auto + then show ?thesis + by (meson same_append_eq) + qed + have "length tsi' = length rs'" "length spl = length rs'" "length ls \ length rs'" + using 1 by auto + then show ?case + apply(subst *) + apply(subst butlast_snoc) + find_theorems "zip" "_@_" + apply(subst(2) zip_append2) + apply(subst(2) zip_append2) + apply(subst(2) zip_append2) + apply(subst zip_append1) + find_theorems min "_ \ _" + apply (simp add: min.absorb2) + find_theorems "zip" "_#_" + find_theorems zip take + apply(simp add: take_zip) + apply(subst drop_sep_tsi') + apply(subst drop_sub_tsi') + apply(subst drop_rs') + apply(subst drop_butlastrs') + apply(simp add: drop_zip min.absorb2) + done + qed + subgoal + find_theorems butlast take + apply(simp add: take_zip drop_zip) + apply(simp add: take_butlast_Suc) + apply(subgoal_tac "drop (Suc (length ls)) (butlast (r # rs')) = butlast (subfwd#(drop (Suc (length ls)) rs'))") + apply (simp add: take_map drop_map) + thm blist_leafs_assn_split + supply R = blist_leafs_assn_split[of + "take (length ls) tsi'" + "take (length ls) rs'" + "take (length ls) spl" + k ls + ] + thm R + find_theorems map take + apply(subst blist_leafs_assn_split) + subgoal by simp + subgoal + by (auto dest!: mod_starD list_assn_len) + apply(subst blist_leafs_assn_split) + subgoal by simp + subgoal + by (auto dest!: mod_starD list_assn_len) + apply(clarsimp) + apply(rule entails_preI) + apply(subst leaf_nodes_assn_split2) + subgoal + by (auto dest!: mod_starD leaf_nodes_assn_impl_length) + apply(subst leaf_nodes_assn_split2) + subgoal + by (auto dest!: mod_starD leaf_nodes_assn_impl_length) + apply(subst leaf_nodes_assn_split2) + subgoal + by (auto dest!: mod_starD leaf_nodes_assn_impl_length) + apply(subst bplustree_leaf_nodes_sep)+ + apply (sep_auto eintros del: exI) + apply(inst_existentials subfwd "(last (subfwd # drop (Suc (length ls)) rs'))" "(last (r # take (length ls) rs'))") + apply(subgoal_tac "last (subfwd # drop (Suc (length ls)) rs') = last (r#rs')") + apply(subgoal_tac "(last (r # take (length ls) rs')) = subp") + apply(simp add: last.simps) + apply (solve_entails) + proof(goal_cases) + case (1 a b) + then have *: "length ls < length rs'" + by simp + have "butlast (r # rs') = + butlast (r # take (length ls) rs') @ subp # butlast (subfwd # drop (Suc (length ls)) rs')" + using 1 by simp + then have "take (length ls + 1) (butlast (r #rs')) = butlast (r # take (length ls) rs') @ [subp]" + using * by simp + then have "butlast (r # rs') ! (length ls) = subp" + using * take_Suc_conv_app_nth[of "length ls" "butlast (r#rs')"] + by simp + then have obt:"(r # rs') ! (length ls) = subp" + using nth_butlast[of "length ls" "r#rs'"] * by auto + have **: "r#(take (length ls) rs') = take (length ls +1) (r#rs')" + by simp + show ?case + apply (subst **) + apply(subst last_take_nth_conv) + using obt * by auto + next + case (2 a b) + then have "rs' = take (length ls) rs' @ subfwd # drop (Suc (length ls)) rs'" + by simp + then have "r#rs' = (r#take (length ls) rs') @ subfwd # drop (Suc (length ls)) rs'" + by simp + then have "last(r#rs') = last((r#take (length ls) rs') @ subfwd # drop (Suc (length ls)) rs')" + by simp + also have "\ = last(subfwd # drop (Suc (length ls)) rs')" + thm last_append[of "r#take (length ls) rs'"] + using last_append[of "r#take (length ls) rs'"] + by simp + finally show ?case .. + next + case 3 + have "drop (Suc (length ls)) (butlast (r # rs')) = butlast (drop (Suc (length ls)) (r#rs'))" + by (auto simp add: butlast.simps butlast_drop) + also have "\ = butlast (drop (length ls) rs')" + by simp + also have "\ = butlast (subfwd # drop (Suc (length ls)) rs')" + proof - + have *:"rs' = take (length ls) rs' @ subfwd # drop (Suc (length ls)) rs'" + using 3 by simp + have "length ls < length rs'" + using 3 by simp + then have "drop (length ls) rs' = subfwd # drop (Suc (length ls)) rs'" + apply(subst *) + by (simp add: min.absorb1 min.absorb2) + then show ?thesis by simp + qed + finally show ?case . + qed + done + done + subgoal + apply(rule hoare_triple_preI) + subgoal by (auto simp add: split_relation_alt dest!: mod_starD list_assn_len arg_cong[of _ _ length])[] + done + done + done + done + done + done + done + qed +qed +declare last.simps[simp add] butlast.simps[simp add] + +(*fun concat_leaf_nodes_lrange\<^sub>i where + "concat_leaf_nodes_lrange\<^sub>i t x = (case leaf_nodes_lrange\<^sub>i t x of (Leaf ks)#list \ lrange_list x ks @ (concat (map leaves list)))" +*) + +definition concat_leaf_nodes_lrange\<^sub>i where +"concat_leaf_nodes_lrange\<^sub>i ti x = do { + lp \ leaf_nodes_lrange\<^sub>i ti x; + li \ !(the lp); + case li of Btleaf xs nxt \ do { + arr_it \ lrange_list\<^sub>i x xs; + fla_it \ leaf_values_adjust (nxt,None) arr_it; + return fla_it + } +}" + +lemma sorted_less_leaf_nodes: "sorted_less (leaves t) \ (Leaf ks) \ set (leaf_nodes t) \ sorted_less ks" +proof(induction t arbitrary: ks rule: leaf_nodes.induct) + case (1 xs) + then show ?case by simp +next + case I: (2 ts t) + then have "(\x \ set ts. Leaf ks \ set (leaf_nodes (fst x))) \ Leaf ks \ set (leaf_nodes t)" + by simp + then show ?case + proof(standard, goal_cases) + case 1 + then show ?case + using I + by (metis (no_types, lifting) in_set_conv_decomp list.simps(9) map_append sorted_leaves_subtrees) + next + case 2 + then show ?case + using I + by (meson sorted_leaves_induct_last) + qed +qed + +lemmas leaf_values_adjust_rule = leaf_values_iter.flatten_it_adjust_rule + +lemma concat_leaf_nodes_lrange\<^sub>i_rule_help: + assumes "k > 0" "root_order k t" "sorted_less (leaves t)" "Laligned t u" + shows " +concat_leaf_nodes_lrange\<^sub>i ti x +\<^sub>t" + apply(subst concat_leaf_nodes_lrange\<^sub>i_def) + apply(vcg (ss) heap: leaf_nodes_lrange\<^sub>i_rule[of k t u])+ + subgoal using assms by simp + subgoal using assms by simp + subgoal using assms by simp + apply simp + apply(rule norm_pre_ex_rule)+ + apply(rule hoare_triple_preI) + apply(auto dest!: mod_starD) +proof(goal_cases) + case (1 l xs1 lptrs1 lptrs2) + obtain ks list where *[simp]: "abs_split_range.leaf_nodes_lrange t x = (Leaf ks)#list \ (Leaf ks) \ set (leaf_nodes t)" + using abs_split_range.leaf_nodes_lrange_not_empty by blast + then obtain r' lptrs2' where [simp]: "lptrs2 = r' # lptrs2'" + using 1 + by (metis Suc_length_conv leaf_nodes_assn_impl_length) + have sorted_less_ks: "sorted_less ks" + using \abs_split_range.leaf_nodes_lrange t x = Leaf ks # list \ Leaf ks \ set (leaf_nodes t)\ assms(3) sorted_less_leaf_nodes split\<^sub>i_range_axioms by blast + then obtain pref where ks_split: "ks = pref @ lrange_list x ks" + proof (goal_cases) + case 1 + have "suffix (lrange_list x ks) ks" + by (metis \sorted_less ks\ abs_split_range.lrange_list_req lrange_suffix sorted_less_lrange) + then have "\pref. ks = pref @ lrange_list x ks" + by (meson suffixE) + then show ?case + using 1 + by blast + qed + show ?case + proof(cases l) + case None + show ?thesis + apply(rule hoare_triple_preI) + using None by simp + next + case (Some a) + then show ?thesis + apply simp + apply(rule norm_pre_ex_rule)+ + apply vcg + apply simp + subgoal for xsi fwd + apply(cases xsi) + apply simp + thm lrange_list_rule + using sorted_less_ks apply (vcg heap: lrange_list_rule) + apply(subst leaf_nodes_assn_flatten)+ + apply(simp) + apply(rule norm_pre_ex_rule)+ + subgoal for ksia ksin it ps2 ps1 + supply R = fi_rule[ + OF leaf_values_adjust_rule, + where F="list_assn leaf_node (leaf_nodes t) (leaf_lists t) * + trunk_assn k t ti r None (lptrs1 @ r' # lptrs2') * + true"] + thm R + supply R' = R[of _ k "map leaves xs1" ps1 "map leaves list" ps2 "(ksia,ksin)" + "lptrs1@r'#lptrs2'" r "(fwd,None)" pref "lrange_list x ks" it] + thm R' + apply(vcg heap: R') + apply(subst leaf_iter_assn_def) + apply simp + subgoal + apply(inst_ex_assn "ps1@[(ksia,ksin)]" "lptrs1@[r']" lptrs2') + apply sep_auto + subgoal + apply(rule entails_preI) + apply(subst leafs_assn_aux_append) + subgoal by (auto dest!: mod_starD leafs_assn_impl_length) + subgoal + apply simp + apply(inst_ex_assn "Some r'") + subgoal using 1(1) ks_split by sep_auto + done + done + done + subgoal + apply (sep_auto eintros del: exI simp add: bplustree_iter_def) + apply(inst_existentials "lptrs1@lptrs2") + apply(subgoal_tac "leaves t = (concat (map leaves xs1) @ pref @ lrange_list x ks @ concat (map leaves list))") + apply(subgoal_tac "abs_split_range.lrange t x = (lrange_list x ks @ concat (map leaves list))") + subgoal using 1(1) 1(2) ks_split by sep_auto + subgoal by (metis \abs_split_range.leaf_nodes_lrange t x = Leaf ks # list \ Leaf ks \ set (leaf_nodes t)\ abs_split_range.split_range_axioms split_range.leaf_nodes_lrange_pre_lrange) + subgoal + using concat_leaf_nodes_leaves[symmetric, of t] 1(1) ks_split + by auto + done + done + done + done + qed +qed + +lemma concat_leaf_nodes_lrange\<^sub>i_rule: + assumes "k > 0" "root_order k t" "sorted_less (leaves t)" "Laligned t u" + shows " +concat_leaf_nodes_lrange\<^sub>i ti x +\<^sub>t" + find_theorems bplustree_assn_leafs + apply(simp add: bplustree_extract_leafs) + using assms apply(sep_auto heap add: concat_leaf_nodes_lrange\<^sub>i_rule_help) + done + +end + +context split\<^sub>i_list +begin + +definition lrange_list\<^sub>i:: "'a \ ('a::{heap,default,linorder,order_top}) pfarray \ 'a pfa_it Heap" + where "lrange_list\<^sub>i x ks = do { + i \ split\<^sub>i_list ks x; + return (ks, i) +}" + +lemma lrange_list\<^sub>i_rule [sep_heap_rules]: + assumes "sorted_less ks" + shows + " + lrange_list\<^sub>i x (a',n') + \<^sub>t" +proof - + obtain ls rs where list_split: "split_list ks x = (ls, rs)" + by (cases "split_list ks x") + then have "lrange_list x ks = rs" + by (simp add: abs_split_list.lrange_filter_split assms) + moreover have "ks = ls@rs" + using abs_split_list.split_list_req(1) list_split by blast + ultimately show ?thesis + apply(subst lrange_list\<^sub>i_def) + using assms list_split abs_split_list.lrange_split_req + apply(sep_auto simp add: sorted_less_lrange pfa_is_it_def split_relation_alt list_assn_append_Cons_left dest!: mod_starD list_assn_len) + done +qed +end + +context split\<^sub>i_full +begin + +sublocale split\<^sub>i_range split split\<^sub>i_list.abs_split_list.lrange_split split\<^sub>i split\<^sub>i_list.lrange_list\<^sub>i + using split\<^sub>i_list.abs_split_list.lrange_split_req split\<^sub>i_list.lrange_list\<^sub>i_rule + apply unfold_locales + apply sep_auto + + done + +end + + + +end \ No newline at end of file diff --git a/thys/BTree/BPlusTree_ImpSet.thy b/thys/BTree/BPlusTree_ImpSet.thy new file mode 100644 --- /dev/null +++ b/thys/BTree/BPlusTree_ImpSet.thy @@ -0,0 +1,1691 @@ +theory BPlusTree_ImpSet + imports + BPlusTree_Set + BPlusTree_ImpSplit + "HOL-Real_Asymp.Inst_Existentials" +begin + +section "Imperative Set operations" + +subsection "Auxiliary operations" + + +text "This locale extends the abstract split locale, +assuming that we are provided with an imperative program +that refines the abstract split function." + + +(* TODO separate into split_tree and split + split_list *) +locale split\<^sub>i_set = abs_split_set: split_set split + split\<^sub>i_tree split split\<^sub>i + for split:: + "('a bplustree \ 'a::{heap,default,linorder,order_top}) list \ 'a + \ ('a bplustree \ 'a) list \ ('a bplustree \ 'a) list" + and split\<^sub>i :: "('a btnode ref option \ 'a::{heap,default,linorder,order_top}) pfarray \ 'a \ nat Heap" + + fixes isin_list\<^sub>i:: "'a \ ('a::{heap,default,linorder,order_top}) pfarray \ bool Heap" + and ins_list\<^sub>i:: "'a \ ('a::{heap,default,linorder,order_top}) pfarray \ 'a pfarray Heap" + and del_list\<^sub>i:: "'a \ ('a::{heap,default,linorder,order_top}) pfarray \ 'a pfarray Heap" + assumes isin_list_rule [sep_heap_rules]:"sorted_less ks \ + + isin_list\<^sub>i x (a',n') + <\b. + is_pfa c ks (a',n') + * \(isin_list x ks = b)>\<^sub>t" + and ins_list_rule [sep_heap_rules]:"sorted_less ks' \ + + ins_list\<^sub>i x (a',n') + <\(a'',n''). is_pfa (max c (length (insert_list x ks'))) (insert_list x ks') (a'',n'') >\<^sub>t" + and del_list_rule [sep_heap_rules]:"sorted_less ks'' \ + + del_list\<^sub>i x (a',n') + <\(a'',n''). is_pfa c (delete_list x ks'') (a'',n'') >\<^sub>t" +begin + +subsection "Initialization" + +definition empty\<^sub>i ::"nat \ 'a btnode ref Heap" + where "empty\<^sub>i k = do { + empty_list \ pfa_empty (2*k); + empty_leaf \ ref (Btleaf empty_list None); + return empty_leaf +}" + +lemma empty\<^sub>i_rule: + shows " + empty\<^sub>i k + <\r. bplustree_assn k (abs_split_set.empty_bplustree) r (Some r) None>" + apply(subst empty\<^sub>i_def) + apply(sep_auto simp add: abs_split_set.empty_bplustree_def) + done + +subsection "Membership" + +(* TODO introduce imperative equivalents to searching/inserting/deleting in a list *) +partial_function (heap) isin\<^sub>i :: "'a btnode ref \ 'a \ bool Heap" + where + "isin\<^sub>i p x = do { + node \ !p; + (case node of + Btleaf xs _ \ isin_list\<^sub>i x xs | + Btnode ts t \ do { + i \ split\<^sub>i ts x; + tsl \ pfa_length ts; + if i < tsl then do { + s \ pfa_get ts i; + let (sub,sep) = s in + isin\<^sub>i (the sub) x + } else + isin\<^sub>i t x + } +)}" + +lemma nth_zip_zip: + assumes "length ys = length xs" + and "length zs = length xs" + and "zs1 @ ((suba', x), sepa') # zs2 = + zip (zip ys xs) zs" + shows "suba' = ys ! length zs1 \ + sepa' = zs ! length zs1 \ + x = xs ! length zs1" +proof - + obtain suba'' x' sepa'' where "zip (zip ys xs) zs ! length zs1 = ((suba'', x'), sepa'')" + by (metis surj_pair) + moreover have "((suba'', x'), sepa'') = ((suba', x), sepa')" + by (metis calculation assms(3) nth_append_length) + moreover have "length zs1 < length xs" + proof - + have "length (zip (zip ys xs) zs) = length xs" + by (simp add: assms(1,2)) + then have "length zs1 + 1 + length zs2 = length xs" + by (metis assms(1,3) group_cancel.add1 length_Cons length_append plus_1_eq_Suc) + then show ?thesis + by (simp add: assms(1)) + qed + ultimately show ?thesis + using assms(1,2) by auto +qed + + +lemma "k > 0 \ root_order k t \ sorted_less (inorder t) \ sorted_less (leaves t) \ + + isin\<^sub>i ti x + <\y. bplustree_assn k t ti r z * \(abs_split_set.isin t x = y)>\<^sub>t" +proof(induction t x arbitrary: ti r z rule: abs_split_set.isin.induct) + case (1 x r z) + then show ?case + apply(subst isin\<^sub>i.simps) + apply sep_auto + done +next + case (2 ts t x ti r z) + obtain ls rs where list_split[simp]: "split ts x = (ls,rs)" + by (cases "split ts x") + moreover have ts_non_empty: "length ts > 0" + using "2.prems"(2) root_order.simps(2) by blast + moreover have "sorted_less (separators ts)" + using "2.prems"(3) sorted_inorder_separators by blast + ultimately show ?case + proof (cases rs) + (* NOTE: induction condition trivial here *) + case [simp]: Nil + show ?thesis + apply(subst isin\<^sub>i.simps) + using ts_non_empty apply(sep_auto) + subgoal using \sorted_less (separators ts)\ by blast + apply simp + apply sep_auto + apply(rule hoare_triple_preI) + apply (sep_auto) + subgoal for a b ti tsi' rs x sub sep + apply(auto simp add: split_relation_alt is_pfa_def dest!: mod_starD list_assn_len)[] + done + thm "2.IH"(1)[of ls "[]"] + using 2(3) apply(sep_auto heap: "2.IH"(1)[of ls "[]"] simp add: sorted_wrt_append) + subgoal + using "2.prems"(2) order_impl_root_order + by (auto simp add: split_relation_alt is_pfa_def dest!: mod_starD list_assn_len)[] + subgoal + using "2.prems"(3) sorted_inorder_induct_last + by (auto simp add: split_relation_alt is_pfa_def dest!: mod_starD list_assn_len)[] + subgoal using "2"(6) sorted_leaves_induct_last + by (auto simp add: split_relation_alt is_pfa_def dest!: mod_starD list_assn_len)[] + using 2(3) apply(sep_auto heap: "2.IH"(1)[of ls "[]"] simp add: sorted_wrt_append) + done + next + case [simp]: (Cons h rrs) + obtain sub sep where h_split[simp]: "h = (sub,sep)" + by (cases h) + then show ?thesis + apply(simp split: list.splits prod.splits) + apply(subst isin\<^sub>i.simps) + using "2.prems" sorted_inorder_separators + apply(sep_auto) + (* simplify towards induction step *) + apply(auto simp add: split_relation_alt list_assn_append_Cons_left dest!: mod_starD list_assn_len)[] +(* NOTE show that z = (suba, sepa) -- adjusted since we now contain also current pointers and forward pointers *) + apply(rule norm_pre_ex_rule)+ + apply(rule hoare_triple_preI) + subgoal for tsi n ti tsi' pointers suba sepa zs1 z zs2 + apply(cases z) + subgoal for subacomb sepa' + apply(cases subacomb) + subgoal for suba' subp subfwd + apply(subgoal_tac "z = ((suba, subp, subfwd), sepa)", simp) + thm "2.IH"(2)[of ls rs h rrs sub sep "(the suba')" subp subfwd] + using 2(3,4,5,6) apply(sep_auto + heap:"2.IH"(2)[of ls rs h rrs sub sep "the suba'" subp subfwd] + simp add: sorted_wrt_append) + using list_split Cons h_split apply simp_all + subgoal + by (meson "2.prems"(1) order_impl_root_order) + subgoal + apply(rule impI) + apply(inst_ex_assn "(tsi,n)" "ti" "tsi'" "(zs1 @ ((suba', subp, subfwd), sepa') # zs2)" "pointers" "zs1" "z" "zs2") + (* proof that previous assumptions hold later *) + apply sep_auto + done + subgoal + (* prove subgoal_tac assumption *) + using nth_zip_zip[of "subtrees tsi'" "zip (r # butlast pointers) pointers" "separators tsi'" zs1 suba' "(subp, subfwd)" sepa' zs2] + apply(auto simp add: split_relation_alt list_assn_append_Cons_left dest!: mod_starD list_assn_len)[] + done + done + done + done + (* eliminate last vacuous case *) + apply(rule hoare_triple_preI) + apply(auto simp add: split_relation_def dest!: mod_starD list_assn_len)[] + done + qed +qed + +subsection "Insertion" + + +datatype 'c btupi = + T\<^sub>i "'c btnode ref" | + Up\<^sub>i "'c btnode ref" "'c" "'c btnode ref" + +fun btupi_assn where + "btupi_assn k (abs_split_set.T\<^sub>i l) (T\<^sub>i li) r z = + bplustree_assn k l li r z" | +(*TODO ai is not necessary not in the heap area of li *) + "btupi_assn k (abs_split_set.Up\<^sub>i l a r) (Up\<^sub>i li ai ri) r' z' = + (\\<^sub>A newr. bplustree_assn k l li r' newr * bplustree_assn k r ri newr z' * id_assn a ai)" | + "btupi_assn _ _ _ _ _ = false" + + +(* TODO take in a pointer ot a btnode instead, only create one new node *) +definition node\<^sub>i :: "nat \ 'a btnode ref \ 'a btupi Heap" where + "node\<^sub>i k p \ do { + pt \ !p; + let a = kvs pt; ti = lst pt in do { + n \ pfa_length a; + if n \ 2*k then do { + a' \ pfa_shrink_cap (2*k) a; + p := Btnode a' ti; + return (T\<^sub>i p) + } + else do { + b \ (pfa_empty (2*k) :: ('a btnode ref option \ 'a) pfarray Heap); + i \ split_half a; + m \ pfa_get a (i-1); + b' \ pfa_drop a i b; + a' \ pfa_shrink (i-1) a; + a'' \ pfa_shrink_cap (2*k) a'; + let (sub,sep) = m in do { + p := Btnode a'' (the sub); + r \ ref (Btnode b' ti); + return (Up\<^sub>i p sep r) + } + } + } +}" + +definition Lnode\<^sub>i :: "nat \ 'a btnode ref \ 'a btupi Heap" where + "Lnode\<^sub>i k p \ do { + pt \ !p; + let a = vals pt; nxt = fwd pt in do { + n \ pfa_length a; + if n \ 2*k then do { + a' \ pfa_shrink_cap (2*k) a; + p := Btleaf a' nxt; + return (T\<^sub>i p) + } + else do { + b \ (pfa_empty (2*k) :: 'a pfarray Heap); + i \ split_half a; + m \ pfa_get a (i-1); + b' \ pfa_drop a i b; + a' \ pfa_shrink i a; + a'' \ pfa_shrink_cap (2*k) a'; + r \ ref (Btleaf b' nxt); + p := Btleaf a'' (Some r); + return (Up\<^sub>i p m r) + } + } +}" + +(* TODO Lnode\<^sub>i allocates a new node when invoked, do not invoke if array didn't grow *) +partial_function (heap) ins\<^sub>i :: "nat \ 'a \ 'a btnode ref \ 'a btupi Heap" + where + "ins\<^sub>i k x p = do { + node \ !p; + (case node of + Btleaf ksi nxt \ do { + ksi' \ ins_list\<^sub>i x ksi; + p := Btleaf ksi' nxt; + Lnode\<^sub>i k p + } | + Btnode tsi ti \ do { + i \ split\<^sub>i tsi x; + tsl \ pfa_length tsi; + if i < tsl then do { + s \ pfa_get tsi i; + let (sub,sep) = s in do { + r \ ins\<^sub>i k x (the sub); + case r of (T\<^sub>i lp) \ do { + pfa_set tsi i (Some lp,sep); + return (T\<^sub>i p) + } | + (Up\<^sub>i lp x' rp) \ do { + pfa_set tsi i (Some rp,sep); + tsi' \ pfa_insert_grow tsi i (Some lp,x'); + p := Btnode tsi' ti; + node\<^sub>i k p + } + } + } + else do { + r \ ins\<^sub>i k x ti; + case r of (T\<^sub>i lp) \ do { + p := (Btnode tsi lp); + return (T\<^sub>i p) + } | (Up\<^sub>i lp x' rp) \ do { + tsi' \ pfa_append_grow' tsi (Some lp,x'); + p := Btnode tsi' rp; + node\<^sub>i k p + } + } + } +)}" + + +(*fun tree\<^sub>i::"'a up\<^sub>i \ 'a bplustree" where + "tree\<^sub>i (T\<^sub>i sub) = sub" | + "tree\<^sub>i (Up\<^sub>i l a r) = (Node [(l,a)] r)" + +fun insert::"nat \ 'a \ 'a bplustree \ 'a bplustree" where + "insert k x t = tree\<^sub>i (ins k x t)" +*) + +definition insert\<^sub>i :: "nat \ 'a \ 'a btnode ref \ 'a btnode ref Heap" where + "insert\<^sub>i \ \k x ti. do { + ti' \ ins\<^sub>i k x ti; + case ti' of + T\<^sub>i sub \ return sub | + Up\<^sub>i l a r \ do { + kvs \ pfa_init (2*k) (Some l,a) 1; + t' \ ref (Btnode kvs r); + return t' + } +}" + + +lemma take_butlast_prepend: "take n (butlast (r # pointers)) = + butlast (r # take n pointers)" + apply (cases "length pointers > n") + by (simp_all add: butlast_take take_Cons' take_butlast) + +lemma take_butlast_append: "take n (butlast (xs @ x # ys)) = + take n (xs @ (butlast (x#ys)))" + by (auto simp add: butlast_append) + +lemma map_eq_nth_eq_diff: + assumes A: "map f l = map g l'" + and B: "i < length l" + shows "f (l!i) = g (l'!i)" +proof - + from A have "length l = length l'" + by (metis length_map) + thus ?thesis using A B + apply (induct l l' arbitrary: i rule: list_induct2) + apply (simp) + subgoal for x xs y ys i + apply(cases i) + apply(simp add: nth_def) + apply simp + done + done +qed + +lemma "BPlusTree_Split.split_half ts = (ls,rs) \ length ls = Suc (length ts) div 2" + by (metis Suc_eq_plus1 split_half_conc) + +lemma take_half_less: "take (Suc (length ts) div 2) ts = ls @ [(sub, sep)] \ length ls < length ts" +proof - + assume " take (Suc (length ts) div 2) ts = ls @ [(sub, sep)]" + then have "ts \ []" + by force + then have "Suc (length ts) div 2 \ length ts" + by linarith + then have "length (take (Suc (length ts) div 2) ts) \ length ts" + by simp + moreover have "length ls < length (take (Suc (length ts) div 2) ts)" + by (simp add: \take (Suc (length ts) div 2) ts = ls @ [(sub, sep)]\) + ultimately show "length ls < length ts" + by linarith +qed + +declare abs_split_set.node\<^sub>i.simps [simp add] +declare last.simps[simp del] butlast.simps[simp del] +lemma node\<^sub>i_rule: assumes c_cap: "2*k \ c" "c \ 4*k+1" + and "length tsi' = length pointers" + and "tsi'' = zip (zip (map fst tsi') (zip (butlast (r#pointers)) (butlast (pointers@[z])))) (map snd tsi')" + shows "

\<^sub>r Btnode (a,n) ti * is_pfa c tsi' (a,n) * blist_assn k ts tsi'' * bplustree_assn k t ti (last (r#pointers)) z> + node\<^sub>i k p + <\u. btupi_assn k (abs_split_set.node\<^sub>i k ts t) u r z>\<^sub>t" +proof (cases "length ts \ 2*k") + case [simp]: True + then show ?thesis + apply(subst node\<^sub>i_def) + apply(rule hoare_triple_preI) + apply(sep_auto) + subgoal by (sep_auto simp add: is_pfa_def)[] + subgoal using c_cap by (sep_auto simp add: is_pfa_def)[] + subgoal using assms(3,4) by (sep_auto) + subgoal + apply(subgoal_tac "length ts = length tsi'") + subgoal using True by (sep_auto) + subgoal using True assms by (sep_auto dest!: mod_starD list_assn_len) + done + done +next + case [simp]: False + then obtain ls sub sep rs where + split_half_eq: "BPlusTree_Split.split_half ts = (ls@[(sub,sep)],rs)" + using abs_split_set.node\<^sub>i_cases by blast + then show ?thesis + apply(subst node\<^sub>i_def) + apply(rule hoare_triple_preI) + apply sep_auto + subgoal by (sep_auto simp add: split_relation_alt split_relation_length is_pfa_def dest!: mod_starD list_assn_len) + subgoal using assms by (sep_auto dest!: mod_starD list_assn_len) + subgoal + apply(subgoal_tac "length ts = length tsi'") + subgoal using False by (sep_auto dest!: mod_starD list_assn_len) + subgoal using assms(3,4) by (sep_auto dest!: mod_starD list_assn_len) + done + apply sep_auto + subgoal using c_cap by (sep_auto simp add: is_pfa_def)[] + subgoal using c_cap by (sep_auto simp add: is_pfa_def)[] + using c_cap apply sep_auto + subgoal using c_cap by (sep_auto simp add: is_pfa_def)[] + subgoal using c_cap by (sep_auto simp add: is_pfa_def)[] + using c_cap apply simp + apply(rule hoare_triple_preI) + apply(vcg) + apply(simp add: split_relation_alt) + apply(rule impI)+ + subgoal for _ _ rsia subi' sepi' rsin lsi _ + supply R = append_take_drop_id[of "(length ls)" ts,symmetric] + thm R + apply(subst R) + supply R = Cons_nth_drop_Suc[of "length ls" ts, symmetric] + thm R + apply(subst R) + subgoal + by (meson take_half_less) + supply R=list_assn_append_Cons_left[where xs="take (length ls) ts" and ys="drop (Suc (length ls)) ts" and x="ts ! (length ls)"] + thm R + apply(subst R) + apply(auto)[] + apply(rule ent_ex_preI)+ + apply(subst ent_pure_pre_iff; rule impI) + apply (simp add: prod_assn_def split!: prod.splits) + subgoal for tsi''l subi'' subir subinext sepi'' tsi''r sub' sep' + (* instantiate right hand side *) +(* newr is the first leaf of the tree directly behind sub + and (r#pointers) is the list of all first leafs of the tree in this node + \ the pointer at position of sub in pointers + or the pointer at position of sub+1 in (r#pointers) +*) + (* Suc (length tsi') div 2 - Suc 0) = length ls *) + apply(inst_ex_assn "subinext" "(rsia,rsin)" ti + "drop (length ls+1) tsi'" + "drop (length ls+1) tsi''" + "drop (length ls+1) pointers" + lsi + "the subi'" + "take (length ls) tsi'" + "take (length ls) tsi''" + "take (length ls) pointers" + ) + apply (sep_auto) + subgoal using assms(3) by linarith + subgoal + using assms(3,4) by (auto dest!: mod_starD + simp add: take_map[symmetric] take_zip[symmetric] take_butlast_prepend[symmetric] + ) + subgoal using assms(3,4) by (auto dest!: mod_starD + simp add: list_assn_prod_map id_assn_list_alt) + subgoal + apply(subgoal_tac "length ls < length pointers") + apply(subgoal_tac "subinext = pointers ! (length ls)") + subgoal + using assms(3,4) apply (auto + simp add: drop_map[symmetric] drop_zip[symmetric] drop_butlast[symmetric] Cons_nth_drop_Suc + )[] + supply R = drop_Suc_Cons[where n="length ls" and xs="butlast pointers" and x=r, symmetric] + thm R + apply(simp only: R drop_zip[symmetric]) + apply (simp add: last.simps butlast.simps) + done + subgoal apply(auto dest!: mod_starD list_assn_len) + proof (goal_cases) + case 1 + have "length ls < length tsi''" + using assms(3,4) "1" by auto + moreover have "subinext = snd (snd (fst (tsi'' ! length ls)))" + using 1 calculation by force + ultimately have "subinext = map snd (map snd (map fst tsi'')) ! length ls" + by auto + then show ?case + using assms(3,4) by auto + qed + subgoal apply(auto dest!: mod_starD list_assn_len) + proof (goal_cases) + case 1 + then have "length ls < length ts" + by (simp) + moreover have "length ts = length tsi''" + by (simp add: 1) + moreover have "\ = length pointers" + using assms(3,4) by auto + ultimately show ?case by simp + qed + done + apply(rule entails_preI) + (* introduce some simplifying equalities *) + apply(subgoal_tac "Suc (length tsi') div 2 = length ls + 1") + prefer 2 subgoal + apply(auto dest!: mod_starD list_assn_len) + proof (goal_cases) + case 1 + have "length tsi' = length tsi''" + using assms(3,4) by auto + also have "\ = length ts" + by (simp add: 1) + finally show ?case + using 1 + by (metis Suc_eq_plus1 abs_split_set.length_take_left div2_Suc_Suc length_append length_append_singleton numeral_2_eq_2) + qed + apply(subgoal_tac "length ts = length tsi''") + prefer 2 subgoal using assms(3,4) by (auto dest!: mod_starD list_assn_len) + apply(subgoal_tac "(sub', sep') = (sub, sep)") + prefer 2 subgoal + by (metis One_nat_def Suc_eq_plus1 Suc_length_conv abs_split_set.length_take_left length_0_conv length_append less_add_Suc1 nat_arith.suc1 nth_append_length nth_take) + apply(subgoal_tac "length ls = length tsi''l") + prefer 2 subgoal by (auto dest!: mod_starD list_assn_len) + apply(subgoal_tac "(subi'', sepi'') = (subi', sepi')") + prefer 2 subgoal + using assms(3,4) apply (auto dest!: mod_starD list_assn_len) + proof (goal_cases) + case 1 + then have "tsi'' ! length tsi''l = ((subi'', subir, subinext), sepi'')" + by auto + moreover have "length tsi''l < length tsi''" + by (simp add: 1) + moreover have "length tsi''l < length tsi'" + using "1" assms(3) by linarith + ultimately have + "fst (fst (tsi'' ! length tsi''l)) = fst (tsi' ! length tsi''l)" + "snd (tsi'' ! length tsi''l) = snd (tsi' ! length tsi''l)" + using assms(4) by auto + then show ?case + by (simp add: "1" \tsi'' ! length tsi''l = ((subi'', subir, subinext), sepi'')\) + case 2 + then show ?case + by (metis \snd (tsi'' ! length tsi''l) = snd (tsi' ! length tsi''l)\ \tsi'' ! length tsi''l = ((subi'', subir, subinext), sepi'')\ snd_conv) + qed + apply(subgoal_tac "(last (r # take (length ls) pointers)) = subir") + prefer 2 subgoal + using assms(3) apply (auto dest!: mod_starD list_assn_len) + proof (goal_cases) + case 1 + have "length tsi''l < length tsi''" + by (simp add: 1) + then have "fst (snd (fst (tsi'' ! length tsi''l))) = subir" + using 1 assms(4) by auto + moreover have "map fst (map snd (map fst tsi'')) = butlast (r#pointers)" + using assms(3,4) by auto + moreover have "(last (r#take (length ls) pointers)) = butlast (r#pointers) ! (length tsi''l)" + by (smt (z3) "1" One_nat_def Suc_eq_plus1 Suc_to_right abs_split_set.length_take_left append_butlast_last_id div_le_dividend le_add2 length_butlast length_ge_1_conv length_take lessI list.size(4) min_eq_arg(2) nth_append_length nth_take nz_le_conv_less take_Suc_Cons take_butlast_conv) + ultimately show ?case + using 1 apply auto + by (metis (no_types, opaque_lifting) 1 length_map map_map nth_append_length) + qed + apply(subgoal_tac "(last (subinext # drop (Suc (length tsi''l)) pointers)) = last (r#pointers)") + prefer 2 subgoal + using assms(3) apply (auto dest!: mod_starD list_assn_len) + proof (goal_cases) + case 1 + have "length tsi''l < length tsi''" + using 1 by auto + moreover have "subinext = snd (snd (fst (tsi'' ! length tsi''l)))" + using "1" calculation by force + ultimately have "subinext = map snd (map snd (map fst tsi'')) ! length tsi''l" + by auto + then have "subinext = pointers ! length tsi''l" + using assms(3,4) by auto + then have "(subinext # drop (Suc (length tsi''l)) pointers) = drop (length tsi''l) pointers" + by (metis 1 Cons_nth_drop_Suc Suc_eq_plus1 Suc_to_right abs_split_set.length_take_left div_le_dividend le_add1 less_Suc_eq nz_le_conv_less take_all_iff zero_less_Suc) + moreover have "last (drop (length tsi''l) pointers) = last pointers" + using \length tsi''l < length tsi''\ 1 by force + ultimately show ?case + by (auto simp add: last.simps butlast.simps) + qed + apply(subgoal_tac "take (length tsi''l) ts = ls") + prefer 2 subgoal + by (metis append.assoc append_eq_conv_conj append_take_drop_id) + apply(subgoal_tac "drop (Suc (length tsi''l)) ts = rs") + prefer 2 subgoal by (metis One_nat_def Suc_eq_plus1 Suc_length_conv append_eq_conv_conj append_take_drop_id length_0_conv length_append) + subgoal by (sep_auto) + done + done + done +qed +declare last.simps[simp add] butlast.simps[simp add] +declare abs_split_set.node\<^sub>i.simps [simp del] + +declare abs_split_set.Lnode\<^sub>i.simps [simp add] +lemma Lnode\<^sub>i_rule: + assumes "k > 0 " "r = Some a" "2*k \ c" "c \ 4*k" + shows "\<^sub>r (Btleaf xsi z) * is_pfa c xs xsi> + Lnode\<^sub>i k a + <\a. btupi_assn k (abs_split_set.Lnode\<^sub>i k xs) a r z>\<^sub>t" +proof (cases "length xs \ 2*k") + case [simp]: True + then show ?thesis + apply(subst Lnode\<^sub>i_def) + apply(rule hoare_triple_preI; simp) + using assms apply(sep_auto eintros del: exI heap add: pfa_shrink_cap_rule) + subgoal for _ _ aaa ba + apply(inst_existentials aaa ba z) + apply simp_all + done + subgoal + apply(rule hoare_triple_preI) + using True apply (auto dest!: mod_starD list_assn_len)+ + done + done +next + case [simp]: False + then obtain ls sep rs where + split_half_eq: "BPlusTree_Split.split_half xs = (ls@[sep],rs)" + using abs_split_set.Lnode\<^sub>i_cases by blast + then show ?thesis + apply(subst Lnode\<^sub>i_def) + apply auto + using assms apply (vcg heap add: pfa_shrink_cap_rule; simp) + apply(rule hoare_triple_preI) + apply (sep_auto heap add: pfa_drop_rule simp add: split_relation_alt + dest!: mod_starD list_assn_len) + + subgoal by (sep_auto simp add: is_pfa_def split!: prod.splits) + subgoal by (sep_auto simp add: is_pfa_def split!: prod.splits) + apply(sep_auto) + subgoal by (sep_auto simp add: is_pfa_def split!: prod.splits) + subgoal by (sep_auto simp add: is_pfa_def split!: prod.splits) + apply(sep_auto eintros del: exI) + subgoal for _ _ _ _ rsa rn lsa ln newr + (* instantiate right hand side *) + apply(inst_existentials "Some newr" + rsa rn z + lsa ln "Some newr" + ) + (* introduce equality between equality of split tsi/ts and original lists *) + apply(simp_all add: pure_def) + apply(sep_auto dest!: mod_starD) + apply(subgoal_tac "Suc (length xs) div 2 = Suc (length ls)") + apply(subgoal_tac "xs = take (Suc (length ls)) xs @ drop (Suc (length ls)) xs") + subgoal + by (metis nth_append_length) + subgoal by auto + subgoal by auto + subgoal by sep_auto + done + done +qed +declare abs_split_set.Lnode\<^sub>i.simps [simp del] + +lemma Lnode\<^sub>i_rule_tree: + assumes "k > 0" + shows " + Lnode\<^sub>i k a + <\a. btupi_assn k (abs_split_set.Lnode\<^sub>i k xs) a r z>\<^sub>t" + using assms by (sep_auto heap add: Lnode\<^sub>i_rule) + +lemma node\<^sub>i_no_split: "length ts \ 2*k \ abs_split_set.node\<^sub>i k ts t = abs_split_set.T\<^sub>i (Node ts t)" + by (simp add: abs_split_set.node\<^sub>i.simps) + +lemma Lnode\<^sub>i_no_split: "length ts \ 2*k \ abs_split_set.Lnode\<^sub>i k ts = abs_split_set.T\<^sub>i (Leaf ts)" + by (simp add: abs_split_set.Lnode\<^sub>i.simps) + +lemma id_assn_emp[simp]: "id_assn a a = emp" + by (simp add: pure_def) + +lemma butlast2[simp]: "butlast (ts@[a,b]) = ts@[a]" + by (induction ts) auto + +lemma butlast3[simp]: "butlast (ts@[a,b,c]) = ts@[a,b]" + by (induction ts) auto + +lemma zip_append_last: "length as = length bs \ zip (as@[a]) (bs@[b]) = zip as bs @ [(a,b)]" + by simp + +lemma pointers_append: "zip (z#as) (as@[a]) = zip (butlast (z#as)) as @ [(last (z#as),a)]" + by (metis (no_types, opaque_lifting) Suc_eq_plus1 append_butlast_last_id butlast_snoc length_Cons length_append_singleton length_butlast list.distinct(1) zip_append_last) + +lemma node\<^sub>i_rule_app: assumes c_cap: "2*k \ c" "c \ 4*k+1" + and "length tsi' = length pointers" + and "tsi'' = zip (zip (map fst tsi') (zip (butlast (r'#pointers)) pointers)) (map snd tsi')" + shows " +< p \\<^sub>r Btnode (tsia,tsin) ri * + is_pfa c (tsi' @ [(Some li, a)]) (tsia, tsin) * + blist_assn k ts tsi'' * + bplustree_assn k l li (last (r'#pointers)) lz * + bplustree_assn k r ri lz rz> node\<^sub>i k p + <\u. btupi_assn k (abs_split_set.node\<^sub>i k (ts @ [(l, a)]) r) u r' rz>\<^sub>t" +proof - +(*[of k c "(tsi' @ [(Some li, b)])" _ _ "(ls @ [(l, a)])" r ri]*) + note node\<^sub>i_rule[of k c "tsi'@[(Some li, a)]" "pointers@[lz]" "tsi''@[((Some li, last(r'#pointers), lz),a)]" r' rz p tsia tsin ri "ts@[(l,a)]" r, OF assms(1,2)] + then show ?thesis + using assms + apply (auto simp add: + list_assn_app_one pointers_append + mult.left_assoc + ) + done +qed + +lemma norm_pre_ex_drule: "<\\<^sub>Ax. P x> c \ (\x.

c )" +proof (goal_cases) + case 1 + then show ?case + using Hoare_Triple.cons_pre_rule by blast +qed + +(* setting up the simplifier for tsi'' in the other direction *) +lemma node\<^sub>i_rule_diff_simp: assumes c_cap: "2*k \ c" "c \ 4*k+1" + and "length tsi' = length pointers" + and "zip (zip (map fst tsi') (zip (butlast (r#pointers)) (butlast (pointers@[z])))) (map snd tsi') = tsi''" + shows "

\<^sub>r Btnode (a,n) ti * is_pfa c tsi' (a,n) * blist_assn k ts tsi'' * bplustree_assn k t ti (last (r#pointers)) z> + node\<^sub>i k p + <\u. btupi_assn k (abs_split_set.node\<^sub>i k ts t) u r z>\<^sub>t" + using node\<^sub>i_rule assms by (auto simp del: butlast.simps last.simps) + +lemma list_assn_aux_append_Cons2: + shows "length xs = length zsl \ list_assn R (xs@x#y#ys) (zsl@z1#z2#zsr) = (list_assn R xs zsl * R x z1 * R y z2 * list_assn R ys zsr)" + by (sep_auto simp add: mult.assoc) + +lemma pointer_zip_access: "length tsi' = length pointers \ i < length tsi' \ + zip (zip (map fst tsi') (zip (butlast (r'#pointers)) (butlast (pointers@[z])))) (map snd tsi') ! i += ((fst (tsi' ! i), (r'#pointers) ! i, pointers ! i), snd (tsi' ! i))" + apply(auto) + by (metis append_butlast_last_id butlast.simps(2) len_greater_imp_nonempty length_Cons length_append_singleton nth_butlast) + +lemma pointer_zip'_access: "length tsi' = length pointers \ i < length tsi' \ + zip (zip (map fst tsi') (zip (butlast (r'#pointers)) (butlast (pointers@[z])))) (map snd tsi') ! i += ((fst (tsi' ! i), (r'#pointers) ! i, pointers ! i), snd (tsi' ! i))" + apply(auto) + by (metis One_nat_def nth_take take_Cons' take_butlast_conv) + +lemma access_len_last: "(x#xs@ys) ! (length xs) = last (x#xs)" + by (induction xs) auto + + +lemma node\<^sub>i_rule_ins2: assumes c_cap: "2*k \ c" "c \ 4*k+1" + and "pointers = lpointers@lz#rz#rpointers" + and "length tsi'' = length pointers" + and "length lpointers = length lsi'" + and "length rpointers = length rsi'" + and "length lsi'' = length ls" + and "length lsi' = length ls" + and "tsi'' = zip (zip (map fst tsi') (zip (butlast (r'#pointers)) (butlast (pointers@[z])))) (map snd tsi')" + and "tsi' = (lsi' @ (Some li, a) # (Some ri,a') # rsi')" + and "lsi'' = take (length lsi') tsi''" + and "rsi'' = drop (Suc (Suc (length lsi'))) tsi''" + and "r'' = last (r'#lpointers)" + and "z'' = last (r'#pointers)" + and "length tsi' = length pointers" + shows " +< p \\<^sub>r Btnode (tsia,tsin) ti * + is_pfa c (lsi' @ (Some li, a) # (Some ri,a') # rsi') (tsia, tsin) * + blist_assn k ls lsi'' * + bplustree_assn k l li r'' lz* + bplustree_assn k r ri lz rz* + blist_assn k rs rsi'' * + bplustree_assn k t ti z'' z> node\<^sub>i k p +<\u. btupi_assn k (abs_split_set.node\<^sub>i k (ls @ (l, a) # (r,a') # rs) t) u r' z>\<^sub>t" +proof - + have " + tsi'' = + lsi'' @ ((Some li, r'', lz), a) # ((Some ri, lz, rz), a') # rsi''" + proof (goal_cases) + case 1 + have "tsi'' = take (length lsi') tsi'' @ drop (length lsi') tsi''" + by auto + also have "\ = take (length lsi') tsi'' @ tsi''!(length lsi') # drop (Suc (length lsi')) tsi''" + by (simp add: Cons_nth_drop_Suc assms(3) assms(4) assms(5)) + also have "\ = take (length lsi') tsi'' @ tsi''!(length lsi') # tsi''!(Suc (length lsi')) #drop (Suc (Suc (length lsi'))) tsi''" + by (metis (no_types, lifting) Cons_nth_drop_Suc One_nat_def Suc_eq_plus1 Suc_le_eq assms(3) assms(4) assms(5) diff_add_inverse2 diff_is_0_eq length_append list.size(4) nat.simps(3) nat_add_left_cancel_le not_less_eq_eq) + also have "\ = lsi'' @ tsi''!(length lsi') # tsi''!(Suc (length lsi')) # rsi''" + using assms(11) assms(12) by force + also have "\ = lsi'' @ ((Some li, r'', lz), a) # ((Some ri, lz, rz), a') # rsi''" + proof (auto, goal_cases) + case 1 + have "pointers ! length lsi' = lz" + by (metis assms(3) assms(5) list.sel(3) nth_append_length) + moreover have "(r'#pointers) ! length lsi' = r''" + using assms access_len_last[of r' lpointers] + by (auto simp del: last.simps butlast.simps) + moreover have " tsi'!(length lsi') = (Some li,a)" + using assms(10) by auto + moreover have "length lsi' < length tsi'" + using \take (length lsi') tsi'' @ tsi'' ! length lsi' # drop (Suc (length lsi')) tsi'' = take (length lsi') tsi'' @ tsi'' ! length lsi' # tsi'' ! Suc (length lsi') # drop (Suc (Suc (length lsi'))) tsi''\ assms(15) assms(4) same_append_eq by fastforce + ultimately show ?case + using pointer_zip'_access[of tsi' "pointers" "length lsi'" r'] assms(15) assms(9) + by (auto simp del: last.simps butlast.simps) + next + case 2 + have "pointers ! (Suc (length lsi')) = rz" + by (metis Suc_eq_plus1 append_Nil assms(3) assms(5) list.sel(3) nth_Cons_Suc nth_append_length nth_append_length_plus) + moreover have "(r'#pointers) ! (Suc (length lsi')) = lz" + using assms(3,4,5,6,7,8) apply auto + by (metis nth_append_length) + moreover have " tsi'!(Suc (length lsi')) = (Some ri,a')" + using assms(10) + by (metis (no_types, lifting) Cons_nth_drop_Suc Suc_le_eq append_eq_conv_conj assms(15) assms(4) drop_all drop_eq_ConsD list.inject list.simps(3) not_less_eq_eq) + moreover have "Suc (length lsi') < length tsi'" + by (simp add: assms(10)) + ultimately show ?case + using pointer_zip'_access[of tsi' pointers "Suc (length lsi')"] assms(15) assms(9) + by (auto simp del: last.simps butlast.simps) + qed + finally show ?thesis . + qed + moreover note node\<^sub>i_rule_diff_simp[of k c + "(lsi' @ (Some li, a) # (Some ri,a') # rsi')" + "lpointers@lz#rz#rpointers" r' z + "lsi''@((Some li, r'', lz), a)#((Some ri, lz, rz), a')#rsi''" + p tsia tsin ti "ls@(l,a)#(r,a')#rs" t +] + ultimately show ?thesis + using assms(1,2,3,4,5,6,7,8,9,10,13,14) + apply (auto simp add: mult.left_assoc list_assn_aux_append_Cons2 prod_assn_def +simp del: last.simps) + done +qed + +lemma upd_drop_prepend: "i < length xs \ drop i (list_update xs i a) = a#(drop (Suc i) xs)" + by (simp add: upd_conv_take_nth_drop) + +lemma zip_update: "(zip xs ys)!i = (a,b) \ list_update (zip xs ys) i (c,b) = zip (list_update xs i c) ys" + by (metis fst_conv list_update_beyond list_update_id not_le_imp_less nth_zip snd_conv update_zip) + +lemma append_Cons_last: "last (xs@x#ys) = last (x#ys)" + by (induction xs) auto + +declare last.simps[simp del] butlast.simps[simp del] +lemma ins\<^sub>i_rule: + "k > 0 \ + sorted_less (inorder t) \ + sorted_less (leaves t) \ + root_order k t \ + + ins\<^sub>i k x ti + <\a. btupi_assn k (abs_split_set.ins k x t) a r z>\<^sub>t" +proof (induction k x t arbitrary: ti r z rule: abs_split_set.ins.induct) + case (1 k x xs ti r z) + then show ?case + apply(subst ins\<^sub>i.simps) + apply (sep_auto heap: Lnode\<^sub>i_rule) + done +next + case (2 k x ts t ti r' z) + obtain ls rrs where list_split: "split ts x = (ls,rrs)" + by (cases "split ts x") + have [simp]: "sorted_less (separators ts)" + using "2.prems" sorted_inorder_separators by simp + have [simp]: "sorted_less (inorder t)" + using "2.prems" sorted_inorder_induct_last by simp + show ?case + proof (cases rrs) + case Nil + then have split_rel_i: "split_relation ts (ls,[]) i \ i = length ts" for i + by (simp add: split_relation_alt) + show ?thesis + proof (cases "abs_split_set.ins k x t") + case (T\<^sub>i a) + then show ?thesis + apply(subst ins\<^sub>i.simps) + using Nil + apply(simp) + apply vcg + apply(simp) + apply vcg + thm split\<^sub>i_rule + apply sep_auto + apply(rule hoare_triple_preI) + using Nil split_rel_i list_split + apply (sep_auto dest!: split_rel_i mod_starD) + subgoal + using Nil list_split + by (simp add: list_assn_aux_ineq_len split_relation_alt) + subgoal + using Nil list_split + by (simp add: list_assn_aux_ineq_len split_relation_alt) + subgoal for tsil tsin tti tsi' + thm "2.IH"(1)[of ls rrs tti] + using "2.prems" sorted_leaves_induct_last + using Nil list_split T\<^sub>i abs_split_set.split_conc[OF list_split] order_impl_root_order + apply(sep_auto split!: list.splits simp add: split_relation_alt + heap add: "2.IH"(1)[of ls rrs tti]) + subgoal for ai + apply(cases ai) + subgoal by sep_auto + subgoal by sep_auto + done + done + done + next + case (Up\<^sub>i l a r) + then show ?thesis + apply(subst ins\<^sub>i.simps) + using Nil + apply(simp) + apply vcg + apply simp + apply vcg + apply sep_auto + apply(rule hoare_triple_preI) + using Nil list_split + apply (sep_auto dest!: split_rel_i mod_starD) + subgoal + using Nil list_split + by (simp add: list_assn_aux_ineq_len split_relation_alt) + subgoal + using Nil list_split + by (simp add: list_assn_aux_ineq_len split_relation_alt) + subgoal for tsia tsin tti tsi' pointers _ _ _ _ _ _ _ _ _ _ i + thm "2.IH"(1)[of ls rrs tti "last (r'#pointers)" z] + using "2.prems" sorted_leaves_induct_last + using Nil list_split Up\<^sub>i abs_split_set.split_conc[OF list_split] order_impl_root_order + apply(sep_auto split!: list.splits + simp add: split_relation_alt + heap add: "2.IH"(1)[of ls rrs tti]) + subgoal for ai + apply(cases ai) + subgoal by sep_auto + apply(rule hoare_triple_preI) + thm node\<^sub>i_rule_app + apply(sep_auto heap add: node\<^sub>i_rule_app) + apply(sep_auto simp add: pure_def) + done + done + done + qed + next + case (Cons a rs) + obtain sub sep where a_split: "a = (sub,sep)" + by (cases a) + then have [simp]: "sorted_less (inorder sub)" + by (metis "2"(4) abs_split_set.split_set(1) list_split local.Cons some_child_sub(1) sorted_inorder_subtrees) + from Cons have split_rel_i: "ts = ls@a#rs \ i = length ls \ i < length ts" for i + by (simp add: split_relation_alt) + then show ?thesis + proof (cases "abs_split_set.ins k x sub") + case (T\<^sub>i a') + then show ?thesis + apply(auto simp add: Cons list_split a_split) + apply(subst ins\<^sub>i.simps) + apply vcg + apply auto + apply vcg + subgoal by sep_auto + apply simp + (*this solves a subgoal*) apply simp + (* at this point, we want to introduce the split, and after that tease the + hoare triple assumptions out of the bracket, s.t. we don't split twice *) + apply (vcg (ss)) + apply (vcg (ss)) + apply (vcg (ss)) + apply (vcg (ss)) + apply (vcg (ss)) + apply (vcg (ss)) + apply (vcg (ss)) + apply (vcg (ss)) + apply (vcg (ss)) + apply (vcg (ss)) + apply (vcg (ss)) + apply (vcg (ss)) + apply (vcg (ss)) + apply (vcg (ss)) + apply (vcg (ss)) + apply (vcg (ss)) + using list_split Cons abs_split_set.split_conc[of ts x ls rrs] + apply (simp add: list_assn_append_Cons_left) + apply(rule norm_pre_ex_rule)+ + apply(rule hoare_triple_preI) + apply(simp add: split_relation_alt prod_assn_def split!: prod.splits) + (* actual induction branch *) + subgoal for tsia tsin tti tsi' pointers suba' sepa' lsi' suba subleaf subnext sepa rsi' _ _ sub' sep' + apply(subgoal_tac "length ls = length lsi'") + apply(subgoal_tac "(suba', sepa') = (suba, sepa)") + apply(subgoal_tac "(sub', sep') = (sub, sep)") + thm "2.IH"(2)[of ls rs a rrs sub sep "the suba" subleaf subnext] + apply (sep_auto heap add: "2.IH"(2)) + subgoal using "2.prems" by metis + subgoal using "2.prems" sorted_leaves_induct_subtree \sorted_less (inorder sub)\ + by (auto split!: btupi.splits) + subgoal + using "2.prems"(3) sorted_leaves_induct_subtree by blast + subgoal using "2.prems"(1,4) order_impl_root_order[of k sub] by auto + subgoal for up + apply(cases up) + subgoal for ai + apply (sep_auto eintros del: exI) + apply(inst_existentials tsia tsin tti "tsi'[length ls := (Some ai, sepa)]" "lsi'@((Some ai, subleaf, subnext),sepa)#rsi'" pointers) + apply (sep_auto simp add: prod_assn_def split!: prod.splits) + subgoal (* necessary goal due to the difference between implementation and abstract code *) + proof (goal_cases) + case 1 + then have *: "((suba, subleaf, subnext), sepa) = (zip (zip (subtrees tsi') (zip (butlast (r' # pointers)) pointers)) (separators tsi'))!(length lsi')" + by (metis nth_append_length) + have **:"(zip (zip (subtrees tsi') (zip (butlast (r' # pointers)) pointers)) (separators tsi'))!(length lsi') = (((subtrees tsi')!(length lsi'), (butlast (r'#pointers))!(length lsi'), pointers!(length lsi')), (separators tsi')!(length lsi'))" + using 1 by simp + have "lsi' @ ((Some ai, subleaf, subnext), sepa) # rsi' = + list_update (lsi' @ ((suba, subleaf, subnext), sepa) # rsi') (length lsi') ((Some ai, subleaf, subnext), sepa)" + by simp + also have "\ = list_update (zip (zip (subtrees tsi') (zip (butlast (r' # pointers)) pointers)) (separators tsi')) (length lsi') ((Some ai, subleaf,subnext), sepa)" + using 1 by simp + also have "\ = zip (list_update (zip (subtrees tsi') (zip (butlast (r' # pointers)) pointers)) (length lsi') (Some ai, subleaf, subnext)) (separators tsi')" + by (meson zip_update sym[OF *]) + finally show ?case + using ** * + by (simp add: update_zip map_update) + qed + subgoal by sep_auto + done + subgoal + apply(rule hoare_triple_preI) + using T\<^sub>i + subgoal by (auto dest!: mod_starD) + done + done + subgoal + using a_split by fastforce + subgoal + proof (goal_cases) + case 1 + then have *: "((suba, subleaf, subnext), sepa) = (zip (zip (subtrees tsi') (zip (butlast (r' # pointers)) pointers)) (separators tsi'))!(length lsi')" + by (metis nth_append_length) + have **:"(zip (zip (subtrees tsi') (zip (butlast (r' # pointers)) pointers)) (separators tsi'))!(length lsi') = (((subtrees tsi')!(length lsi'), (butlast (r'#pointers))!(length lsi'), pointers!(length lsi')), (separators tsi')!(length lsi'))" + using 1 by simp + then show ?case + using ** * 1 + by simp + qed + subgoal by (auto dest!: mod_starD list_assn_len) + done + subgoal + apply(rule hoare_triple_preI) + using Cons split_relation_alt[of ts ls "a#rs"] list_split + by (auto dest!: list_assn_len mod_starD) + done + next + case (Up\<^sub>i l w r) + then show ?thesis + apply(auto simp add: Cons list_split a_split) + apply(subst ins\<^sub>i.simps) + apply vcg + apply auto + apply vcg + subgoal by sep_auto + apply simp + (*this solves a subgoal*) apply simp + (* at this point, we want to introduce the split, and after that tease the + hoare triple assumptions out of the bracket, s.t. we don't split twice *) + apply (vcg (ss)) + apply (vcg (ss)) + apply (vcg (ss)) + apply (vcg (ss)) + apply (vcg (ss)) + apply (vcg (ss)) + apply (vcg (ss)) + apply (vcg (ss)) + apply (vcg (ss)) + apply (vcg (ss)) + apply (vcg (ss)) + apply (vcg (ss)) + apply (vcg (ss)) + apply (vcg (ss)) + apply (vcg (ss)) + apply (vcg (ss)) + using list_split Cons abs_split_set.split_conc[of ts x ls rrs] + apply (simp add: list_assn_append_Cons_left) + apply(rule norm_pre_ex_rule)+ + apply(rule hoare_triple_preI) + apply(simp add: split_relation_alt prod_assn_def split!: prod.splits) + (* actual induction branch *) + subgoal for tsia tsin tti tsi' pointers suba' sepa' lsi' suba subleaf subnext sepa rsi' _ _ sub' sep' + apply(subgoal_tac "length ls = length lsi'") + apply(subgoal_tac "(suba', sepa') = (suba, sepa)") + apply(subgoal_tac "(sub', sep') = (sub, sep)") + thm "2.IH"(2)[of ls rs a rrs sub sep "the suba" subleaf subnext] + apply (sep_auto heap add: "2.IH"(2)) + subgoal using "2.prems" by metis + subgoal using "2.prems" sorted_leaves_induct_subtree \sorted_less (inorder sub)\ + by (auto split!: btupi.splits) + subgoal + using "2.prems"(3) sorted_leaves_induct_subtree by blast + subgoal using "2.prems"(1,4) order_impl_root_order[of k sub] by auto + subgoal for up + apply(cases up) + subgoal by simp + subgoal for li ai ri (* split case *) + apply (sep_auto dest!: mod_starD list_assn_len heap: pfa_insert_grow_rule) + subgoal by (sep_auto simp add: is_pfa_def) + subgoal for aa ba ac bc ae be ak bk al bl newr x xaa + apply(simp split!: prod.splits) + subgoal for tsia' + supply R= node\<^sub>i_rule_ins2[where k=k and c="max (2*k) (Suc tsin)" and + lsi'="take (length lsi') tsi'" and li=li and ri=ri + and rsi'="drop (Suc (length lsi')) tsi'" + and lpointers="take (length lsi') pointers" + and rpointers="drop (Suc (length lsi')) pointers" + and pointers="take (length lsi') pointers @ newr # subnext # drop (Suc (length lsi')) pointers" + and z''="last (r'#pointers)" + and tsi'="take (length lsi') tsi' @ (Some li, ai) # (Some ri, sepa) # drop (Suc (length lsi')) tsi'" + and r'="r'" and z="z" +and tsi''="zip (zip (subtrees + (take (length lsi') tsi' @ + (Some li, ai) # (Some ri, sepa) # drop (Suc (length lsi')) tsi')) + (zip (butlast + (r' # + take (length lsi') pointers @ newr # subnext # drop (Suc (length lsi')) pointers)) + (butlast + ((take (length lsi') pointers @ newr # subnext # drop (Suc (length lsi')) pointers) @ + [z])))) + (separators + (take (length lsi') tsi' @ + (Some li, ai) # (Some ri, sepa) # drop (Suc (length lsi')) tsi'))" + ] + thm R + apply (sep_auto simp add: upd_drop_prepend eintros del: exI heap: R split!: prod.splits) + subgoal + proof (goal_cases) + case 1 + from sym[OF 1(8)] have "lsi' = take (length lsi') (zip (zip (subtrees tsi') (zip (butlast (r' # pointers)) pointers)) (separators tsi'))" + by auto + then show ?case using 1 + by (auto simp add: take_zip take_map take_butlast_prepend take_butlast_append) + qed + subgoal + proof (goal_cases) + case 1 + let ?tsi''="zip (zip (subtrees tsi') (zip (butlast (r' # pointers)) pointers)) (separators tsi')" + from sym[OF 1(8)] have "rsi' = drop (Suc (length lsi')) ?tsi''" + by auto + moreover have "pointers ! length lsi' = subnext" + proof - + let ?i = "length lsi'" + have "?tsi'' ! ?i = ((fst (tsi'!?i), (r' # pointers) ! ?i, pointers ! ?i), snd (tsi' ! ?i))" + using pointer_zip_access 1 by fastforce + moreover have "?tsi'' ! ?i = ((suba, subleaf, subnext), sepa)" + by (metis "1" nth_append_length) + ultimately show ?thesis by simp + qed + ultimately show ?case using 1 + by (auto simp add: drop_zip drop_map drop_butlast Cons_nth_drop_Suc) + qed + subgoal + proof (goal_cases) + case 1 + let ?tsi''="zip (zip (subtrees tsi') (zip (butlast (r' # pointers)) pointers)) (separators tsi')" + let ?i = "length lsi'" + show ?thesis + proof - + let ?i = "length lsi'" + have "?tsi'' ! ?i = ((fst (tsi'!?i), (r' # pointers) ! ?i, pointers ! ?i), snd (tsi' ! ?i))" + using pointer_zip_access 1 by fastforce + moreover have "?tsi'' ! ?i = ((suba, subleaf, subnext), sepa)" + by (metis "1" nth_append_length) + ultimately have "(r'#pointers) ! ?i = subleaf" + by simp + then show ?thesis + using sym[OF append_take_drop_id, of pointers "length lsi'"] + using access_len_last[of r' "take (length lsi') pointers" "drop (length lsi') pointers"] + using 1 + by simp + qed + qed + subgoal + proof (goal_cases) + case 1 + let ?tsi''="zip (zip (subtrees tsi') (zip (butlast (r' # pointers)) pointers)) (separators tsi')" + let ?i = "length lsi'" + have "pointers ! ?i = subnext" + proof - + have "?tsi'' ! ?i = ((fst (tsi'!?i), (r' # pointers) ! ?i, pointers ! ?i), snd (tsi' ! ?i))" + using pointer_zip_access 1 by fastforce + moreover have "?tsi'' ! ?i = ((suba, subleaf, subnext), sepa)" + by (metis "1" nth_append_length) + ultimately show ?thesis by simp + qed + moreover have "drop (length lsi') pointers \ []" + using "1" by auto + moreover have "pointers \ []" + using "1" by auto + ultimately show ?case + apply(auto simp add: Cons_nth_drop_Suc last.simps) + apply(auto simp add: last_conv_nth) + by (metis Suc_to_right le_SucE) + qed + subgoal by auto + subgoal by (sep_auto simp add: pure_def) + done + done + done + done + subgoal + using a_split by fastforce + subgoal + proof (goal_cases) + case 1 + then have *: "((suba, subleaf, subnext), sepa) = (zip (zip (subtrees tsi') (zip (butlast (r' # pointers)) pointers)) (separators tsi'))!(length lsi')" + by (metis nth_append_length) + have **:"(zip (zip (subtrees tsi') (zip (butlast (r' # pointers)) pointers)) (separators tsi'))!(length lsi') = (((subtrees tsi')!(length lsi'), (butlast (r'#pointers))!(length lsi'), pointers!(length lsi')), (separators tsi')!(length lsi'))" + using 1 by simp + then show ?case + using ** * 1 + by simp + qed + subgoal by (auto dest!: mod_starD list_assn_len) + done + subgoal + apply(rule hoare_triple_preI) + using Cons split_relation_alt[of ts ls "a#rs"] list_split + by (auto dest!: list_assn_len mod_starD) + done + qed + qed + qed +declare last.simps[simp add] butlast.simps[simp add] + +text "The imperative insert refines the abstract insert." + +lemma insert\<^sub>i_rule: + assumes "k > 0" "sorted_less (inorder t)" "sorted_less (leaves t)" "root_order k t" + shows " + insert\<^sub>i k x ti + <\u. bplustree_assn k (abs_split_set.insert k x t) u r z>\<^sub>t" +proof(cases "abs_split_set.ins k x t") + case (T\<^sub>i x1) + then show ?thesis + unfolding insert\<^sub>i_def + using assms + by (sep_auto split!: btupi.splits heap: ins\<^sub>i_rule) +next + case (Up\<^sub>i x21 x22 x23) + then show ?thesis + unfolding insert\<^sub>i_def + using assms + apply (sep_auto eintros del: exI split!: btupi.splits heap: ins\<^sub>i_rule) + subgoal for x21a x22a x23a newr a b xa + apply(inst_existentials a b x23a "[(Some x21a, x22a)]" "[((Some x21a, r, newr),x22a)]" "[newr]") + apply (auto simp add: prod_assn_def) + apply (sep_auto) + done + done +qed + +text "The \"pure\" resulting rule follows automatically." +lemma insert\<^sub>i_rule': + shows "(abs_split_set.invar_leaves (Suc k) t \ sorted_less (leaves t))> + insert\<^sub>i (Suc k) x ti + <\ri.\\<^sub>Au. bplustree_assn (Suc k) u ri r z * \(abs_split_set.invar_leaves (Suc k) u \ sorted_less (leaves u) \ leaves u = (ins_list x (leaves t)))>\<^sub>t" + using Laligned_sorted_inorder[of t top] sorted_wrt_append + using abs_split_set.insert_bal[of t] abs_split_set.insert_order[of "Suc k" t] + using abs_split_set.insert_Linorder_top[of "Suc k" t] + by (sep_auto heap: insert\<^sub>i_rule simp add: sorted_ins_list) + + +subsection "Deletion" + +text "The below definitions work for non-linked-leaf B-Plus-Trees +but not yet for linked-leaf trees" + + +(* rebalance middle tree gets a list of trees, an index pointing to +the position of sub/sep and a last tree *) + +definition rebalance_middle_tree:: "nat \ (('a::{default,heap,linorder,order_top}) btnode ref option \ 'a) pfarray \ nat \ 'a btnode ref \ 'a btnode Heap" + where + "rebalance_middle_tree \ \ k tsi i p_ti. ( do { + ti \ !p_ti; + case ti of + Btleaf txsi n_p \ do { + (r_sub,sep) \ pfa_get tsi i; + subi \ !(the r_sub); + l_sub \ pfa_length (vals subi); + l_txs \ pfa_length (txsi); + if l_sub \ k \ l_txs \ k then do { + return (Btnode tsi p_ti) + } else do { + l_tsi \ pfa_length tsi; + if i+1 = l_tsi then do { + mts' \ pfa_extend_grow (vals subi) (txsi); + (the r_sub) := Btleaf mts' n_p; + res_node\<^sub>i \ Lnode\<^sub>i k (the r_sub); + case res_node\<^sub>i of + T\<^sub>i u \ do { + tsi' \ pfa_shrink i tsi; + return (Btnode tsi' u) + } | + Up\<^sub>i l a r \ do { + tsi' \ pfa_set tsi i (Some l,a); + return (Btnode tsi' r) + } + } else do { + (r_rsub,rsep) \ pfa_get tsi (i+1); + rsub \ !(the r_rsub); + mts' \ pfa_extend_grow (vals subi) (vals rsub); + (the r_sub) := Btleaf mts' (fwd rsub); + res_node\<^sub>i \ Lnode\<^sub>i k (the r_sub); + case res_node\<^sub>i of + T\<^sub>i u \ do { + tsi' \ pfa_set tsi i (Some u,rsep); + tsi'' \ pfa_delete tsi' (i+1); + return (Btnode tsi'' p_ti) + } | + Up\<^sub>i l a r \ do { + tsi' \ pfa_set tsi i (Some l,a); + tsi'' \ pfa_set tsi' (i+1) (Some r,rsep); + return (Btnode tsi'' p_ti) + } + } + }} | + Btnode ttsi tti \ do { + (r_sub,sep) \ pfa_get tsi i; + subi \ !(the r_sub); + l_sub \ pfa_length (kvs subi); + l_tts \ pfa_length (ttsi); + if l_sub \ k \ l_tts \ k then do { + return (Btnode tsi p_ti) + } else do { + l_tsi \ pfa_length tsi; + if i+1 = l_tsi then do { + mts' \ pfa_append_extend_grow (kvs subi) (Some (lst subi),sep) (ttsi); + (the r_sub) := Btnode mts' (lst ti); + res_node\<^sub>i \ node\<^sub>i k (the r_sub); + case res_node\<^sub>i of + T\<^sub>i u \ do { + tsi' \ pfa_shrink i tsi; + return (Btnode tsi' u) + } | + Up\<^sub>i l a r \ do { + tsi' \ pfa_set tsi i (Some l,a); + return (Btnode tsi' r) + } + } else do { + (r_rsub,rsep) \ pfa_get tsi (i+1); + rsub \ !(the r_rsub); + mts' \ pfa_append_extend_grow (kvs subi) (Some (lst subi),sep) (kvs rsub); + (the r_sub) := Btnode mts' (lst rsub); + res_node\<^sub>i \ node\<^sub>i k (the r_sub); + case res_node\<^sub>i of + T\<^sub>i u \ do { + tsi' \ pfa_set tsi i (Some u,rsep); + tsi'' \ pfa_delete tsi' (i+1); + return (Btnode tsi'' p_ti) + } | + Up\<^sub>i l a r \ do { + tsi' \ pfa_set tsi i (Some l,a); + tsi'' \ pfa_set tsi' (i+1) (Some r,rsep); + return (Btnode tsi'' p_ti) + } + } + } +}} +) +" + + +definition rebalance_last_tree:: "nat \ (('a::{default,heap,linorder,order_top}) btnode ref option \ 'a) pfarray \ 'a btnode ref \ 'a btnode Heap" + where + "rebalance_last_tree \ \k tsi ti. do { + l_tsi \ pfa_length tsi; + rebalance_middle_tree k tsi (l_tsi-1) ti +}" + + +subsection "Refinement of the abstract B-tree operations" + + +lemma P_imp_Q_implies_P: "P \ (Q \ P)" + by simp + + + +lemma btupi_assn_T: "h \ btupi_assn k (abs_split_set.node\<^sub>i k ts t) (T\<^sub>i x) r z \ abs_split_set.node\<^sub>i k ts t = abs_split_set.T\<^sub>i (Node ts t)" + apply(auto simp add: abs_split_set.node\<^sub>i.simps dest!: mod_starD split!: list.splits prod.splits) + done + +lemma btupi_assn_Up: "h \ btupi_assn k (abs_split_set.node\<^sub>i k ts t) (Up\<^sub>i l a r) r' z \ + abs_split_set.node\<^sub>i k ts t = ( + case BPlusTree_Split.split_half ts of (ls,rs) \ ( + case last ls of (sub,sep) \ + abs_split_set.Up\<^sub>i (Node (butlast ls) sub) sep (Node rs t) + ) +)" + apply(auto simp add: abs_split_set.node\<^sub>i.simps split!: list.splits prod.splits) + done + +lemma Lbtupi_assn_T: "h \ btupi_assn k (abs_split_set.Lnode\<^sub>i k ts) (T\<^sub>i x) r z \ abs_split_set.Lnode\<^sub>i k ts = abs_split_set.T\<^sub>i (Leaf ts)" + apply(cases "length ts \ 2*k") + apply(auto simp add: abs_split_set.Lnode\<^sub>i.simps split!: list.splits prod.splits) + done + +lemma Lbtupi_assn_Up: "h \ btupi_assn k (abs_split_set.Lnode\<^sub>i k ts) (Up\<^sub>i l a r) r' z \ + abs_split_set.Lnode\<^sub>i k ts = ( + case BPlusTree_Split.split_half ts of (ls,rs) \ ( + case last ls of sep \ + abs_split_set.Up\<^sub>i (Leaf ls) sep (Leaf rs) + ) +)" + apply(auto simp add: abs_split_set.Lnode\<^sub>i.simps split!: list.splits prod.splits) + done + +lemma second_last_access:"(xs@a#b#ys) ! Suc(length xs) = b" + by (simp add: nth_via_drop) + +lemma second_last_update:"(xs@a#b#ys)[Suc(length xs) := c] = (xs@a#c#ys)" + by (metis append.assoc append_Cons empty_append_eq_id length_append_singleton list_update_length) + +lemma clean_heap:"\(a, b) \ P \ Q; (a, b) \ P\ \ Q" + by auto + + + +partial_function (heap) del ::"nat \ 'a \ ('a::{default,heap,linorder,order_top}) btnode ref \ 'a btnode ref Heap" + where + "del k x tp = do { + ti \ !tp; + (case ti of Btleaf xs np \ do { + xs' \ del_list\<^sub>i x xs; + tp := (Btleaf xs' np); + return tp +} | + Btnode tsi tti \ do { + i \ split\<^sub>i tsi x; + tsl \ pfa_length tsi; + if i < tsl then do { + (sub,sep) \ pfa_get tsi i; + sub' \ del k x (the sub); + kvs' \ pfa_set tsi i (Some sub',sep); + node' \ rebalance_middle_tree k kvs' i tti; + tp := node'; + return tp + } else do { + t' \ del k x tti; + node' \ rebalance_last_tree k tsi t'; + tp := node'; + return tp + } + }) +}" + + +end + +context split\<^sub>i_list +begin + +definition isin_list\<^sub>i:: "'a \ ('a::{heap,default,linorder,order_top}) pfarray \ bool Heap" + where "isin_list\<^sub>i x ks = do { + i \ split\<^sub>i_list ks x; + xsl \ pfa_length ks; + if i \ xsl then return False + else do { + sep \ pfa_get ks i; + return (sep = x) + } +}" + +lemma isin_list\<^sub>i_rule [sep_heap_rules]: + assumes "sorted_less ks" + shows + " + isin_list\<^sub>i x (a',n') + <\b. + is_pfa c ks (a',n') + * \(b = abs_split_list.isin_list x ks)>\<^sub>t" +proof - + obtain ls rs where list_split: "split_list ks x = (ls, rs)" + by (cases "split_list ks x") + then show ?thesis + proof (cases rs) + case Nil + then show ?thesis + apply(subst isin_list\<^sub>i_def) + using assms list_split apply(sep_auto simp add: split_relation_alt dest!: mod_starD list_assn_len) + done + next + case (Cons a rrs) + then show ?thesis + apply(subst isin_list\<^sub>i_def) + using list_split apply simp + using assms list_split apply(sep_auto simp add: split_relation_alt list_assn_append_Cons_left dest!: mod_starD list_assn_len) + done + qed +qed + +definition ins_list\<^sub>i:: "'a \ ('a::{heap,default,linorder,order_top}) pfarray \ 'a pfarray Heap" + where "ins_list\<^sub>i x ks = do { + i \ split\<^sub>i_list ks x; + xsl \ pfa_length ks; + if i \ xsl then + pfa_append_grow ks x + else do { + sep \ pfa_get ks i; + if sep = x then + return ks + else + pfa_insert_grow ks i x + } +}" + +lemma ins_list\<^sub>i_rule [sep_heap_rules]: + assumes "sorted_less ks" + shows + " + ins_list\<^sub>i x (a',n') + <\(a'',n''). is_pfa (max c (length (abs_split_list.insert_list x ks))) (abs_split_list.insert_list x ks) (a'',n'') + >\<^sub>t" +proof - + obtain ls rs where list_split: "split_list ks x = (ls, rs)" + by (cases "split_list ks x") + then show ?thesis + proof (cases rs) + case Nil + then show ?thesis + apply(subst ins_list\<^sub>i_def) + apply vcg + subgoal using assms by auto + apply(rule hoare_triple_preI) + apply vcg + using list_split apply (auto simp add: split_relation_alt split!: prod.splits list.splits dest!: mod_starD list_assn_len) + subgoal + apply(simp add: is_pfa_def) + apply(rule ent_ex_preI) + subgoal for l + apply(rule ent_ex_postI[where x="l"]) + using assms list_split apply(sep_auto simp add: split_relation_alt pure_def dest!: mod_starD list_assn_len) + done + done + subgoal + apply(simp add: is_pfa_def) + apply(rule ent_ex_preI) + subgoal for l + apply(rule ent_ex_postI[where x="l"]) + using assms list_split apply(sep_auto simp add: split_relation_alt pure_def dest!: mod_starD list_assn_len) + done + done + done + next + case (Cons a rrs) + then show ?thesis + proof (cases "a = x") + case True + then show ?thesis + apply(subst ins_list\<^sub>i_def) + apply vcg + subgoal using assms by auto + apply(rule hoare_triple_preI) + apply vcg + subgoal using list_split Cons by (auto simp add: split_relation_alt split!: prod.splits list.splits dest!: mod_starD list_assn_len) + apply vcg + subgoal using list_split Cons by (auto simp add: split_relation_alt split!: prod.splits list.splits dest!: mod_starD list_assn_len) + apply vcg + prefer 2 + subgoal by (metis (no_types, lifting) id_assn_list list_split local.Cons mod_starD split_relation_access) + using list_split Cons apply (auto simp add: split_relation_alt list_assn_append_Cons_left split!: prod.splits list.splits dest!: mod_starD list_assn_len) + apply(subgoal_tac "max c (Suc (length ls + length rrs)) = c") + subgoal using assms list_split by (sep_auto simp add: split_relation_alt dest!: mod_starD id_assn_list) + subgoal + apply(auto simp add: is_pfa_def) + by (metis add_Suc_right length_Cons length_append length_take max.absorb1 min_eq_arg(2)) + done + next + case False + then show ?thesis + apply(subst ins_list\<^sub>i_def) + apply vcg + subgoal using assms by auto + apply(rule hoare_triple_preI) + apply vcg + subgoal using list_split Cons by (auto simp add: split_relation_alt split!: prod.splits list.splits dest!: mod_starD list_assn_len) + apply vcg + subgoal using list_split Cons by (auto simp add: split_relation_alt split!: prod.splits list.splits dest!: mod_starD list_assn_len) + apply vcg + subgoal by (metis (no_types, lifting) id_assn_list list_split local.Cons mod_starD split_relation_access) + apply vcg + subgoal by (auto simp add: is_pfa_def) + using list_split Cons apply (auto simp add: split_relation_alt list_assn_append_Cons_left split!: prod.splits list.splits dest!: mod_starD list_assn_len) + subgoal for _ _ _ _ + apply(subgoal_tac "(Suc (Suc (length ls + length rrs))) = Suc n'") + subgoal + using assms list_split Cons by (sep_auto simp add: split_relation_alt dest!: mod_starD id_assn_list) + subgoal + apply(auto simp add: is_pfa_def) + by (metis add_Suc_right length_Cons length_append length_take min_eq_arg(2)) + done + done +qed +qed +qed + +definition del_list\<^sub>i:: "'a \ ('a::{heap,default,linorder,order_top}) pfarray \ 'a pfarray Heap" + where "del_list\<^sub>i x ks = do { + i \ split\<^sub>i_list ks x; + xsl \ pfa_length ks; + if i \ xsl then + return ks + else do { + sep \ pfa_get ks i; + if sep = x then + pfa_delete ks i + else + return ks + } +}" + +lemma del_list\<^sub>i_rule [sep_heap_rules]: + assumes "sorted_less ks" + shows " + del_list\<^sub>i x (a',n') + <\(a'',n''). is_pfa c (abs_split_list.delete_list x ks) (a'',n'')>\<^sub>t" +proof - + obtain ls rs where list_split: "split_list ks x = (ls, rs)" + by (cases "split_list ks x") + then show ?thesis + proof (cases rs) + case Nil + then show ?thesis + apply(subst del_list\<^sub>i_def) + apply vcg + subgoal using assms by auto + apply(rule hoare_triple_preI) + apply vcg + using list_split apply (auto simp add: split_relation_alt split!: prod.splits list.splits dest!: mod_starD list_assn_len) + done + next + case (Cons a rrs) + then show ?thesis + proof (cases "a = x") + case True + then show ?thesis + apply(subst del_list\<^sub>i_def) + apply vcg + subgoal using assms by auto + apply(rule hoare_triple_preI) + apply vcg + subgoal using list_split Cons by (auto simp add: split_relation_alt split!: prod.splits list.splits dest!: mod_starD list_assn_len) + apply vcg + subgoal using list_split Cons by (auto simp add: split_relation_alt split!: prod.splits list.splits dest!: mod_starD list_assn_len) + apply vcg + subgoal using list_split Cons apply (auto simp add: split_relation_alt is_pfa_def split!: prod.splits list.splits dest!: mod_starD list_assn_len) + by (metis add_Suc_right length_Cons length_append length_take less_add_Suc1 min_eq_arg(2)) + prefer 2 + subgoal by (simp add: list_split local.Cons split_relation_access) + using list_split Cons apply (auto simp add: split_relation_alt list_assn_append_Cons_left split!: prod.splits list.splits dest!: mod_starD list_assn_len) + done + next + case False + then show ?thesis + apply(subst del_list\<^sub>i_def) + apply vcg + subgoal using assms by auto + apply(rule hoare_triple_preI) + apply vcg + subgoal using list_split Cons by (auto simp add: split_relation_alt split!: prod.splits list.splits dest!: mod_starD list_assn_len) + apply vcg + subgoal using list_split Cons by (auto simp add: split_relation_alt split!: prod.splits list.splits dest!: mod_starD list_assn_len) + apply vcg + subgoal using list_split Cons by (auto simp add: split_relation_alt is_pfa_def split!: prod.splits list.splits dest!: mod_starD list_assn_len) + subgoal by (simp add: list_split local.Cons split_relation_access) + apply vcg + using list_split Cons apply (auto simp add: split_relation_alt split!: prod.splits list.splits dest!: mod_starD list_assn_len) + done + qed + qed +qed + +end + +context split\<^sub>i_full +begin + +sublocale split\<^sub>i_set split\<^sub>i_list.abs_split_list.isin_list split\<^sub>i_list.abs_split_list.insert_list + split\<^sub>i_list.abs_split_list.delete_list split split\<^sub>i split\<^sub>i_list.isin_list\<^sub>i split\<^sub>i_list.ins_list\<^sub>i split\<^sub>i_list.del_list\<^sub>i + using split\<^sub>i_list.abs_split_list.isin_list_set split\<^sub>i_list.abs_split_list.insert_list_set split\<^sub>i_list.abs_split_list.delete_list_set + apply unfold_locales + apply sep_auto + + done + +end + + +end + diff --git a/thys/BTree/BPlusTree_ImpSplit.thy b/thys/BTree/BPlusTree_ImpSplit.thy new file mode 100644 --- /dev/null +++ b/thys/BTree/BPlusTree_ImpSplit.thy @@ -0,0 +1,572 @@ +theory BPlusTree_ImpSplit + imports + BPlusTree_Imp + BPlusTree_Split + Imperative_Loops +begin + +definition "split_relation xs \ + \(as,bs) i. i \ length xs \ as = take i xs \ bs = drop i xs" + +lemma split_relation_alt: + "split_relation as (ls,rs) i = (as = ls@rs \ i = length ls)" + by (auto simp add: split_relation_def) + + +lemma split_relation_length: "split_relation xs (ls,rs) (length xs) = (ls = xs \ rs = [])" + by (simp add: split_relation_def) + +(* auxiliary lemmas on assns *) +(* simp? not sure if it always makes things more easy *) +lemma list_assn_prod_map: "list_assn (A \\<^sub>a B) xs ys = list_assn B (map snd xs) (map snd ys) * list_assn A (map fst xs) (map fst ys)" + apply(induct "(A \\<^sub>a B)" xs ys rule: list_assn.induct) + apply(auto simp add: ab_semigroup_mult_class.mult.left_commute ent_star_mono star_aci(2) star_assoc) + done + +(* concrete *) +lemma id_assn_list: "h \ list_assn id_assn (xs::'a list) ys \ xs = ys" + apply(induction "id_assn::('a \ 'a \ assn)" xs ys rule: list_assn.induct) + apply(auto simp add: less_Suc_eq_0_disj pure_def) + done + +lemma id_assn_list_alt: "list_assn id_assn (xs::'a list) ys = \(xs = ys)" + apply(induction "id_assn::('a \ 'a \ assn)" xs ys rule: list_assn.induct) + apply(auto simp add: less_Suc_eq_0_disj pure_def) + done + + +lemma snd_map_help: + "x \ length tsi \ + (\j snd (tsi!x) = ((map snd tsi)!x)" + by auto + + +lemma split_ismeq: "((a::nat) \ b \ X) = ((a < b \ X) \ (a = b \ X))" + by auto + +lemma split_relation_map: "split_relation as (ls,rs) i \ split_relation (map f as) (map f ls, map f rs) i" + apply(induction as arbitrary: ls rs i) + apply(auto simp add: split_relation_def take_map drop_Cons') + apply(metis list.simps(9) take_map) + done + +lemma split_relation_access: "\split_relation as (ls,rs) i; rs = r#rrs\ \ as!i = r" + by (simp add: split_relation_alt) + + + +lemma index_to_elem_all: "(\jx \ set xs. P x)" + by (simp add: all_set_conv_nth) + +lemma index_to_elem: "n < length xs \ (\jx \ set (take n xs). P x)" + by (simp add: all_set_conv_nth) + (* ----------------- *) + +definition split_half :: "'a::heap pfarray \ nat Heap" + where + "split_half a \ do { + l \ pfa_length a; + return ((l + 1) div 2) +}" + +lemma split_half_rule[sep_heap_rules]: "< + is_pfa c tsi a> + split_half a + <\i. + is_pfa c tsi a + * \(i = (length tsi + 1) div 2 \ split_relation tsi (BPlusTree_Split.split_half tsi) i)>" + unfolding split_half_def split_relation_def + apply(rule hoare_triple_preI) + apply(sep_auto dest!: list_assn_len mod_starD) + done + + +subsection "The imperative split locale" + +locale split\<^sub>i_tree = abs_split_tree: BPlusTree_Split.split_tree split + for split:: + "('a::{heap,default,linorder,order_top} bplustree \ 'a) list \ 'a + \ ('a bplustree \ 'a) list \ ('a bplustree \ 'a) list" + + fixes split\<^sub>i:: "('a btnode ref option \ 'a::{heap,default,linorder,order_top}) pfarray \ 'a \ nat Heap" + assumes split\<^sub>i_rule [sep_heap_rules]:"sorted_less (separators ts) \ + length tsi = length rs \ + tsi'' = zip (zip (map fst tsi) (zip (butlast (r#rs)) (butlast (rs@[z])))) (map snd tsi) \ + + split\<^sub>i (a,n) p + <\i. + is_pfa c tsi (a,n) + * blist_assn k ts tsi'' + * \(split_relation ts (split ts p) i)>\<^sub>t" + +locale split\<^sub>i_list = abs_split_list: split_list split_list + for split_list:: + "('a::{heap,default,linorder,order_top}) list \ 'a + \ 'a list \ 'a list" + + fixes split\<^sub>i_list:: "('a::{heap,default,linorder,order_top}) pfarray \ 'a \ nat Heap" + assumes split\<^sub>i_list_rule [sep_heap_rules]: "sorted_less xs \ + + split\<^sub>i_list (a,n) p + <\i. + is_pfa c xs (a,n) + * \(split_relation xs (split_list xs p) i)>\<^sub>t" + + +locale split\<^sub>i_full = split\<^sub>i_tree: split\<^sub>i_tree split + split\<^sub>i_list: split\<^sub>i_list split_list + for split:: + "('a bplustree \ 'a::{linorder,heap,default,order_top}) list \ 'a + \ ('a bplustree \ 'a) list \ ('a bplustree \ 'a) list" + and split_list:: + "'a::{default,linorder,order_top,heap} list \ 'a + \ 'a list \ 'a list" + +section "Imperative split operations" + +text "So far, we have only given a functional specification of a possible split. + We will now provide imperative split functions that refine the functional specification. + However, rather than tracing the execution of the abstract specification, + the imperative versions are implemented using while-loops." + + +subsection "Linear split" + +text "The linear split is the most simple split function for binary trees. + It serves a good example on how to use while-loops in Imperative/HOL + and how to prove Hoare-Triples about its application using loop invariants." + +definition lin_split :: "('a::heap \ 'b::{heap,linorder}) pfarray \ 'b \ nat Heap" + where + "lin_split \ \ (a,n) p. do { + + i \ heap_WHILET + (\i. if i Array.nth a i; + return (si. return (i+1)) + 0; + + return i +}" + + +lemma lin_split_rule: " +< is_pfa c xs (a,n)> + lin_split (a,n) p + <\i. is_pfa c xs (a,n) * \(i\n \ (\j (i snd (xs!i)\p))>\<^sub>t" + unfolding lin_split_def + + supply R = heap_WHILET_rule''[where + R = "measure (\i. n - i)" + and I = "\i. is_pfa c xs (a,n) * \(i\n \ (\j 'b \ nat Heap" + where + "bin'_split \ \(a,n) p. do { + (low',high') \ heap_WHILET + (\(low,high). return (low < high)) + (\(low,high). let mid = ((low + high) div 2) in + do { + s \ Array.nth a mid; + if p < s then + return (low, mid) + else if p > s then + return (mid+1, high) + else return (mid,mid) + }) + (0::nat,n); + return low' +}" + + +thm sorted_wrt_nth_less + +(* alternative: replace (\j 0 \ xs!(l-1) < p)*) +lemma bin'_split_rule: " +sorted_less xs \ +< is_pfa c xs (a,n)> + bin'_split (a,n) p + <\l. is_pfa c xs (a,n) * \(l \ n \ (\j (l xs!l\p)) >\<^sub>t" + unfolding bin'_split_def + + supply R = heap_WHILET_rule''[where + R = "measure (\(l,h). h-l)" + and I = "\(l,h). is_pfa c xs (a,n) * \(l\h \ h \ n \ (\j (h xs!h\p))" + and b = "\(l,h). l length l'a" + assume a: "l'a ! ((aa + n) div 2) < p" + moreover assume "aa < n" + ultimately have b: "((aa+n)div 2) < n" + by linarith + then have "(take n l'a) ! ((aa + n) div 2) < p" + using a by auto + moreover assume "sorted_less (take n l'a)" + ultimately have "\j. j < (aa+n)div 2 \ (take n l'a) ! j < (take n l'a) ! ((aa + n) div 2)" + using + sorted_wrt_nth_less[where ?P="(<)" and xs="(take n l'a)" and ?j="((aa + n) div 2)"] + a b "0" by auto + moreover fix j assume "j < (aa+n) div 2" + ultimately show "l'a ! j < p" using "0" b + using \take n l'a ! ((aa + n) div 2) < p\ dual_order.strict_trans by auto + qed + subgoal for l' aa b l'a aaa ba j + proof - + assume t0: "n \ length l'a" + assume t1: "aa < b" + assume a: "l'a ! ((aa + b) div 2) < p" + moreover assume "b \ n" + ultimately have b: "((aa+b)div 2) < n" using t1 + by linarith + then have "(take n l'a) ! ((aa + b) div 2) < p" + using a by auto + moreover assume "sorted_less (take n l'a)" + ultimately have "\j. j < (aa+b)div 2 \ (take n l'a) ! j < (take n l'a) ! ((aa + b) div 2)" + using + sorted_wrt_nth_less[where ?P="(<)" and xs="(take n l'a)" and ?j="((aa + b) div 2)"] + a b t0 by auto + moreover fix j assume "j < (aa+b) div 2" + ultimately show "l'a ! j < p" using t0 b + using \take n l'a ! ((aa + b) div 2) < p\ dual_order.strict_trans by auto + qed + apply sep_auto + apply (metis le_less nth_take) + apply (metis le_less nth_take) + apply sep_auto + subgoal for l' aa l'a aaa ba j + proof - + assume t0: "aa < n" + assume t1: " n \ length l'a" + assume t4: "sorted_less (take n l'a)" + assume t5: "j < (aa + n) div 2" + have "(aa+n) div 2 < n" using t0 by linarith + then have "(take n l'a) ! j < (take n l'a) ! ((aa + n) div 2)" + using t0 sorted_wrt_nth_less[where xs="take n l'a" and ?j="((aa + n) div 2)"] + t1 t4 t5 by auto + then show ?thesis + using \(aa + n) div 2 < n\ t5 by auto + qed + subgoal for l' aa b l'a aaa ba j + proof - + assume t0: "aa < b" + assume t1: " n \ length l'a" + assume t3: "b \ n" + assume t4: "sorted_less (take n l'a)" + assume t5: "j < (aa + b) div 2" + have "(aa+b) div 2 < n" using t3 t0 by linarith + then have "(take n l'a) ! j < (take n l'a) ! ((aa + b) div 2)" + using t0 sorted_wrt_nth_less[where xs="take n l'a" and ?j="((aa + b) div 2)"] + t1 t4 t5 by auto + then show ?thesis + using \(aa + b) div 2 < n\ t5 by auto + qed + apply (metis nth_take order_mono_setup.refl) + apply sep_auto + apply (sep_auto simp add: is_pfa_def) + done + +text "We can fortunately directly use this function as the split_list interpretation" + + +text "Then, using the same loop invariant, a binary split for B-tree-like arrays +is derived in a straightforward manner." + + +definition bin_split :: "('a::heap \ 'b::{heap,linorder}) pfarray \ 'b \ nat Heap" + where + "bin_split \ \(a,n) p. do { + (low',high') \ heap_WHILET + (\(low,high). return (low < high)) + (\(low,high). let mid = ((low + high) div 2) in + do { + (_,s) \ Array.nth a mid; + if p < s then + return (low, mid) + else if p > s then + return (mid+1, high) + else return (mid,mid) + }) + (0::nat,n); + return low' +}" + + +thm nth_take + +lemma nth_take_eq: "take n ls = take n ls' \ i < n \ ls!i = ls'!i" + by (metis nth_take) + +lemma map_snd_sorted_less: "\sorted_less (map snd xs); i < j; j < length xs\ + \ snd (xs ! i) < snd (xs ! j)" + by (metis (mono_tags, opaque_lifting) length_map less_trans nth_map sorted_wrt_iff_nth_less) + +lemma map_snd_sorted_lesseq: "\sorted_less (map snd xs); i \ j; j < length xs\ + \ snd (xs ! i) \ snd (xs ! j)" + by (metis eq_iff less_imp_le map_snd_sorted_less order.not_eq_order_implies_strict) + +lemma bin_split_rule: " +sorted_less (map snd xs) \ +< is_pfa c xs (a,n)> + bin_split (a,n) p + <\l. is_pfa c xs (a,n) * \(l \ n \ (\j (l snd(xs!l)\p)) >\<^sub>t" + (* this works in principle, as demonstrated above *) + unfolding bin_split_def + + supply R = heap_WHILET_rule''[where + R = "measure (\(l,h). h-l)" + and I = "\(l,h). is_pfa c xs (a,n) * \(l\h \ h \ n \ (\j (h snd (xs!h)\p))" + and b = "\(l,h). lAny function that yields the heap rule +we have obtained for bin\_split and lin\_split also +refines this abstract split.\ + +locale split\<^sub>i_tree_smeq = + fixes split_fun :: "('a::{heap,default,linorder,order_top} btnode ref option \ 'a) array \ nat \ 'a \ nat Heap" + assumes split_rule: "sorted_less (separators xs) \ + + split_fun (a, n) (p::'a) + <\r. is_pfa c xs (a, n) * + \ (r \ n \ + (\j + (r < n \ p \ snd (xs ! r)))>\<^sub>t" +begin + + +lemma linear_split_full: "\(_,s) \ set xs. s < p \ linear_split xs p = (xs,[])" + by simp + + +lemma linear_split_split: + assumes "n < length xs" + and "(\(_,s) \ set (take n xs). s < p)" + and " (case (xs!n) of (_,s) \ \(s < p))" + shows "linear_split xs p = (take n xs, drop n xs)" + using assms apply (auto) + apply (metis (mono_tags, lifting) id_take_nth_drop old.prod.case takeWhile_eq_all_conv takeWhile_tail) + by (metis (no_types, lifting) Cons_nth_drop_Suc case_prod_conv dropWhile.simps(2) dropWhile_append2 id_take_nth_drop) + + +(* TODO refactor proof? *) +lemma split_rule_linear_split: + shows + "sorted_less (separators ts) \ + min (length ks) (length tsi) = length tsi \ + tsi' = zip ks (separators tsi) \ + < + is_pfa c tsi (a,n) + * list_assn (A \\<^sub>a id_assn) ts tsi'> + split_fun (a,n) p + <\i. + is_pfa c tsi (a,n) + * list_assn (A \\<^sub>a id_assn) ts tsi' + * \(split_relation ts (linear_split ts p) i)>\<^sub>t" + apply(rule hoare_triple_preI) + apply (sep_auto heap: split_rule dest!: mod_starD id_assn_list + simp add: list_assn_prod_map split_ismeq map_snd_zip_take simp del: linear_split.simps) + apply(auto simp add: is_pfa_def simp del: linear_split.simps) +proof - + + fix h l' assume heap_init: + "h \ a \\<^sub>a l'" + "map snd ts = (map snd (take n l'))" + "n \ length l'" + + + show full_thm: "\j + split_relation ts (linear_split ts p) n" + proof - + assume sm_list: "\jj < length (map snd (take n l')). ((map snd (take n l'))!j) < p" + by simp + then have "\j(_,s) \ set ts. s < p" + by (metis case_prod_unfold in_set_conv_nth length_map nth_map) + then have "linear_split ts p = (ts, [])" + using linear_split_full[of ts p] by simp + then show "split_relation ts (linear_split ts p) n" + using split_relation_length + by (metis heap_init(2) heap_init(3) length_map length_take min.absorb2) + + qed + then show "\j + p \ snd (take n l' ! n) \ + split_relation ts (linear_split ts p) n" + by simp + + show part_thm: "\x. x < n \ + \j + p \ snd (l' ! x) \ split_relation ts (linear_split ts p) x" + proof - + fix x assume x_sm_len: "x < n" + moreover assume sm_list: "\jjj(_,x) \ set (take x ts). x < p" + by (auto simp add: in_set_conv_nth min.absorb2)+ + moreover assume "p \ snd (l' ! x)" + then have "case l'!x of (_,s) \ \(s < p)" + by (simp add: case_prod_unfold) + then have "case ts!x of (_,s) \ \(s < p)" + using heap_init x_sm_len x_sm_len_ts + by (metis (mono_tags, lifting) case_prod_unfold length_map length_take min.absorb2 nth_take snd_map_help(2)) + ultimately have "linear_split ts p = (take x ts, drop x ts)" + using x_sm_len_ts linear_split_split[of x ts p] heap_init + by (metis length_map length_take min.absorb2) + then show "split_relation ts (linear_split ts p) x" + using x_sm_len_ts + by (metis append_take_drop_id heap_init(2) heap_init(3) length_map length_take less_imp_le_nat min.absorb2 split_relation_alt) + qed +qed + + +sublocale split\<^sub>i_tree linear_split split_fun + apply(unfold_locales) + unfolding linear_split.simps + subgoal by (auto split: list.splits) + subgoal + apply (auto split: list.splits) + by (metis (no_types, lifting) case_prodD in_set_conv_decomp takeWhile_eq_all_conv takeWhile_idem) + subgoal + by (metis case_prod_conv hd_dropWhile le_less_linear list.sel(1) list.simps(3)) + subgoal for ts tsi rs tsi'' r z c a n k p + supply R= split_rule_linear_split[of ts "zip (subtrees tsi) (zip (butlast (r # rs)) (butlast (rs @ [z])))" tsi +tsi'' + ] + thm R + apply(sep_auto heap: R simp del: last.simps butlast.simps) + done + done + +end + +locale split\<^sub>i_list_smeq = + fixes split_list_fun :: "('a::{heap,default,linorder,order_top} array \ nat) \ 'a \ nat Heap" + assumes split_list_rule: "sorted_less xs \ + + split_list_fun (a, n) (p::'a) + <\r. is_pfa c xs (a, n) * + \ (r \ n \ + (\j + (r < n \ p \ xs ! r))>\<^sub>t" +begin + + +lemma split_list_rule_linear_split: + shows + "sorted_less ts \ < + is_pfa c ts (a,n)> + split_list_fun (a,n) p + <\i. + is_pfa c ts (a,n) + * \(split_relation ts (linear_split_list ts p) i)>\<^sub>t" + apply(rule hoare_triple_preI) + apply (sep_auto heap: split_list_rule dest!: mod_starD + simp add: list_assn_prod_map split_ismeq id_assn_list_alt simp del: linear_split_list.simps) + apply(auto simp add: is_pfa_def split_relation_alt) + subgoal by (smt (verit) eq_len_takeWhile_conv leD length_take length_takeWhile_le linorder_neqE_nat min_eq_arg(2) nth_length_takeWhile nth_take nth_take_eq) + subgoal by (metis le_neq_implies_less length_take length_takeWhile_le min_eq_arg(2) nth_length_takeWhile nth_take) + subgoal by (metis le_neq_implies_less length_take length_takeWhile_le min_eq_arg(2) nth_length_takeWhile nth_take) + done + + +sublocale split\<^sub>i_list linear_split_list split_list_fun + apply(unfold_locales) + subgoal by (auto split: list.splits) + subgoal + apply (auto split: list.splits) + by (metis (no_types, lifting) case_prodD in_set_conv_decomp takeWhile_eq_all_conv takeWhile_idem) + subgoal + apply (auto split: list.splits) + by (metis case_prod_conv hd_dropWhile le_less_linear list.sel(1) list.simps(3)) + apply(sep_auto heap: split_list_rule_linear_split) + done + +end + +locale split\<^sub>i_full_smeq = split\<^sub>i_tree_smeq split_fun + split\<^sub>i_list_smeq split_list_fun + for split_fun:: "('a::{heap,default,linorder,order_top} btnode ref option \ 'a) array \ nat \ 'a \ nat Heap" + and split_list_fun :: "('a::{heap,default,linorder,order_top} array \ nat) \ 'a \ nat Heap" +begin + +sublocale split\<^sub>i_full split_fun split_list_fun linear_split linear_split_list + by (unfold_locales) + +end + +text "The fact that these functions fulfill the locale specifications will only be shown +when we try to extract the executable code, because +the correct definitions have to be derived directly at the first instance of interpretation." + +end \ No newline at end of file diff --git a/thys/BTree/BPlusTree_ImpSplitCE.thy b/thys/BTree/BPlusTree_ImpSplitCE.thy new file mode 100644 --- /dev/null +++ b/thys/BTree/BPlusTree_ImpSplitCE.thy @@ -0,0 +1,117 @@ +theory BPlusTree_ImpSplitCE + imports + BPlusTree_ImpRange + BPlusTree_ImpSet + BPlusTree_SplitCE +begin + + +subsection "Obtaining executable code" + +text "In order to obtain fully defined functions, +we need to plug our split function implementations +into the locales we introduced previously." + +text "Obtaining actual code turns out to be slightly more difficult + due to the use of locales. However, we successfully obtain +the B-tree insertion and membership query with binary search splitting." + + + +global_interpretation bplustree_imp_binary_split_list: split\<^sub>i_list_smeq bin'_split + defines bplustree_isin_list = bplustree_imp_binary_split_list.isin_list\<^sub>i + and bplustree_ins_list = bplustree_imp_binary_split_list.ins_list\<^sub>i + and bplustree_del_list = bplustree_imp_binary_split_list.del_list\<^sub>i + and bplustree_lrange_list = bplustree_imp_binary_split_list.lrange_list\<^sub>i + apply unfold_locales + apply(sep_auto heap: bin'_split_rule) + done + +print_theorems + +global_interpretation bplustree_imp_binary_split: + split\<^sub>i_full_smeq bin_split bin'_split + defines bplustree_isin = bplustree_imp_binary_split.isin\<^sub>i + and bplustree_ins = bplustree_imp_binary_split.ins\<^sub>i + and bplustree_insert = bplustree_imp_binary_split.insert\<^sub>i + (*and bplustree_del = bplustree_imp_binary_split.del + and bplustree_delete = bplustree_imp_binary_split.delete*) + and bplustree_empty = bplustree_imp_binary_split.empty\<^sub>i + and bplustree_leaf_nodes_lrange = bplustree_imp_binary_split.leaf_nodes_lrange\<^sub>i + and bplustree_lrange = bplustree_imp_binary_split.concat_leaf_nodes_lrange\<^sub>i + apply unfold_locales + apply(sep_auto heap: bin_split_rule) + done + +lemma [code]: +"bplustree_isin p x = +!p \ +(\node. + case node of + Btnode ts t \ + bin_split ts x \ + (\i. pfa_length ts \ + (\tsl. if i < tsl + then pfa_get ts i \ + (\s. let (sub, sep) = s in bplustree_isin (the sub) x) + else bplustree_isin t x)) + | Btleaf xs xa \ bplustree_isin_list x xs)" + unfolding bplustree_isin_list_def + by (simp add: bplustree_imp_binary_split.isin\<^sub>i.simps) +lemma [code]: +"bplustree_ins k x p = +!p \ +(\node. + case node of + Btnode tsi ti \ + bin_split tsi x \ + (\i. pfa_length tsi \ + (\tsl. if i < tsl + then pfa_get tsi i \ + (\s. let (sub, sep) = s + in bplustree_ins k x (the sub) \ + (\r. case r of + bplustree_imp_binary_split.T\<^sub>i lp \ + pfa_set tsi i (Some lp, sep) \ + (\_. return (bplustree_imp_binary_split.T\<^sub>i p)) + | bplustree_imp_binary_split.Up\<^sub>i lp x' rp \ + pfa_set tsi i (Some rp, sep) \ + (\_. + pfa_insert_grow tsi i (Some lp, x') \ + (\tsi'. p := Btnode tsi' ti \ (\_. bplustree_imp_binary_split.node\<^sub>i k p))))) + else bplustree_ins k x ti \ + (\r. case r of + bplustree_imp_binary_split.T\<^sub>i lp \ + p := Btnode tsi lp \ + (\_. return (bplustree_imp_binary_split.T\<^sub>i p)) + | bplustree_imp_binary_split.Up\<^sub>i lp x' rp \ + pfa_append_grow' tsi (Some lp, x') \ + (\tsi'. + p := Btnode tsi' rp \ + (\_. bplustree_imp_binary_split.node\<^sub>i k p))))) + | Btleaf ksi nxt \ + bplustree_ins_list x ksi \ + (\ksi'. p := Btleaf ksi' nxt \ (\_. bplustree_imp_binary_split.Lnode\<^sub>i k p)))" + unfolding bplustree_ins_list_def + by (simp add: bplustree_imp_binary_split.ins\<^sub>i.simps) + +declare bplustree_imp_binary_split.leaf_nodes_lrange\<^sub>i.simps[code] +lemma [code]: +"bplustree_lrange ti x = + bplustree_leaf_nodes_lrange ti x \ + (\lp. !the lp \ + (\li. case li of + Btleaf xs nxt \ + bplustree_lrange_list x xs \ + (\arr_it. leaf_values_adjust (nxt, None) arr_it \ return)))" + unfolding bplustree_lrange_list_def + by (simp add: bplustree_imp_binary_split.concat_leaf_nodes_lrange\<^sub>i_def) + +export_code bplustree_empty bplustree_isin bplustree_insert bplustree_lrange leaf_values_init leaf_values_next leaf_values_has_next checking OCaml SML Scala +export_code bplustree_empty bplustree_isin bplustree_insert bplustree_lrange leaf_values_init leaf_values_next leaf_values_has_next in OCaml module_name BPlusTree +export_code bplustree_empty bplustree_isin bplustree_insert bplustree_lrange leaf_values_init leaf_values_next leaf_values_has_next in SML module_name BPlusTree +export_code bplustree_empty bplustree_isin bplustree_insert bplustree_lrange leaf_values_init leaf_values_next leaf_values_has_next in Scala module_name BPlusTree + + + +end \ No newline at end of file diff --git a/thys/BTree/BPlusTree_Iter.thy b/thys/BTree/BPlusTree_Iter.thy new file mode 100644 --- /dev/null +++ b/thys/BTree/BPlusTree_Iter.thy @@ -0,0 +1,1345 @@ +theory BPlusTree_Iter + imports + BPlusTree_Imp + "HOL-Real_Asymp.Inst_Existentials" + "Separation_Logic_Imperative_HOL.Imp_List_Spec" + Flatten_Iter_Spec + Partially_Filled_Array_Iter + Subst_Mod_Mult_AC +begin + + +(* TODO use list_zip? \ not well defined return type *) + +fun bplustree_assn_leafs :: "nat \ ('a::heap) bplustree \ 'a btnode ref \ 'a btnode ref option \ 'a btnode ref option \ 'a btnode ref list \ assn" where + "bplustree_assn_leafs k (Leaf xs) a r z leafptrs = + (\\<^sub>A xsi fwd. + a \\<^sub>r Btleaf xsi fwd + * is_pfa (2*k) xs xsi + * \(fwd = z) + * \(r = Some a) + * \(leafptrs = [a]) + )" | + "bplustree_assn_leafs k (Node ts t) a r z leafptrs = + (\\<^sub>A tsi ti tsi' tsi'' rs split. + a \\<^sub>r Btnode tsi ti + * bplustree_assn_leafs k t ti (last (r#rs)) (last (rs@[z])) (last split) + * is_pfa (2*k) tsi' tsi + * \(concat split = leafptrs) + * \(length tsi' = length rs) + * \(length split = length rs + 1) + * \(tsi'' = zip (zip (map fst tsi') (zip (butlast (r#rs)) (zip (butlast (rs@[z])) (butlast split)))) (map snd tsi')) + * list_assn ((\ t (ti,r',z',lptrs). bplustree_assn_leafs k t (the ti) r' z' lptrs) \\<^sub>a id_assn) ts tsi'' + )" + +(*fun make_list_list where "make_list_list xs = [xs]" + +lemma make_list_list_concat: "concat (make_list_list ys) = ys" + by auto + +lemma ex_concat: "\xs. concat xs = ys" + using make_list_list_concat by blast*) + +lemma inst_same: "(\x. P x = Q x) \ (\\<^sub>A x. P x) = (\\<^sub>A x. Q x)" + by simp + + +lemma reorder_ex: + "\z. (\\<^sub>Aa b c d e f g. z a b c d e f g) = (\\<^sub>Ab c d e f a g. z a b c d e f g)" + "\z. (\\<^sub>Aa b . z a b) = (\\<^sub>Ab a. z a b)" + "\z. (\\<^sub>Aa b c d. z a b c d) = (\\<^sub>Ab c a d. z a b c d)" + apply(intro ent_iffI; sep_auto)+ + done + +lemma inst_same2: "(\x. P = Q x) \ P = (\\<^sub>A x. Q x)" + by simp + +lemma pure_eq_pre: + "(P \ Q = R) \ (Q * \P = R * \P)" + by fastforce + + +lemma otf_lem_comm_ex: +"\a b c d e f g. (\\<^sub>A x. a * b x * c * d x * e x * f x * g x) = a * c * (\\<^sub>A x. b x * d x * e x * f x * g x)" +"\a b c d e. (\\<^sub>Aaa x. a * b x * c * d aa * e aa) = (a * c * (\\<^sub>A aa x. b x * d aa * e aa))" +"\b d e. (\\<^sub>A aa x. b x * d aa * e aa) = (\\<^sub>A x. b x) * (\\<^sub>A aa. d aa * e aa)" + by (auto simp add: algebra_simps) + +declare last.simps[simp del] butlast.simps[simp del] +lemma bplustree_extract_leafs: + "bplustree_assn k t ti r z = (\\<^sub>Aleafptrs. bplustree_assn_leafs k t ti r z leafptrs)" +proof(induction arbitrary: r rule: bplustree_assn.induct ) + case (1 k xs a r z) + then show ?case + (*apply auto*) + apply (rule ent_iffI) + subgoal + apply(inst_ex_assn "[a]") + apply sep_auto + done + subgoal + apply(rule ent_ex_preI) + apply clarsimp + apply(rule ent_ex_preI)+ + subgoal for x xsi fwd + apply(inst_ex_assn xsi fwd) + apply simp + done + done + done +next + case Istep: (2 k ts t a r z) + show ?case + apply(simp (no_asm)) + thm bplustree_assn_leafs.simps(2) + apply(subst reorder_ex(1)) + apply(intro inst_same) + thm reorder_ex(2) + apply(subst reorder_ex(2)) + apply(subst reorder_ex(3)) + apply(rule inst_same) +(* pre-massage term for an explicit treatment. ignore inductive assumptions in simp s.t. +bplustree of the last tree does not get simplified away immediately *) + proof(goal_cases) + case (1 tsi ti tsi' rs) + have *: " + length tsi's = length tss \ + length tss = length rss \ + set tsi's \ set tsi' \ + set rss \ set rs \ + set tss \ set ts \ + blist_assn k tss + (zip (zip (subtrees tsi's) (zip (butlast (ra # rss)) rss)) (separators tsi's)) = + (\\<^sub>Asplit. list_assn ((\ t (ti,r',z',lptrs). bplustree_assn_leafs k t (the ti) r' z' lptrs) \\<^sub>a id_assn) tss + (zip (zip (subtrees tsi's) (zip (butlast (ra # rss)) (zip rss split))) (separators tsi's)) * + \(length split = length rss))" + for rss tsi's tss ra + proof (induct arbitrary: ra rule: list_induct3) + case Nil + then show ?case + apply sep_auto + apply(subst ex_one_point_gen[where v="[]"]) + apply simp_all + done + next + case (Cons subsepi tsi's subsep tss subleaf rss r) + then show ?case + apply (auto simp add: butlast_double_Cons last_double_Cons) + apply(auto simp add: prod_assn_def split: prod.splits) + proof(goal_cases) + case (1 sub sep) + then have *: "bplustree_assn k sub (the (fst subsepi)) r subleaf = (\\<^sub>As. bplustree_assn_leafs k sub (the (fst subsepi)) r subleaf s)" + proof - + have "subsep \ set ts" + by (simp add: "1"(10) "1"(8)) + moreover obtain temp1 temp2 where "((fst subsepi, (temp1:: 'a btnode ref option), subleaf), (temp2::'a)) \ set [((fst subsepi, temp1, subleaf), temp2)]" + by auto + ultimately show ?thesis + using Istep(2)[of "(sub,sep)" "((fst subsepi, temp1, subleaf), temp2)" "[((fst subsepi, temp1, subleaf), temp2)]" "fst subsepi" "(temp1, subleaf)" temp1 subleaf r] + using 1 + by simp + qed + show ?case + apply (simp add: * 1(3)[of subleaf]) + apply(intro ent_iffI) + subgoal + apply(intro ent_ex_preI) + subgoal for split x + apply(inst_ex_assn "x#split") + apply simp + done + done + subgoal + apply(intro ent_ex_preI) + subgoal for split + apply(cases split) + apply simp + subgoal for hdsplit tlsplit + apply(inst_ex_assn "tlsplit" "hdsplit") + apply (auto) + done + done + done + done + qed + qed + have **: "bplustree_assn k t ti (last (r # rs)) z = (\\<^sub>Alsplit. bplustree_assn_leafs k t ti (last (r # rs)) z lsplit)" + using Istep(1)[of ti "last(r #rs)" "[]"] + by (auto simp add: last.simps) + show ?case +(* apply IH to last tree *) + apply(subst **) + apply(simp add: inst_same[OF bplustree_assn_leafs.simps(2)]) + proof(intro ent_iffI, goal_cases) + case _: (1) + show ?case +(* apply IH to list via rule just shown *) + apply(rule entails_preI) + apply(intro ent_ex_preI) + apply(clarsimp dest!: mod_starD list_assn_len) + apply (subst *[of tsi' ts rs]) + apply simp_all +(* show that the remainder is equivalent *) + apply(intro ent_ex_preI) + apply(rule entails_preI) + apply(clarsimp dest!: mod_starD list_assn_len) + subgoal for lsplit _ _ _ _ _ _ _ split + find_theorems "\\<^sub>A_._" + apply(inst_ex_assn "concat (split@[lsplit])" "zip (zip (subtrees tsi') (zip (butlast (r # rs)) (zip rs (butlast (split@[lsplit]))))) + (separators tsi')" "split@[lsplit]") + apply (sep_auto simp add: last.simps butlast.simps) + done + done + next + case _: (2) + show ?case +(* apply IH to list via rule just shown (other direction) *) + apply(rule entails_preI) + apply(rule ent_ex_preI) + apply(rule ent_ex_preI) + apply(clarsimp dest!: mod_starD list_assn_len) + apply(subst merge_pure_star[symmetric] mult.left_assoc)+ + apply(subst otf_lem_comm_ex)+ + apply(rule ent_star_mono) + subgoal by sep_auto +proof(goal_cases) + case (1 c aa d ae bd af be ag bf) + have **: "(\\<^sub>Ax. bplustree_assn_leafs k t ti (last (r # rs)) z (last x) * + list_assn + ((\t (ti, r', x, y). bplustree_assn_leafs k t (the ti) r' x y) \\<^sub>a id_assn) + ts aa * + \ (concat x = c) * + \ (length x = Suc (length rs)) * + \ (aa = + zip (zip (subtrees tsi') (zip (butlast (r # rs)) (zip rs (butlast x)))) + (separators tsi'))) \\<^sub>A ((\\<^sub>Asplit. list_assn ((\t (ti, r', x, y). bplustree_assn_leafs k t (the ti) r' x y) \\<^sub>a id_assn) ts (zip (zip (subtrees tsi') (zip (butlast (r # rs)) (zip rs split))) (separators tsi')) * + \ (length split = length rs)) * (\\<^sub>Alsplit. bplustree_assn_leafs k t ti (last (r # rs)) z lsplit) +)" + using 1 by sep_auto + from ** show ?case + apply(rule ent_trans) + apply(subst mult.commute[of "ex_assn (bplustree_assn_leafs k t ti (last (r # rs)) z)"]) + apply(rule ent_star_mono) + prefer 2 + subgoal by sep_auto + subgoal + apply(subst *[of tsi' ts rs r, symmetric]) + apply(simp_all add: 1) + apply sep_auto + done + done + qed + qed +qed +qed +declare last.simps[simp add] butlast.simps[simp add] + +(* even without the existential quantifier, we get our general assertion, used in insertion etc back*) +lemma bplustree_discard_leafs: + "bplustree_assn_leafs k t ti r z leafptrs \\<^sub>A bplustree_assn k t ti r z" + by (simp add: bplustree_extract_leafs) + + +fun leaf_nodes_assn :: "nat \ ('a::heap) bplustree list \ 'a btnode ref option \ 'a btnode ref option \ 'a btnode ref list \ assn" where + "leaf_nodes_assn k ((Leaf xs)#lns) (Some r) z (r'#lptrs) = + (\\<^sub>A xsi fwd. + r \\<^sub>r Btleaf xsi fwd + * is_pfa (2*k) xs xsi + * leaf_nodes_assn k lns fwd z lptrs + * \(r = r') + )" | + "leaf_nodes_assn k [] r z [] = \(r = z)" | + "leaf_nodes_assn _ _ _ _ _ = false" + + +fun trunk_assn :: "nat \ ('a::heap) bplustree \ 'a btnode ref \ 'a btnode ref option \ 'a btnode ref option \ 'a btnode ref list \ assn" where + "trunk_assn k (Leaf xs) a r z lptrs = \(r = Some a \ lptrs = [a])" | + "trunk_assn k (Node ts t) a r z lptrs = + (\\<^sub>A tsi ti tsi' tsi'' rs split. + a \\<^sub>r Btnode tsi ti + * trunk_assn k t ti (last (r#rs)) (last (rs@[z])) (last split) + * is_pfa (2*k) tsi' tsi + * \(concat split = lptrs) + * \(length tsi' = length rs) + * \(length split = length rs + 1) + * \(tsi'' = zip (zip (map fst tsi') (zip (butlast (r#rs)) (zip (butlast (rs@[z])) (butlast split)))) (map snd tsi')) + * list_assn ((\ t (ti,r',z',lptrs). trunk_assn k t (the ti) r' z' lptrs) \\<^sub>a id_assn) ts tsi'' + )" + +lemma leaf_nodes_assn_split: +"length xs = length xsi \ ysi = (yi#ysr) \ + leaf_nodes_assn k (xs @ ys) r z (xsi @ ysi) = leaf_nodes_assn k xs r (Some yi) xsi * leaf_nodes_assn k ys (Some yi) z ysi" +proof(induction arbitrary: r rule: list_induct2) + case (Nil r) + then show ?case + apply(cases r; cases ys) + apply clarsimp_all + subgoal for _ t _ + apply(cases t) + apply clarsimp + apply(intro inst_same) + apply(rule pure_eq_pre) + apply clarsimp_all + done + done +next + case (Cons x xs xi xsi r) + show ?case + apply(cases r; cases x) + apply clarsimp_all + apply(intro inst_same) + apply(rule pure_eq_pre) + subgoal for a x1 xsi' fwd + using Cons.IH[of fwd, OF Cons.prems] + apply (clarsimp simp add: mult.assoc) + done + done +qed + +lemma "length xs \ length xsi \ leaf_nodes_assn k xs r z xsi = false" + by (induction rule: leaf_nodes_assn.induct) auto + +lemma imp_eq_pure: "(\h. h \ P \ Q) = (P = P * \(Q))" + apply(intro iffI) + subgoal using ent_iffI by force + subgoal by (metis mod_pure_star_dist) + done + +lemma imp_imp_pure: "(\h. h \ P \ Q) \ (P = P * \(Q))" + using imp_eq_pure by blast + +thm concat_append +lemma concat_append_butlast: "xs \ [] \ concat (butlast xs) @ last xs = concat xs" + apply(induction xs) + apply auto + done + +declare last.simps[simp del] butlast.simps[simp del] +lemma bplustree_assn_leafs_len_imp: "h \ bplustree_assn_leafs k t a r z leafptrs \ length leafptrs = length (leaf_nodes t)" +proof(induction k t a r z leafptrs arbitrary: h rule: bplustree_assn_leafs.induct) + case (1 k xs a r z leafptrs) + then show ?case + by(clarsimp) +next + case (2 k ts t a r z leafptrs h) + from "2.prems" show ?case + apply(sep_auto) + proof(goal_cases) + case (1 tsia tsin ti tsi' rs split) + have *: " +length tss = length splits \ +length splits = length tsi's \ +length tsi's = length rss \ +set tss \ set ts \ +set tsi's \ set tsi' \ +set rss \ set rs \ +h \ list_assn + ((\t (ti, r', x, y). bplustree_assn_leafs k t (the ti) r' x y) \\<^sub>a id_assn) tss + (zip (zip (subtrees tsi's) (zip (butlast (ra # rss)) (zip rss splits))) (separators tsi's)) +\ (length (concat splits)) = length (concat (map (leaf_nodes \ fst) tss))" for h tss tsi's splits rss ra + proof(induction arbitrary: ra h rule: list_induct4) + case Nil + then show ?case + by sep_auto + next + case (Cons x xs y ys z zs w ws) + from Cons.prems show ?case + apply (auto simp add: butlast_double_Cons last_double_Cons) + apply(auto simp add: prod_assn_def split: prod.splits) + apply(auto dest!: mod_starD) + using Cons.IH + apply(auto) + using "2.IH"(2) + apply sep_auto + by (meson list.set_intros(1)) + qed + have **: "length ts = length rs" "split \ []" + using 1 by (auto dest!: mod_starD list_assn_len) + from 1 show ?case + apply(auto dest!: mod_starD) + apply(subst concat_append_butlast[symmetric]) + subgoal using ** by sep_auto + subgoal for h1 h2 h3 h4 h5 h6 h7 h8 + using *[of ts "butlast split" tsi' rs r "(h1,h2)"] "2.IH"(1)[of ti rs split "(h7,h8)"] + using ** + by sep_auto + done + qed +qed +declare last.simps[simp add] butlast.simps[simp add] + +lemma bplustree_assn_leafs_len_aux: "bplustree_assn_leafs k t a r z leafptrs = bplustree_assn_leafs k t a r z leafptrs * \(length leafptrs = length (leaf_nodes t))" + by (meson bplustree_assn_leafs_len_imp imp_imp_pure) + +declare last.simps[simp del] butlast.simps[simp del] +lemma trunk_assn_leafs_len_imp: "h \ trunk_assn k t a r z leafptrs \ length leafptrs = length (leaf_nodes t)" +(* same procedure as for bplustree_nodes_assn_leaf *) +proof(induction k t a r z leafptrs arbitrary: h rule: trunk_assn.induct) + case (1 k xs a r z leafptrs) + then show ?case + by(clarsimp) +next + case (2 k ts t a r z leafptrs h) + from "2.prems" show ?case + apply(sep_auto) + proof(goal_cases) + case (1 tsia tsin ti tsi' rs split) + have *: " +length tss = length splits \ +length splits = length tsi's \ +length tsi's = length rss \ +set tss \ set ts \ +set tsi's \ set tsi' \ +set rss \ set rs \ +h \ list_assn + ((\t (ti, r', x, y). trunk_assn k t (the ti) r' x y) \\<^sub>a id_assn) tss + (zip (zip (subtrees tsi's) (zip (butlast (ra # rss)) (zip rss splits))) (separators tsi's)) +\ (length (concat splits)) = length (concat (map (leaf_nodes \ fst) tss))" for h tss tsi's splits rss ra + proof(induction arbitrary: ra h rule: list_induct4) + case Nil + then show ?case + by sep_auto + next + case (Cons x xs y ys z zs w ws) + from Cons.prems show ?case + apply (auto simp add: butlast_double_Cons last_double_Cons) + apply(auto simp add: prod_assn_def split: prod.splits) + apply(auto dest!: mod_starD) + using Cons.IH + apply(auto) + using "2.IH"(2) + apply sep_auto + by (meson list.set_intros(1)) + qed + have **: "length ts = length rs" "split \ []" + using 1 by (auto dest!: mod_starD list_assn_len) + from 1 show ?case + apply(auto dest!: mod_starD) + apply(subst concat_append_butlast[symmetric]) + subgoal using ** by sep_auto + subgoal for h1 h2 h3 h4 h5 h6 h7 h8 + using *[of ts "butlast split" tsi' rs r "(h1,h2)"] "2.IH"(1)[of ti rs split "(h7,h8)"] + using ** + by sep_auto + done + qed +qed +declare last.simps[simp add] butlast.simps[simp add] + +lemma trunk_assn_leafs_len_aux: "trunk_assn k t a r z leafptrs = trunk_assn k t a r z leafptrs * \(length leafptrs = length (leaf_nodes t))" + by (meson trunk_assn_leafs_len_imp imp_imp_pure) + +declare last.simps[simp del] butlast.simps[simp del] +lemma bplustree_assn_leafs_not_empty_aux: "bplustree_assn_leafs k t a r z leafptrs = bplustree_assn_leafs k t a r z leafptrs * \(leafptrs \ [])" + apply(intro ent_iffI) + subgoal + apply(subst bplustree_assn_leafs_len_aux) + using leaf_nodes_not_empty + apply sep_auto + done + subgoal by sep_auto + done + +lemma trunk_assn_not_empty_aux: "trunk_assn k t a r z leafptrs = trunk_assn k t a r z leafptrs * \(leafptrs \ [])" + apply(intro ent_iffI) + subgoal + apply(subst trunk_assn_leafs_len_aux) + using leaf_nodes_not_empty + apply sep_auto + done + subgoal by sep_auto + done +declare last.simps[simp add] butlast.simps[simp add] + +declare last.simps[simp del] butlast.simps[simp del] +lemma bplustree_assn_leafs_hd: + "h \ bplustree_assn_leafs k t a r z leafptrs \ r = Some (hd leafptrs)" +proof(induction k t a r z leafptrs arbitrary: h rule: bplustree_assn_leafs.induct) + case (1 k xs a r z leafptrs) + then show ?case + by(clarsimp) +next + case (2 k ts t a r z leafptrs h) + from "2.prems" show ?case + apply(sep_auto dest!: mod_starD) + proof(goal_cases) + case (1 a b ti tsi' rs split ab bb ad bd ae be af bf) + have "length ts = length rs" + using 1 by (auto dest!: list_assn_len) + then show ?case + proof(cases ts) + case Nil + then have "length split = 1" "rs = []" + using "1"(4) \length ts = length rs\ by auto + then have *: "split = [last split]" + by (metis append_butlast_last_id list.distinct(1) list_decomp_1 list_se_match(4)) + then have "concat split = last split" + apply(subst *) + unfolding concat.simps + by simp + then show ?thesis + using 1 + using "2.IH"(1)[of ti rs split "(af,bf)"] + using \rs = []\ + by (auto simp add: last.simps) + next + case (Cons a list) + then obtain ra rss ss1 ss2 splits tss tsi's where *: + "rs = ra#rss" + "split = ss1 # ss2 # splits" + "tsi' = tss # tsi's" + by (metis (no_types, lifting) "1"(3) "1"(4) Suc_length_conv \length ts = length rs\) + obtain h1 h2 where first_subtree: "(h1, h2) \ bplustree_assn_leafs k (fst a) (the (fst tss)) r ra ss1" + using 1 + apply (auto simp add: butlast_double_Cons last_double_Cons * Cons) + apply (auto simp add: prod_assn_def split: prod.splits ) + apply(auto dest!: mod_starD) + done + then have "ss1 \ []" + using bplustree_assn_leafs_not_empty_aux[of k "(fst a)" "(the (fst tss))" r ra ss1] + by auto + then have "hd (concat split) = hd ss1" + by (simp add: "*"(2)) + then show ?thesis + using first_subtree + apply auto + by (metis "2.IH"(2) fst_conv list.set_intros(1) local.Cons) + qed + qed +qed +declare last.simps[simp add] butlast.simps[simp add] + +lemma bplustree_assn_leafs_hd_aux: + "bplustree_assn_leafs k t a r z leafptrs = bplustree_assn_leafs k t a r z leafptrs * \(r = Some (hd leafptrs))" + by (meson bplustree_assn_leafs_hd imp_imp_pure) + +declare last.simps[simp del] butlast.simps[simp del] +lemma trunk_assn_hd: + "h \ trunk_assn k t a r z leafptrs \ r = Some (hd leafptrs)" +proof(induction k t a r z leafptrs arbitrary: h rule: trunk_assn.induct) + case (1 k xs a r z leafptrs) + then show ?case + by(clarsimp) +next + case (2 k ts t a r z leafptrs h) + from "2.prems" show ?case + apply(sep_auto dest!: mod_starD) + proof(goal_cases) + case (1 a b ti tsi' rs split ab bb ad bd ae be af bf) + have "length ts = length rs" + using 1 by (auto dest!: list_assn_len) + then show ?case + proof(cases ts) + case Nil + then have "length split = 1" "rs = []" + using "1"(4) \length ts = length rs\ by auto + then have *: "split = [last split]" + by (metis append_butlast_last_id list.distinct(1) list_decomp_1 list_se_match(4)) + then have "concat split = last split" + apply(subst *) + unfolding concat.simps + by simp + then show ?thesis + using 1 + using "2.IH"(1)[of ti rs split "(af,bf)"] + using \rs = []\ + by (auto simp add: last.simps) + next + case (Cons a list) + then obtain ra rss ss1 ss2 splits tss tsi's where *: + "rs = ra#rss" + "split = ss1 # ss2 # splits" + "tsi' = tss # tsi's" + by (metis (no_types, lifting) "1"(3) "1"(4) Suc_length_conv \length ts = length rs\) + obtain h1 h2 where first_subtree: "(h1, h2) \ trunk_assn k (fst a) (the (fst tss)) r ra ss1" + using 1 + apply (auto simp add: butlast_double_Cons last_double_Cons * Cons) + apply (auto simp add: prod_assn_def split: prod.splits ) + apply(auto dest!: mod_starD) + done + then have "ss1 \ []" + using trunk_assn_not_empty_aux[of k "(fst a)" "(the (fst tss))" r ra ss1] + by auto + then have "hd (concat split) = hd ss1" + by (simp add: "*"(2)) + then show ?thesis + using first_subtree + apply auto + by (metis "2.IH"(2) fst_conv list.set_intros(1) local.Cons) + qed + qed +qed +declare last.simps[simp add] butlast.simps[simp add] + +lemma trunk_assn_hd_aux: + "trunk_assn k t a r z leafptrs = trunk_assn k t a r z leafptrs * \(r = Some (hd leafptrs))" + by (simp add: imp_imp_pure trunk_assn_hd) + +declare last.simps[simp del] butlast.simps[simp del] +lemma subleaf_at_head_of_concat_inner: "length tsi's = length rss \ + length rss = length tss \ + length tss = length splits \ +list_assn ((\t (ti, x, xa, y). trunk_assn k t (the ti) x xa y) \\<^sub>a R) tss + (zip (zip (subtrees tsi's) (zip (butlast (subleaf # rss)) (zip rss splits))) + (separators tsi's)) * + trunk_assn k t ti (last (subleaf # rss)) z ss += +list_assn ((\t (ti, x, xa, y). trunk_assn k t (the ti) x xa y) \\<^sub>a R) tss + (zip (zip (subtrees tsi's) (zip (butlast (subleaf # rss)) (zip rss splits))) + (separators tsi's)) * + trunk_assn k t ti (last (subleaf # rss)) z ss * \(Some (hd (concat splits@ss)) = subleaf)" + apply(cases splits) + subgoal + apply (sep_auto simp add: last.simps) + apply (metis (mono_tags, opaque_lifting) trunk_assn_hd_aux pure_assn_eq_conv) + done + subgoal + apply(cases tss; cases rss; cases tsi's) + apply simp_all + apply (sep_auto + simp add: butlast_double_Cons last_double_Cons) + apply(intro ent_iffI) + subgoal + apply(subst trunk_assn_hd_aux) + apply(subst trunk_assn_not_empty_aux) + apply sep_auto + done + subgoal by sep_auto + done + done + +lemma subleaf_at_head_of_concat_bplustree: "length tsi's = length rss \ + length rss = length tss \ + length tss = length splits \ +list_assn ((\t (ti, x, xa, y). bplustree_assn_leafs k t (the ti) x xa y) \\<^sub>a R) tss + (zip (zip (subtrees tsi's) (zip (butlast (subleaf # rss)) (zip rss splits))) + (separators tsi's)) * + bplustree_assn_leafs k t ti (last (subleaf # rss)) z ss += +list_assn ((\t (ti, x, xa, y). bplustree_assn_leafs k t (the ti) x xa y) \\<^sub>a R) tss + (zip (zip (subtrees tsi's) (zip (butlast (subleaf # rss)) (zip rss splits))) + (separators tsi's)) * + bplustree_assn_leafs k t ti (last (subleaf # rss)) z ss * \(Some (hd (concat splits@ss)) = subleaf)" + apply(cases splits) + subgoal + apply (sep_auto simp add: last.simps) + apply (metis (mono_tags, opaque_lifting) bplustree_assn_leafs_hd_aux pure_assn_eq_conv) + done + subgoal + apply(cases tss; cases rss; cases tsi's) + apply simp_all + apply (sep_auto + simp add: butlast_double_Cons last_double_Cons) + apply(intro ent_iffI) + subgoal + apply(subst bplustree_assn_leafs_hd_aux) + apply(subst bplustree_assn_leafs_not_empty_aux) + apply sep_auto + done + subgoal by sep_auto + done + done +declare last.simps[simp add] butlast.simps[simp add] + + +declare last.simps[simp del] butlast.simps[simp del] +lemma bplustree_leaf_nodes_sep: + "bplustree_assn_leafs k t ti r z lptrs = leaf_nodes_assn k (leaf_nodes t) r z lptrs * trunk_assn k t ti r z lptrs" +proof(induction arbitrary: r rule: bplustree_assn_leafs.induct) + case (1 k xs a r z) + then show ?case + apply(intro ent_iffI) + apply sep_auto+ + done +next + case (2 k ts t a r z lptrs ra) + show ?case + apply simp + apply(intro inst_same) + apply (clarsimp simp add: mult.left_assoc) + apply(intro pure_eq_pre) + apply(clarsimp) + proof(goal_cases) + case (1 tsia tsin ti tsi' rs split) + have *: " + length tsi's = length rss \ + length rss = length tss \ + length tss = length splits \ + set tsi's \ set tsi' \ + set rss \ set rs \ + set tss \ set ts \ + set splits \ set split \ + bplustree_assn_leafs k t ti (last (ra # rss)) z (last split)* + list_assn ((\t (ti, x, y, s). bplustree_assn_leafs k t (the ti) x y s) \\<^sub>a id_assn) tss + (zip (zip (subtrees tsi's) (zip (butlast (ra # rss)) (zip rss splits))) (separators tsi's)) = + leaf_nodes_assn k (concat (map (leaf_nodes \ fst) tss) @ leaf_nodes t) ra z (concat splits @ last split) * + list_assn ((\t (ti, x, y, s). trunk_assn k t (the ti) x y s) \\<^sub>a id_assn) tss + (zip (zip (subtrees tsi's) (zip (butlast (ra # rss)) (zip rss splits))) (separators tsi's)) * + trunk_assn k t ti (last (ra#rss)) z (last split)" + for rss tsi's tss splits + proof (induct arbitrary: ra rule: list_induct4) + case (Nil r) + then show ?case + apply(clarsimp) + using 2(1)[of ti r "[]" "split"] + apply (simp add: last.simps) + done + next + case (Cons subsepi tsi's subleaf rss subsep tss fsplit splits r) + show ?case + apply (sep_auto + simp add: butlast_double_Cons last_double_Cons) + apply(subst prod_assn_def)+ + apply(simp split!: prod.splits add: mult.left_assoc) + subgoal for sub sep +(* extract fact that length of leaf nodes of subleaf matches leaf_nodes_assn_split req *) + apply(subst bplustree_assn_leafs_len_aux[of k sub]) + apply(subst trunk_assn_leafs_len_aux[of k sub]) + apply sep_auto + apply(intro pure_eq_pre) +(* extract fact that the remaining list is not empty *) + apply(subst bplustree_assn_leafs_not_empty_aux[of k t]) + apply(subst trunk_assn_not_empty_aux[of k t]) + apply sep_auto + apply(intro pure_eq_pre) + supply R = leaf_nodes_assn_split[of "leaf_nodes sub" fsplit + "concat splits @ last split" "hd (concat splits @ last split)" "tl (concat splits @ last split)"] + thm R + apply(subst R) + subgoal by simp + subgoal by simp + (* show that r = hd fsplit *) + apply(subst bplustree_assn_leafs_hd_aux[of k sub]) + apply(subst trunk_assn_hd_aux[of k sub]) + apply sep_auto + apply(intro pure_eq_pre) +(* refactor multiplication s.t. we can apply the lemma about two mult. factors with an OTF lemma *) + supply R = subleaf_at_head_of_concat_inner[of tsi's rss tss splits k id_assn subleaf t ti z "last split"] + thm R + apply (subst_mod_mult_ac R) + subgoal using Cons by simp + subgoal using Cons by simp + subgoal using Cons by simp + apply(simp add: mult.left_assoc)? +(* refactor multiplication s.t. we can apply the lemma about two mult. factors with an OTF lemma *) + supply R=subleaf_at_head_of_concat_bplustree[of tsi's rss tss splits k id_assn subleaf t ti z "last split"] + thm R + apply (subst_mod_mult_ac R) + subgoal using Cons by simp + subgoal using Cons by simp + subgoal using Cons by simp + apply(simp add: mult.left_assoc)? + apply(intro pure_eq_pre) + proof(goal_cases) + case 1 + moreover have p: "set tsi's \ set tsi'" + "set rss \ set rs" + "set tss \ set ts" + "set splits \ set split" + using Cons.prems by auto + moreover have "(sub,sep) \ set ts" + using "1" Cons.prems(3) by force + moreover obtain temp1 temp2 where "((fst subsepi, (temp1:: 'a btnode ref option), subleaf, fsplit), (temp2::'a)) \ set [((fst subsepi, temp1, subleaf, fsplit), temp2)]" + by auto + ultimately show ?case + apply(inst_ex_assn subleaf) + using "Cons.hyps"(4)[of subleaf, OF p, simplified] + apply (auto simp add: algebra_simps) + using "2.IH"(2)[of subsep "((fst subsepi, temp1, subleaf, fsplit),temp2)" "[((fst subsepi, temp1, subleaf, fsplit),temp2)]" + "fst subsepi" "(temp1, subleaf, fsplit)" temp1 "(subleaf, fsplit)" subleaf fsplit r, simplified] + apply auto + using assn_times_assoc ent_refl by presburger + qed + done + qed + show ?case + apply(intro ent_iffI) + subgoal + apply(rule entails_preI) + using 1 + apply(auto dest!: mod_starD list_assn_len) + apply(subst_mod_mult_ac *[of tsi' rs ts "butlast split", simplified]) + subgoal by auto + subgoal by auto + subgoal by auto + subgoal by (meson in_set_butlastD subset_code(1)) + subgoal + apply(subgoal_tac "concat (butlast split) @ (last split) = concat split") + prefer 2 + subgoal + apply(subst concat_append_butlast) + apply auto + done + subgoal by sep_auto + done + done + subgoal + apply(rule entails_preI) + using 1 + apply(auto dest!: mod_starD list_assn_len) + apply(subgoal_tac "concat split = concat (butlast split) @ (last split)") + prefer 2 + subgoal + apply(subst concat_append_butlast) + apply auto + done + apply simp + apply(subst_mod_mult_ac *[of tsi' rs ts "butlast split", simplified, symmetric]) + subgoal by auto + subgoal by auto + subgoal by auto + subgoal by (meson in_set_butlastD subset_code(1)) + subgoal by sep_auto + done + done + qed + qed +declare last.simps[simp add] butlast.simps[simp add] + + +fun leaf_node:: "('a::heap) bplustree \ 'a list \ assn" where + "leaf_node (Leaf xs) xsi = \(xs = xsi)" | + "leaf_node _ _ = false" + +fun leafs_assn :: "('a::heap) pfarray list \ 'a btnode ref list \ 'a btnode ref option \ 'a btnode ref option \ assn" where + "leafs_assn (ln#lns) (r'#lptrs) (Some r) z = + (\\<^sub>A fwd. + r \\<^sub>r Btleaf ln fwd + * leafs_assn lns lptrs fwd z + * \(r' = r) + )" | + "leafs_assn [] [] r z = \(r = z)" | + "leafs_assn _ _ _ _ = false" + +lemma leafs_assn_aux_append: + "length xs = length xsi \ leafs_assn (xs@ys) (xsi@ysi) r z = (\\<^sub>Al. leafs_assn xs xsi r l * leafs_assn ys ysi l z)" + apply(induction xs xsi r z rule: leafs_assn.induct) + apply(sep_auto intro!: ent_iffI)+ + done + +abbreviation "leaf_lists \ \t. map leaves (leaf_nodes t)" + +lemma leaf_nodes_assn_flatten_help: + "length ts = length lptrs \ leaf_nodes_assn k ts r z lptrs = (\\<^sub>Aps. list_assn leaf_node ts (map leaves ts) * list_assn (is_pfa (2*k)) (map leaves ts) ps * leafs_assn ps lptrs r z)" +proof (induction ts lptrs arbitrary: r rule: list_induct2) + case Nil + then show ?case + apply(intro ent_iffI) + subgoal by sep_auto + subgoal by sep_auto + done +next + case (Cons a xs r' lptrs r) + then show ?case + proof(intro ent_iffI, goal_cases) + case 1 + show ?case + apply(cases r; cases a) + apply simp_all + find_theorems "\\<^sub>A_._ \\<^sub>A_" + apply(rule ent_ex_preI)+ + subgoal for aa x1 xsi fwd + apply (subst "Cons.IH"[of fwd]) + apply simp + apply(rule ent_ex_preI)+ + subgoal for ps + apply(inst_ex_assn "xsi#ps") + apply simp_all + apply(inst_ex_assn fwd) + apply (sep_auto) + done + done + done + next + case 2 + have *: "list_assn leaf_node xs (map leaves xs) * list_assn (is_pfa (2 * k)) (map leaves xs) ps' * leafs_assn ps' lptrs r'' z + \\<^sub>A leaf_nodes_assn k xs r'' z lptrs" + for ps' r'' + using assn_eq_split(1)[OF sym[OF "Cons.IH"[of r'']]] + ent_ex_inst[where Q="leaf_nodes_assn k xs r'' z lptrs" and y=ps'] + by blast + show ?case + apply(rule ent_ex_preI)+ + subgoal for ps + apply(cases ps; cases r; cases a) + apply simp_all + apply(rule ent_ex_preI)+ + subgoal for aa list aaa x1 fwd + apply(inst_ex_assn aa fwd) + apply sep_auto + using *[of list fwd] + by (smt (z3) assn_aci(9) assn_times_comm fr_refl) + done + done + qed +qed + +lemma leaf_nodes_assn_impl_length: "h \ leaf_nodes_assn k xs r z lptrs \ length xs = length lptrs" + apply(induction xs arbitrary: h r lptrs) + subgoal for h r lptrs + apply(cases r; cases lptrs) + apply sep_auto+ + done + subgoal for a xs h r lptrs + apply(cases r; cases lptrs; cases a) + apply (sep_auto dest: mod_starD)+ + done + done + +lemma leafs_assn_impl_length: "h \ leafs_assn xs lptrs r z \ length xs = length lptrs" + apply(induction xs arbitrary: h r lptrs) + subgoal for h r lptrs + apply(cases r; cases lptrs) + apply sep_auto+ + done + subgoal for a xs h r lptrs + apply(cases r; cases lptrs) + apply (sep_auto dest: mod_starD)+ + done + done + +lemma leaf_nodes_assn_flatten: + "leaf_nodes_assn k ts r z lptrs = (\\<^sub>Aps. list_assn leaf_node ts (map leaves ts) * list_assn (is_pfa (2*k)) (map leaves ts) ps * leafs_assn ps lptrs r z)" +proof(intro ent_iffI, goal_cases) + case 1 + then show ?case + apply(rule entails_preI) + apply (subst leaf_nodes_assn_flatten_help) + subgoal by (sep_auto dest!: mod_starD leaf_nodes_assn_impl_length) + subgoal by sep_auto + done +next + case 2 + then show ?case + apply(rule entails_preI) + apply (subst leaf_nodes_assn_flatten_help) + subgoal by (sep_auto dest!: mod_starD leafs_assn_impl_length list_assn_len) + subgoal by sep_auto + done +qed + + +subsection "Iterator" + + +partial_function (heap) first_leaf :: "('a::heap) btnode ref \ 'a btnode ref option Heap" + where + "first_leaf p = do { + node \ !p; + (case node of + Btleaf _ _ \ do { return (Some p) } | + Btnode tsi ti \ do { + s \ pfa_get tsi 0; + let (sub,sep) = s in do { + first_leaf (the sub) + } + } +)}" + +partial_function (heap) last_leaf :: "('a::heap) btnode ref \ 'a btnode ref option Heap" + where + "last_leaf p = do { + node \ !p; + (case node of + Btleaf _ z \ do { return z } | + Btnode tsi ti \ do { + last_leaf ti + } +)}" + +declare last.simps[simp del] butlast.simps[simp del] +lemma first_leaf_rule[sep_heap_rules]: + assumes "k > 0" "root_order k t" + shows " + first_leaf ti + <\u. bplustree_assn k t ti r z * \(u = r)>\<^sub>t" + using assms +proof(induction t arbitrary: ti z) + case (Leaf x) + then show ?case + apply(subst first_leaf.simps) + apply (sep_auto dest!: mod_starD) + done +next + case (Node ts t) + then obtain sub sep tts where Cons: "ts = (sub,sep)#tts" + apply(cases ts) by auto + then show ?case + apply(subst first_leaf.simps) + apply (sep_auto simp add: butlast.simps) + subgoal for tsia tsil ti tsi' rs subi sepi + apply(cases rs; cases tsi') + apply simp_all + subgoal for subleaf rrs _ ttsi' + supply R = "Node.IH"(1)[of "(sub,sep)" sub "(the subi)" subleaf] + thm R + using "Node.prems"(1) + apply (sep_auto heap add: R) + subgoal by (metis Node.prems(2) assms(1) bplustree.inject(2) bplustree.simps(4) Cons list.set_intros(1) order_impl_root_order root_order.elims(2) some_child_sub(1)) + apply (sep_auto eintros del: exI) + apply(inst_existentials tsia tsil ti "(subi, sepi) # ttsi'" "((subi, (r, subleaf)),sepi)#(zip (zip (subtrees ttsi') (zip (butlast (subleaf # rrs)) rrs)) (separators ttsi'))" "subleaf # rrs") + apply (sep_auto simp add: last.simps butlast.simps)+ + done + done + done +qed +declare last.simps[simp add] butlast.simps[simp add] + +declare last.simps[simp del] butlast.simps[simp del] +lemma last_leaf_rule[sep_heap_rules]: + assumes "k > 0" "root_order k t" + shows " + last_leaf ti + <\u. bplustree_assn k t ti r z * \(u = z)>\<^sub>t" + using assms +proof(induction t arbitrary: ti r) + case (Leaf x) + then show ?case + apply(subst last_leaf.simps) + apply (sep_auto dest!: mod_starD) + done +next + case (Node ts t) + show ?case + apply(subst last_leaf.simps) + supply R = "Node.IH"(2) + apply (sep_auto heap add: R) + subgoal using "Node.prems" by simp + subgoal by (metis Node.prems(2) assms(1) bplustree.inject(2) bplustree.simps(4) Cons list.set_intros(1) order_impl_root_order root_order.elims(2) some_child_sub(1)) + apply (sep_auto eintros del: exI) + subgoal for tsia tsil ti tsi' rs + apply(inst_existentials tsia tsil ti "tsi'" " (zip (zip (subtrees tsi') (zip (butlast (r # rs)) rs)) (separators tsi'))" rs) + apply (sep_auto simp add: last.simps butlast.simps)+ + done + done +qed +declare last.simps[simp add] butlast.simps[simp add] + + +definition tree_leaf_iter_init where +"tree_leaf_iter_init p = do { + r \ first_leaf (the p); + z \ last_leaf (the p); + return (r, z) +}" + +lemma tree_leaf_iter_init_rule_help: + assumes "k > 0" "root_order k t" + shows " + tree_leaf_iter_init (Some ti) + <\(u,v). bplustree_assn k t ti r z * \(u = r \ v = z)>\<^sub>t" + using assms + unfolding tree_leaf_iter_init_def + by (sep_auto) + +lemma tree_leaf_iter_init_rule: + assumes "k > 0" "root_order k t" + shows " + tree_leaf_iter_init (Some ti) + <\(u,v). \\<^sub>A lptrs. leaf_nodes_assn k (leaf_nodes t) r z lptrs * trunk_assn k t ti r z lptrs * \(u = r \ v = z)>\<^sub>t" + using assms + apply(vcg heap add: tree_leaf_iter_init_rule_help) + by (simp add: bplustree_extract_leafs bplustree_leaf_nodes_sep) + +lemma tree_leaf_iter_init_rule_alt: + assumes "k > 0" "root_order k t" + shows " + tree_leaf_iter_init (Some ti) + <\(u,v). \\<^sub>A lptrs ps. list_assn leaf_node (leaf_nodes t) (map leaves (leaf_nodes t)) * list_assn (is_pfa (2*k)) (map leaves (leaf_nodes t)) ps * leafs_assn ps lptrs r z * trunk_assn k t ti r z lptrs * \(u = r \ v = z)>\<^sub>t" + using assms + apply(vcg heap add: tree_leaf_iter_init_rule) + apply(sep_auto simp add: leaf_nodes_assn_flatten) + done + +(* TODO derive version that yields leaf_iter_assn *) + + +definition leaf_iter_next where +"leaf_iter_next = (\(r,z). do { + p \ !(the r); + return (vals p, (fwd p, z)) +})" + +lemma leaf_iter_next_rule_help: + " + leaf_iter_next (r,z) + <\(p,(n,z')). leafs_assn [x] [l] r n * leafs_assn xs lptrs n z' * \(p = x) * \(z=z')>" + apply(subst leaf_iter_next_def) + apply(cases r; cases x) + apply(sep_auto)+ + done + +definition leaf_iter_assn where "leaf_iter_assn xs lptrs r xs2 = (\(n,z). + (\\<^sub>Axs1 lptrs1 lptrs2. \(xs = xs1@xs2) * \(lptrs = lptrs1@lptrs2) * leafs_assn xs1 lptrs1 r n * leafs_assn xs2 lptrs2 n z * \(z=None)))" + +lemma leaf_nodes_assn_imp_iter_assn: + "leafs_assn xs lptrs r None \\<^sub>A leaf_iter_assn xs lptrs r xs (r,None)" + unfolding leaf_iter_assn_def + by sep_auto + +definition leaf_iter_init where +"leaf_iter_init p = do { + return (p, None) +}" + +lemma leaf_iter_init_rule: + shows " + leaf_iter_init r + <\u. leaf_iter_assn xs lptrs r xs u>" + unfolding leaf_iter_init_def + using leaf_nodes_assn_imp_iter_assn + by (sep_auto) + + +lemma leaf_iter_next_rule: " +leaf_iter_next it +<\(p, it'). leaf_iter_assn xs lptrs r xs2 it' * \(p = x)>" + unfolding leaf_iter_assn_def + apply(clarsimp split: prod.splits) + apply(intro norm_pre_ex_rule) + subgoal for n z xs1 lptrs1 lptrs2 + apply(rule hoare_triple_preI) + apply(clarsimp dest!: mod_starD leafs_assn_impl_length) + apply(cases lptrs2; clarsimp) + subgoal for l llptrs2 + apply (sep_auto heap add: leaf_iter_next_rule_help eintros del: exI) + apply(inst_existentials "xs1@[x]" "lptrs1@[l]" llptrs2) + subgoal by sep_auto + subgoal by (sep_auto simp add: leafs_assn_aux_append) + done + done + done + +definition leaf_iter_has_next where +"leaf_iter_has_next = (\(r,z). return (r \ z))" + +(* TODO this so far only works for the whole tree (z = None) +for subintervals, we would need to show that the list of pointers is indeed distinct, +hence r = z can only occur at the end *) +lemma leaf_iter_has_next_rule: + " leaf_iter_has_next it <\u. leaf_iter_assn xs lptrs r xs2 it * \(u \ xs2 \ [])>" + unfolding leaf_iter_has_next_def leaf_iter_assn_def + apply(cases it; simp) + apply(intro norm_pre_ex_rule) + apply(rule hoare_triple_preI) + apply(clarsimp dest!: mod_starD leafs_assn_impl_length) + apply(sep_auto split!: prod.splits dest!: mod_starD) + by (metis leafs_assn.simps list.exhaust mod_false option.exhaust) + +(* copied from peter lammichs lseg_prec2, don't ask what happens in the induction step +(or ask peter lammich) *) +declare mult.left_commute[simp add] +lemma leafs_assn_prec2: + "\l l'. (h\ + (leafs_assn l lptrs p None * F1) \\<^sub>A (leafs_assn l' lptrs p None * F2)) + \ l=l'" + apply (intro allI) + subgoal for l l' + proof (induct l arbitrary: lptrs p l' F1 F2) + case Nil thus ?case + apply (cases l') + apply simp + apply (cases p) + apply (auto simp add: mod_and_dist dest!: mod_starD leafs_assn_impl_length) + done + next + case (Cons y l) + from Cons.prems show ?case + apply (cases p) + apply simp + apply (cases l') + subgoal by (auto simp add: mod_and_dist dest!: mod_starD leafs_assn_impl_length)[] + apply(cases lptrs) + subgoal by (auto simp add: mod_and_dist dest!: mod_starD leafs_assn_impl_length)[] + apply (rule) + apply clarsimp + apply(subgoal_tac "y = (aa, b) \ fwd = fwda", simp) + using Cons.hyps apply (erule prec_frame') + apply frame_inference + apply frame_inference + apply (drule_tac p=a in prec_frame[OF sngr_prec]) + apply frame_inference + apply frame_inference + apply simp + done + qed + done +declare mult.left_commute[simp del] + +interpretation leaf_node_it: imp_list_iterate + "\x y. leafs_assn x lptrs y None" + "\x y. leaf_iter_assn x lptrs y" + leaf_iter_init + leaf_iter_has_next + leaf_iter_next + apply(unfold_locales) + subgoal + by (simp add: leafs_assn_prec2 precise_def) + subgoal for l p + by (sep_auto heap add: leaf_iter_init_rule) + subgoal for l' l p it + thm leaf_iter_next_rule + apply(cases l'; cases it) + by (sep_auto heap add: leaf_iter_next_rule)+ + subgoal for l p l' it' + thm leaf_iter_has_next_rule + apply(cases it') + apply(rule hoare_triple_preI) + apply(sep_auto heap add: leaf_iter_has_next_rule) + done + subgoal for l p l' it + unfolding leaf_iter_assn_def + apply(cases it) + apply simp_all + apply(intro ent_ex_preI) + apply(rule entails_preI) + apply(clarsimp dest!: mod_starD leafs_assn_impl_length) + by (sep_auto simp add: leafs_assn_aux_append) + done + +global_interpretation leaf_values_iter: flatten_iter + "\x y. leafs_assn x lptrs y None" "\x y. leaf_iter_assn x lptrs y" + leaf_iter_init leaf_iter_has_next leaf_iter_next + "is_pfa (2*k)" "pfa_is_it (2*k)" pfa_it_init pfa_it_has_next pfa_it_next + defines leaf_values_adjust = leaf_values_iter.flatten_it_adjust + and leaf_values_init = leaf_values_iter.flatten_it_init + and leaf_values_next = leaf_values_iter.flatten_it_next + and leaf_values_has_next = leaf_values_iter.flatten_it_has_next + by (unfold_locales) + +thm leaf_values_iter.is_flatten_list.simps +thm leaf_values_iter.is_flatten_it.simps +thm leaf_values_init_def +thm leaf_values_iter.flatten_it_init_def +print_theorems + +fun bplustree_iter_init :: "('a::heap) btnode ref \ _" where + "bplustree_iter_init ti = do { + rz \ tree_leaf_iter_init (Some ti); + it \ leaf_values_init (fst rz); + return it +}" + + +lemma leaf_nodes_imp_flatten_list: + "leaf_nodes_assn k ts r None lptrs \\<^sub>A + list_assn leaf_node ts (map leaves ts) * + leaf_values_iter.is_flatten_list lptrs k (map leaves ts) (concat (map leaves ts)) r" + apply(simp add: leaf_nodes_assn_flatten) + apply(intro ent_ex_preI) + subgoal for ps + apply(inst_ex_assn ps "map leaves ts") + apply sep_auto + done + done + +lemma leaf_nodes_imp_flatten_list_back: + "list_assn leaf_node ts (map leaves ts) * +leaf_values_iter.is_flatten_list lptrs k (map leaves ts) (concat (map leaves ts)) r \\<^sub>A + leaf_nodes_assn k ts r None lptrs" + apply(simp add: leaf_nodes_assn_flatten) + apply(intro ent_ex_preI) + subgoal for ps + apply(inst_ex_assn ps "map leaves ts") + apply sep_auto + done + done + +lemma leaf_nodes_flatten_list: "leaf_nodes_assn k ts r None lptrs = + list_assn leaf_node ts (map leaves ts) * + leaf_values_iter.is_flatten_list lptrs k (map leaves ts) (concat (map leaves ts)) r" + apply(intro ent_iffI) + subgoal by (rule leaf_nodes_imp_flatten_list) + subgoal by (rule leaf_nodes_imp_flatten_list_back) + done + +definition "bplustree_iter_list k t ti r = (\\<^sub>A lptrs. + leaf_values_iter.is_flatten_list lptrs k (map leaves (leaf_nodes t)) (leaves t) r * + list_assn leaf_node (leaf_nodes t) (map leaves (leaf_nodes t)) * + trunk_assn k t ti r None lptrs)" + +lemma bplustree_iff_leaf_view: "bplustree_assn k t ti r None = bplustree_iter_list k t ti r" + unfolding bplustree_iter_list_def + apply(simp add: + bplustree_extract_leafs + bplustree_leaf_nodes_sep + leaf_nodes_flatten_list + concat_leaf_nodes_leaves + ) + apply (auto simp add: algebra_simps) + done + +definition "bplustree_iter k t ti r vs it = (\\<^sub>A fringe. + leaf_values_iter.is_flatten_it fringe k (map leaves (leaf_nodes t)) (leaves t) r vs it * + list_assn leaf_node (leaf_nodes t) (map leaves (leaf_nodes t)) * + trunk_assn k t ti r None fringe)" + +(* Now finally, we can hide away that we extracted anything +and just provide the user with some pretty definitions *) + +lemma bplustree_iter_init_rule: + assumes "k > 0" "root_order k t" + shows " +bplustree_iter_init ti +<\it. bplustree_iter k t ti r (leaves t) it>\<^sub>t" + unfolding bplustree_iter_init.simps + unfolding bplustree_iter_def + using assms + apply (sep_auto heap add: tree_leaf_iter_init_rule) + apply(subst leaf_nodes_flatten_list) + apply(vcg heap add: leaf_values_iter.flatten_it_init_rule) + subgoal for lptrs + apply(inst_ex_assn lptrs) + apply(sep_auto simp add: concat_leaf_nodes_leaves) + done + done + +(* using is_flatten_it we can now iterate through elements in the leafs *) + +abbreviation "bplustree_iter_next \ leaf_values_next" + +lemma bplustree_iter_next_rule: "vs \ [] \ + + bplustree_iter_next it + <\(a, it'). bplustree_iter k t ti r (tl vs) it' * \ (a = hd vs)>\<^sub>t" + unfolding bplustree_iter_def + apply(sep_auto heap add: leaf_values_iter.flatten_it_next_rule) + done + +abbreviation "bplustree_iter_has_next \ leaf_values_has_next" + +lemma bplustree_iter_has_next_rule: " + + bplustree_iter_has_next it + <\r'. bplustree_iter k t ti r vs it * \ (r' = (vs \ []))>\<^sub>t" + unfolding bplustree_iter_def + apply(sep_auto heap add: leaf_values_iter.flatten_it_has_next_rule) + done + +lemma bplustree_iter_quit: +"bplustree_iter k t ti r vs it \\<^sub>A bplustree_assn k t ti r None * true" + unfolding bplustree_iter_def + apply(rule ent_ex_preI) + subgoal for lptrs + apply(rule ent_frame_fwd[OF leaf_values_iter.flatten_quit_iteration, where F="list_assn leaf_node (leaf_nodes t) (leaf_lists t) * + trunk_assn k t ti r None lptrs"]) + apply solve_entails + apply(simp add: + bplustree_extract_leafs + bplustree_leaf_nodes_sep + leaf_nodes_flatten_list + concat_leaf_nodes_leaves + ) + apply(rule ent_ex_preI) + subgoal for lsi' + apply(inst_ex_assn lptrs lsi') + apply sep_auto + done + done + done + +declare first_leaf.simps[code] +declare last_leaf.simps[code] +(* declare leaf_values_iter.flatten_it_adjust.simps[code] *) +(* Code exports can be found with in ImpSplitCE *) +end \ No newline at end of file diff --git a/thys/BTree/BPlusTree_Iter_OneWay.thy b/thys/BTree/BPlusTree_Iter_OneWay.thy new file mode 100644 --- /dev/null +++ b/thys/BTree/BPlusTree_Iter_OneWay.thy @@ -0,0 +1,679 @@ +theory BPlusTree_Iter_OneWay + imports + BPlusTree_Imp + "HOL-Real_Asymp.Inst_Existentials" + "Separation_Logic_Imperative_HOL.Imp_List_Spec" + Flatten_Iter + Partially_Filled_Array_Iter +begin + + +fun leaf_nodes_assn :: "nat \ ('a::heap) bplustree list \ 'a btnode ref option \ 'a btnode ref option \ assn" where + "leaf_nodes_assn k ((Leaf xs)#lns) (Some r) z = + (\\<^sub>A xsi fwd. + r \\<^sub>r Btleaf xsi fwd + * is_pfa (2*k) xs xsi + * leaf_nodes_assn k lns fwd z + )" | + "leaf_nodes_assn k [] r z = \(r = z)" | + "leaf_nodes_assn _ _ _ _ = false" + + +fun inner_nodes_assn :: "nat \ ('a::heap) bplustree \ 'a btnode ref \ 'a btnode ref option \ 'a btnode ref option \ assn" where + "inner_nodes_assn k (Leaf xs) a r z = \(r = Some a)" | + "inner_nodes_assn k (Node ts t) a r z = + (\\<^sub>A tsi ti tsi' tsi'' rs. + a \\<^sub>r Btnode tsi ti + * inner_nodes_assn k t ti (last (r#rs)) (last (rs@[z])) + * is_pfa (2*k) tsi' tsi + * \(length tsi' = length rs) + * \(tsi'' = zip (zip (map fst tsi') (zip (butlast (r#rs)) (butlast (rs@[z])))) (map snd tsi')) + * list_assn ((\ t (ti,r',z'). inner_nodes_assn k t (the ti) r' z') \\<^sub>a id_assn) ts tsi'' + )" + + +lemma leaf_nodes_assn_aux_append: + "leaf_nodes_assn k (xs@ys) r z = (\\<^sub>Al. leaf_nodes_assn k xs r l * leaf_nodes_assn k ys l z)" + apply(induction k xs r z rule: leaf_nodes_assn.induct) + apply(sep_auto intro!: ent_iffI)+ + done + + + +declare last.simps[simp del] butlast.simps[simp del] +declare mult.left_assoc[simp add] +lemma bplustree_leaf_nodes_help: + "bplustree_assn k t ti r z \\<^sub>A leaf_nodes_assn k (leaf_nodes t) r z * inner_nodes_assn k t ti r z" +proof(induction arbitrary: r rule: bplustree_assn.induct) + case (1 k xs a r z) + then show ?case + by (sep_auto) +next + case (2 k ts t a r z ra) + show ?case + apply(auto) + apply(rule ent_ex_preI)+ + proof (goal_cases) + case (1 tsi ti tsi' tsi'' rs) + have *: " + length tsi's = length rss \ + length rss = length tss \ + set tsi's \ set tsi' \ + set rss \ set rs \ + set tss \ set ts \ + bplustree_assn k t ti (last (ra # rss)) z * + blist_assn k tss + (zip (zip (subtrees tsi's) (zip (butlast (ra # rss)) rss)) (separators tsi's)) \\<^sub>A + leaf_nodes_assn k (concat (map (leaf_nodes \ fst) tss) @ leaf_nodes t) ra z * + inner_nodes_assn k t ti (last (ra#rss)) z * + list_assn ((\ t (ti,r',z'). inner_nodes_assn k t (the ti) r' z') \\<^sub>a id_assn) tss + (zip (zip (subtrees tsi's) (zip (butlast (ra # rss)) rss)) (separators tsi's)) +" + for rss tsi's tss + proof (induct arbitrary: ra rule: list_induct3) + case (Nil r) + then show ?case + apply sep_auto + using 2(1)[of ti r "[]"] + apply (simp add: last.simps butlast.simps) + done + next + case (Cons subsepi tsi's subleaf rss subsep tss r) + show ?case + apply (sep_auto + simp add: butlast_double_Cons last_double_Cons) + apply(subst prod_assn_def) + apply(simp split!: prod.splits add: mult.left_assoc) + apply(subst leaf_nodes_assn_aux_append) + apply simp + apply(inst_ex_assn subleaf) + proof (goal_cases) + case (1 sub sep) + have "(sub,sep) \ set ts" + using "1" Cons.prems(3) by force + moreover have "set tsi's \ set tsi' \ set rss \ set rs \ set tss \ set ts" + by (meson Cons.prems set_subset_Cons subset_trans) + moreover obtain temp1 temp2 where "((fst subsepi, (temp1:: 'a btnode ref option), subleaf), (temp2::'a)) \ set [((fst subsepi, temp1, subleaf), temp2)]" + by auto + ultimately show ?case + using + Cons(3)[of subleaf] + "2.IH"(2)[of "(sub,sep)" + "((fst subsepi, (temp1, subleaf)),temp2)" "[((fst subsepi, (temp1, subleaf)),temp2)]" + "fst subsepi" "(temp1, subleaf)" temp1 subleaf r] + apply auto + thm mult.commute + thm star_aci + apply(subst mult.commute) + thm mult.commute[where b="inner_nodes_assn k sub (the (fst subsepi)) r subleaf"] + apply(subst mult.commute[where b="inner_nodes_assn k sub (the (fst subsepi)) r subleaf"]) + find_theorems "_ * _ = _ * _" + apply(simp) + thm ent_star_mono + supply R=ent_star_mono[where +P="bplustree_assn k sub (the (fst subsepi)) r subleaf" and P'="inner_nodes_assn k sub (the (fst subsepi)) r subleaf * + leaf_nodes_assn k (leaf_nodes sub) r subleaf" +and Q="bplustree_assn k t ti (last (subleaf # rss)) z * + id_assn sep (snd subsepi) * + blist_assn k tss + (zip (zip (subtrees tsi's) (zip (butlast (subleaf # rss)) rss)) (separators tsi's))" +and Q'="leaf_nodes_assn k (concat (map (\a. leaf_nodes (fst a)) tss) @ leaf_nodes t) subleaf + z * + inner_nodes_assn k t ti (last (subleaf # rss)) z * + id_assn sep (snd subsepi) * + list_assn ((\t (ti, x, y). inner_nodes_assn k t (the ti) x y) \\<^sub>a id_assn) tss + (zip (zip (subtrees tsi's) (zip (butlast (subleaf # rss)) rss)) (separators tsi's))" + ,simplified] + thm R + apply(rule R) + subgoal + apply(subst mult.commute) + by simp + subgoal + thm mult.commute + apply(subst mult.commute[where b="id_assn _ _"], simp)+ + find_theorems "_ * _ = _* _" + apply(subst mult.commute) + supply R = ent_star_mono[where + P="id_assn sep (snd subsepi)" and P'="id_assn sep (snd subsepi)" +and Q="bplustree_assn k t ti (last (subleaf # rss)) z * + blist_assn k tss + (zip (zip (subtrees tsi's) (zip (butlast (subleaf # rss)) rss)) + (separators tsi's))" and +Q'="leaf_nodes_assn k (concat (map (\a. leaf_nodes (fst a)) tss) @ leaf_nodes t) subleaf + z * + inner_nodes_assn k t ti (last (subleaf # rss)) z * + list_assn ((\t (ti, x, y). inner_nodes_assn k t (the ti) x y) \\<^sub>a id_assn) tss + (zip (zip (subtrees tsi's) (zip (butlast (subleaf # rss)) rss)) + (separators tsi's))" +, simplified] + thm R + apply(rule R) + apply simp + done + done + qed + qed + show ?case + apply(rule entails_preI) + using 1 apply (auto dest!: mod_starD list_assn_len) + using *[of tsi' rs ts, simplified] + apply(inst_ex_assn tsi ti tsi' tsi'' rs) + by (smt (z3) assn_aci(10) assn_times_comm fr_refl mult.right_neutral pure_true) + qed +qed +declare last.simps[simp add] butlast.simps[simp add] +declare mult.left_assoc[simp del] + +lemma bplustree_leaf_nodes: + "bplustree_assn k t ti r z \\<^sub>A leaf_nodes_assn k (leaf_nodes t) r z * inner_nodes_assn k t ti r z" + using bplustree_leaf_nodes_help[of k t ti r z] by simp + +fun leaf_node:: "('a::heap) bplustree \ 'a list \ assn" where + "leaf_node (Leaf xs) xsi = \(xs = xsi)" | + "leaf_node _ _ = false" + +fun leafs_assn :: "('a::heap) pfarray list \ 'a btnode ref option \ 'a btnode ref option \ assn" where + "leafs_assn (ln#lns) (Some r) z = + (\\<^sub>A fwd. + r \\<^sub>r Btleaf ln fwd + * leafs_assn lns fwd z + )" | + "leafs_assn [] r z = \(r = z)" | + "leafs_assn _ _ _ = false" + +lemma leafs_assn_aux_append: + "leafs_assn (xs@ys) r z = (\\<^sub>Al. leafs_assn xs r l * leafs_assn ys l z)" + apply(induction xs r z rule: leafs_assn.induct) + apply(sep_auto intro!: ent_iffI)+ + done + +lemma leaf_nodes_assn_split: + "leaf_nodes_assn k ts r z = (\\<^sub>Aps. list_assn leaf_node ts (map bplustree.vals ts) * list_assn (is_pfa (2*k)) (map bplustree.vals ts) ps * leafs_assn ps r z)" +proof (induction ts arbitrary: r) + case Nil + then show ?case + apply(intro ent_iffI) + subgoal by sep_auto + subgoal by sep_auto + done +next + case (Cons a xs) + then show ?case + proof(intro ent_iffI, goal_cases) + case 1 + show ?case + apply(cases r; cases a) + apply simp_all + find_theorems "\\<^sub>A_._ \\<^sub>A_" + apply(rule ent_ex_preI)+ + subgoal for aa x1 xsi fwd + apply (subst "Cons.IH"[of fwd]) + apply simp + apply(rule ent_ex_preI)+ + subgoal for ps + apply(inst_ex_assn "xsi#ps") + apply simp_all + apply(inst_ex_assn fwd) + apply (sep_auto) + done + done + done + next + case 2 + have *: "list_assn leaf_node xs (map bplustree.vals xs) * list_assn (is_pfa (2 * k)) (map bplustree.vals xs) ps' * leafs_assn ps' r' z + \\<^sub>A leaf_nodes_assn k xs r' z" + for ps' r' + using assn_eq_split(1)[OF sym[OF "Cons.IH"[of r']]] + ent_ex_inst[where Q="leaf_nodes_assn k xs r' z" and y=ps'] + by blast + show ?case + apply(rule ent_ex_preI)+ + subgoal for ps + apply(cases ps; cases r; cases a) + apply simp_all + apply(rule ent_ex_preI)+ + subgoal for aa list aaa x1 fwd + apply(inst_ex_assn aa fwd) + apply sep_auto + using *[of list fwd] + by (smt (z3) assn_aci(9) assn_times_comm fr_refl) + done + done + qed +qed + +lemma inst_same: "(\x. P x = Q x) \ (\\<^sub>A x. P x) = (\\<^sub>A x. Q x)" + by simp + +lemma inst_same2: "(\x. P = Q x) \ P = (\\<^sub>A x. Q x)" + by simp + +lemma pure_eq_pre: "(P \ Q = R) \ (Q * \P = R * \P)" + by fastforce + +lemma bplustree_leaf_nodes_sep: + "leaf_nodes_assn k (leaf_nodes t) r z * (leaf_nodes_assn k (leaf_nodes t) r z -* bplustree_assn k t ti r z) \\<^sub>A bplustree_assn k t ti r z" + by (simp add: ent_mp) + +declare last.simps[simp del] butlast.simps[simp del] +lemma bplustree_leaf_nodes_sep: + "bplustree_assn k t ti r z = leaf_nodes_assn k (leaf_nodes t) r z * (leaf_nodes_assn k (leaf_nodes t) r z -* bplustree_assn k t ti r z)" + oops + +(* this doesn't hold, we need to know more about the remaining list, +specifically because inner_nodes_assn doesn't say anything about next pointers *) +lemma leaf_nodes_assn_split_spec: "leaf_nodes_assn k + (leaf_nodes x @ ys) r z * + inner_nodes_assn k x a r m = + leaf_nodes_assn k (leaf_nodes x) r m * leaf_nodes_assn k ys m z * + inner_nodes_assn k x a r m" + oops + + + +(* TODO find a statement that cleanly separates the heap *) +declare last.simps[simp del] butlast.simps[simp del] +lemma bplustree_leaf_nodes_sep: + "bplustree_assn k t ti r z = leaf_nodes_assn k (leaf_nodes t) r z * inner_nodes_assn k t ti r z" + oops +(* +proof(induction arbitrary: r rule: bplustree_assn.induct) + case (1 k xs a r z) + then show ?case + apply(intro ent_iffI) + apply sep_auto+ + done +next + case (2 k ts t a r z ra) + show ?case + apply simp + apply(rule inst_same)+ + apply(rule pure_eq_pre) + proof(goal_cases) + case (1 tsi ti tsi' tsi'' rs) + have *: " + length tsi's = length rss \ + length rss = length tss \ + set tsi's \ set tsi' \ + set rss \ set rs \ + set tss \ set ts \ + bplustree_assn k t ti (last (ra # rss)) z * + blist_assn k tss + (zip (zip (subtrees tsi's) (zip (butlast (ra # rss)) rss)) (separators tsi's)) = + leaf_nodes_assn k (concat (map (leaf_nodes \ fst) tss) @ leaf_nodes t) ra z * + list_assn ((\t (ti, x, y). inner_nodes_assn k t (the ti) x y) \\<^sub>a id_assn) tss + (zip (zip (subtrees tsi's) (zip (butlast (ra # rss)) rss)) (separators tsi's)) * + inner_nodes_assn k t ti (last (ra#rss)) z" + for rss tsi's tss + proof (induct arbitrary: ra rule: list_induct3) + case (Nil r) + then show ?case + apply sep_auto + using 2(1)[of ti r] + apply (simp add: last.simps) + done + next + case (Cons subsepi tsi's subleaf rss subsep tss r) + show ?case + apply (sep_auto + simp add: butlast_double_Cons last_double_Cons) + apply(subst prod_assn_def) + apply(simp split!: prod.splits add: mult.left_assoc) + (*apply(subst leaf_nodes_assn_split_spec)*) + proof(goal_cases) + case (1 sub sep) + moreover have p: "set tsi's \ set tsi'" + "set rss \ set rs" + "set tss \ set ts" + using Cons.prems by auto + moreover have "(sub,sep) \ set ts" + using "1" Cons.prems(3) by force + moreover obtain temp1 temp2 where "((fst subsepi, (temp1:: 'a btnode ref option), subleaf), (temp2::'a)) \ set [((fst subsepi, temp1, subleaf), temp2)]" + by auto + ultimately show ?case + apply(inst_ex_assn subleaf) + using "Cons.hyps"(3)[of subleaf, OF p] + apply (auto simp add: algebra_simps) + using "2.IH"(2)[of subsep "((fst subsepi, (temp1, subleaf)),temp2)" "[((fst subsepi, (temp1, subleaf)),temp2)]" + "fst subsepi" "(temp1, subleaf)" temp1 subleaf r] + apply auto + using assn_times_assoc ent_refl by presburger + qed + qed + show ?case + apply(intro ent_iffI) + subgoal + apply(rule entails_preI) + using 1 + apply(auto dest!: mod_starD list_assn_len) + using *[of tsi' rs ts, simplified] + apply (smt (z3) assn_aci(10) assn_times_comm entails_def) + done + subgoal + apply(rule entails_preI) + using 1 + apply(auto dest!: mod_starD list_assn_len) + using *[of tsi' rs ts, simplified] + apply (smt (z3) assn_aci(10) assn_times_comm entails_def) + done + done + qed + qed +declare last.simps[simp add] butlast.simps[simp add] +*) + +subsection "Iterator" + +partial_function (heap) first_leaf :: "('a::heap) btnode ref \ 'a btnode ref option Heap" + where + "first_leaf p = do { + node \ !p; + (case node of + Btleaf _ _ \ do { return (Some p) } | + Btnode tsi ti \ do { + s \ pfa_get tsi 0; + let (sub,sep) = s in do { + first_leaf (the sub) + } + } +)}" + +partial_function (heap) last_leaf :: "('a::heap) btnode ref \ 'a btnode ref option Heap" + where + "last_leaf p = do { + node \ !p; + (case node of + Btleaf _ z \ do { return z } | + Btnode tsi ti \ do { + last_leaf ti + } +)}" + +declare last.simps[simp del] butlast.simps[simp del] +lemma first_leaf_rule[sep_heap_rules]: + assumes "k > 0" "root_order k t" + shows " + first_leaf ti + <\u. bplustree_assn k t ti r z * \(u = r)>\<^sub>t" + using assms +proof(induction t arbitrary: ti z) + case (Leaf x) + then show ?case + apply(subst first_leaf.simps) + apply (sep_auto dest!: mod_starD) + done +next + case (Node ts t) + then obtain sub sep tts where Cons: "ts = (sub,sep)#tts" + apply(cases ts) by auto + then show ?case + apply(subst first_leaf.simps) + apply (sep_auto simp add: butlast.simps) + subgoal for tsia tsil ti tsi' rs subi sepi + apply(cases rs; cases tsi') + apply simp_all + subgoal for subleaf rrs _ ttsi' + supply R = "Node.IH"(1)[of "(sub,sep)" sub "(the subi)" subleaf] + thm R + using "Node.prems"(1) + apply (sep_auto heap add: R) + subgoal by (metis Node.prems(2) assms(1) bplustree.inject(2) bplustree.simps(4) Cons list.set_intros(1) order_impl_root_order root_order.elims(2) some_child_sub(1)) + apply (sep_auto eintros del: exI) + apply(inst_existentials tsia tsil ti "(subi, sepi) # ttsi'" "((subi, (r, subleaf)),sepi)#(zip (zip (subtrees ttsi') (zip (butlast (subleaf # rrs)) rrs)) (separators ttsi'))" "subleaf # rrs") + apply (sep_auto simp add: last.simps butlast.simps)+ + done + done + done +qed +declare last.simps[simp add] butlast.simps[simp add] + +declare last.simps[simp del] butlast.simps[simp del] +lemma last_leaf_rule[sep_heap_rules]: + assumes "k > 0" "root_order k t" + shows " + last_leaf ti + <\u. bplustree_assn k t ti r z * \(u = z)>\<^sub>t" + using assms +proof(induction t arbitrary: ti r) + case (Leaf x) + then show ?case + apply(subst last_leaf.simps) + apply (sep_auto dest!: mod_starD) + done +next + case (Node ts t) + show ?case + apply(subst last_leaf.simps) + supply R = "Node.IH"(2) + apply (sep_auto heap add: R) + subgoal using "Node.prems" by simp + subgoal by (metis Node.prems(2) assms(1) bplustree.inject(2) bplustree.simps(4) Cons list.set_intros(1) order_impl_root_order root_order.elims(2) some_child_sub(1)) + apply (sep_auto eintros del: exI) + subgoal for tsia tsil ti tsi' rs + apply(inst_existentials tsia tsil ti "tsi'" " (zip (zip (subtrees tsi') (zip (butlast (r # rs)) rs)) (separators tsi'))" rs) + apply (sep_auto simp add: last.simps butlast.simps)+ + done + done +qed +declare last.simps[simp add] butlast.simps[simp add] + + +definition tree_leaf_iter_init where +"tree_leaf_iter_init p = do { + r \ first_leaf (the p); + z \ last_leaf (the p); + return (r, z) +}" + +lemma tree_leaf_iter_init_rule: + assumes "k > 0" "root_order k t" + shows " + tree_leaf_iter_init (Some ti) + <\(u,v). leaf_nodes_assn k (leaf_nodes t) u v * inner_nodes_assn k t ti r z * \(u = r \ v = z)>\<^sub>t" + using assms + using bplustree_leaf_nodes_help[of k t ti r z] + unfolding tree_leaf_iter_init_def + apply (sep_auto) + using ent_star_mono ent_true by blast + + +definition leaf_iter_next where +"leaf_iter_next = (\(r,z). do { + p \ !(the r); + return (vals p, (fwd p, z)) +})" + +lemma leaf_iter_next_rule_help: + " + leaf_iter_next (r,z) + <\(p,(n,z')). leafs_assn [x] r n * leafs_assn xs n z' * \(p = x) * \(z=z')>" + apply(subst leaf_iter_next_def) + apply(cases r; cases x) + apply(sep_auto)+ + done + +definition leaf_iter_assn where "leaf_iter_assn xs r xs2 = (\(n,z). + (\\<^sub>Axs1. \(xs = xs1@xs2) * leafs_assn xs1 r n * leafs_assn xs2 n z * \(z=None)))" + +lemma leaf_nodes_assn_imp_iter_assn: "leafs_assn xs r None \\<^sub>A leaf_iter_assn xs r xs (r,None)" + unfolding leaf_iter_assn_def + by sep_auto + +definition leaf_iter_init where +"leaf_iter_init p = do { + return (p, None) +}" + +lemma leaf_iter_init_rule: + shows " + leaf_iter_init r + <\u. leaf_iter_assn xs r xs u>" + unfolding leaf_iter_init_def + using leaf_nodes_assn_imp_iter_assn + by (sep_auto) + +lemma leaf_iter_next_rule: " +leaf_iter_next it +<\(p, it'). leaf_iter_assn xs r xs2 it' * \(p = x)>" + unfolding leaf_iter_assn_def + apply(cases it) + by (sep_auto heap add: leaf_iter_next_rule_help simp add: leafs_assn_aux_append) + +definition leaf_iter_has_next where +"leaf_iter_has_next = (\(r,z). return (r \ z))" + +(* TODO this so far only works for the whole tree (z = None) +for subintervals, we would need to show that the list of pointers is indeed distinct, +hence r = z can only occur at the end *) +lemma leaf_iter_has_next_rule: + " leaf_iter_has_next it <\u. leaf_iter_assn xs r xs2 it * \(u \ xs2 \ [])>" + unfolding leaf_iter_has_next_def + apply(cases it) + apply(sep_auto simp add: leaf_iter_assn_def split!: prod.splits dest!: mod_starD) + subgoal for a + apply(cases xs2; cases a) + by auto + done + +(* copied from peter lammichs lseg_prec2 *) +declare mult.left_commute[simp add] +lemma leafs_assn_prec2: + "\l l'. (h\ + (leafs_assn l p None * F1) \\<^sub>A (leafs_assn l' p None * F2)) + \ l=l'" + apply (intro allI) + subgoal for l l' + proof (induct l arbitrary: p l' F1 F2) + case Nil thus ?case + apply simp_all + apply (cases l') + apply simp + apply (cases p) + apply auto + done + next + case (Cons y l) + from Cons.prems show ?case + apply (cases p) + apply simp + apply (cases l') + apply (auto) [] + apply (clarsimp) + apply (rule) + apply (drule_tac p=a in prec_frame[OF sngr_prec]) + apply frame_inference + apply frame_inference + apply simp + subgoal for a aa b list fwd fwda + apply(subgoal_tac "fwd=fwda") + using Cons.hyps[of fwd "a \\<^sub>r Btleaf y fwda * F1" list "a \\<^sub>r Btleaf (aa, b) fwd * F2", simplified] + apply (simp add: mult.left_assoc mod_and_dist) + apply (simp add: ab_semigroup_mult_class.mult.commute) + apply (drule_tac p=a in prec_frame[OF sngr_prec]) + apply frame_inference + apply frame_inference + apply simp + done + done + qed + done +declare mult.left_commute[simp del] + +interpretation leaf_node_it: imp_list_iterate + "\x y. leafs_assn x y None" + leaf_iter_assn + leaf_iter_init + leaf_iter_has_next + leaf_iter_next + apply(unfold_locales) + subgoal + by (simp add: leafs_assn_prec2 precise_def) + subgoal for l p + by (sep_auto heap add: leaf_iter_init_rule) + subgoal for l' l p it + thm leaf_iter_next_rule + apply(cases l'; cases it) + by (sep_auto heap add: leaf_iter_next_rule)+ + subgoal for l p l' it' + thm leaf_iter_has_next_rule + apply(cases it') + apply(rule hoare_triple_preI) + apply(sep_auto heap add: leaf_iter_has_next_rule) + done + subgoal for l p l' it + unfolding leaf_iter_assn_def + apply(cases it) + apply simp_all + apply(rule ent_ex_preI) + by (sep_auto simp add: leafs_assn_aux_append) + done + +interpretation leaf_elements_iter: flatten_iter + "\x y. leafs_assn x y None" leaf_iter_assn leaf_iter_init leaf_iter_has_next leaf_iter_next + "is_pfa (2*k)" "pfa_is_it (2*k)" pfa_it_init pfa_it_has_next pfa_it_next + by (unfold_locales) + +thm leaf_elements_iter.is_flatten_list.simps +thm leaf_elements_iter.is_flatten_it.simps +thm tree_leaf_iter_init_def +thm leaf_elements_iter.flatten_it_init_def +print_theorems + +fun leaf_elements_iter_init :: "('a::heap) btnode ref \ _" where + "leaf_elements_iter_init ti = do { + rz \ tree_leaf_iter_init (Some ti); + it \ leaf_elements_iter.flatten_it_init (fst rz); + return it +}" + + +(* NOTE: the other direction does not work, we are loosing information here + workaround: introduce specialized is_flatten_list assumption, show that all operations + preserve its correctness +*) +lemma leaf_nodes_imp_flatten_list: + "leaf_nodes_assn k ts r None \\<^sub>A + list_assn leaf_node ts (map bplustree.vals ts) * + leaf_elements_iter.is_flatten_list k (concat (map bplustree.vals ts)) r" + apply(simp add: leaf_nodes_assn_split) + apply(rule ent_ex_preI)+ + subgoal for ps + apply(inst_ex_assn ps "map bplustree.vals ts") + apply sep_auto + done + done + +lemma concat_leaf_nodes_leaves: "(concat (map bplustree.vals (leaf_nodes t))) = leaves t" + apply(induction t rule: leaf_nodes.induct) + subgoal by auto + subgoal for ts t + apply(induction ts) + subgoal by simp + subgoal by auto + done + done + +lemma leaf_elements_iter_init_rule: + assumes "k > 0" "root_order k t" + shows " +leaf_elements_iter_init ti +\<^sub>t" + unfolding leaf_elements_iter_init.simps + using assms + apply (sep_auto heap add: + tree_leaf_iter_init_rule + ) + supply R = Hoare_Triple.cons_pre_rule[OF leaf_nodes_imp_flatten_list[of k "leaf_nodes t" r], + where Q="\it. leaf_elements_iter.is_flatten_it k (leaves t) r (leaves t) it * true" + and c="leaf_elements_iter.flatten_it_init r"] + thm R + apply(sep_auto heap add: R) + subgoal + apply(simp add: concat_leaf_nodes_leaves) + apply sep_auto + done + subgoal by sep_auto + done + +end \ No newline at end of file diff --git a/thys/BTree/BPlusTree_Range.thy b/thys/BTree/BPlusTree_Range.thy new file mode 100644 --- /dev/null +++ b/thys/BTree/BPlusTree_Range.thy @@ -0,0 +1,432 @@ +theory BPlusTree_Range +imports BPlusTree + "HOL-Data_Structures.Set_Specs" + "HOL-Library.Sublist" + BPlusTree_Split +begin + +text "Lrange describes all elements in a set that are greater or equal to l, +a lower bounded range (with no upper bound)" + +definition Lrange where + "Lrange l X = {x \ X. x \ l}" + +definition "lrange_filter l = filter (\x. x \ l)" + +lemma lrange_filter_iff_Lrange: "set (lrange_filter l xs) = Lrange l (set xs)" + by (auto simp add: lrange_filter_def Lrange_def) + +fun lrange_list where + "lrange_list l (x#xs) = (if x \ l then (x#xs) else lrange_list l xs)" | + "lrange_list l [] = []" + +lemma sorted_leq_lrange: "sorted_wrt (\) xs \ lrange_list (l::'a::linorder) xs = lrange_filter l xs" + apply(induction xs) + apply(auto simp add: lrange_filter_def) + by (metis dual_order.trans filter_True) + +lemma sorted_less_lrange: "sorted_less xs \ lrange_list (l::'a::linorder) xs = lrange_filter l xs" + by (simp add: sorted_leq_lrange strict_sorted_iff) + +lemma lrange_list_sorted: "sorted_less (xs@x#ys) \ + lrange_list l (xs@x#ys) = + (if l < x then (lrange_list l xs)@x#ys else lrange_list l (x#ys))" + by (induction xs arbitrary: x) auto + +lemma lrange_filter_sorted: "sorted_less (xs@x#ys) \ + lrange_filter l (xs@x#ys) = + (if l < x then (lrange_filter l xs)@x#ys else lrange_filter l (x#ys))" + by (metis lrange_list_sorted sorted_less_lrange sorted_wrt_append) + + +lemma lrange_suffix: "suffix (lrange_list l xs) xs" + apply(induction xs) + apply (auto dest: suffix_ConsI) + done + + +locale split_range = split_tree split + for split:: + "('a bplustree \ 'a::{linorder,order_top}) list \ 'a + \ ('a bplustree \ 'a) list \ ('a bplustree \ 'a) list" + + fixes lrange_list :: "'a \ ('a::{linorder,order_top}) list \ 'a list" + assumes lrange_list_req: + (* we later derive such a function from a split function similar to the above *) + "sorted_less ks \ lrange_list l ks = lrange_filter l ks" +begin + +fun lrange:: "'a bplustree \ 'a \ 'a list" where + "lrange (Leaf ks) x = (lrange_list x ks)" | + "lrange (Node ts t) x = ( + case split ts x of (_,(sub,sep)#rs) \ ( + lrange sub x @ leaves_list rs @ leaves t + ) + | (_,[]) \ lrange t x + )" + +text "lrange proof" + + +(* lift to split *) + + +lemma lrange_sorted_split: + assumes "Laligned (Node ts t) u" + and "sorted_less (leaves (Node ts t))" + and "split ts x = (ls, rs)" + shows "lrange_filter x (leaves (Node ts t)) = lrange_filter x (leaves_list rs @ leaves t)" +proof (cases ls) + case Nil + then have "ts = rs" + using assms by (auto dest!: split_conc) + then show ?thesis by simp +next + case Cons + then obtain ls' sub sep where ls_tail_split: "ls = ls' @ [(sub,sep)]" + by (metis list.simps(3) rev_exhaust surj_pair) + then have x_sm_sep: "sep < x" + using split_req(2)[of ts x ls' sub sep rs] + using Laligned_sorted_separators[OF assms(1)] + using assms sorted_cons sorted_snoc + by blast + moreover have leaves_split: "leaves (Node ts t) = leaves_list ls @ leaves_list rs @ leaves t" + using assms(3) leaves_split by blast + then show ?thesis + proof (cases "leaves_list ls") + case Nil + then show ?thesis + using leaves_split + by (metis self_append_conv2) + next + case Cons + then obtain leavesls' l' where leaves_tail_split: "leaves_list ls = leavesls' @ [l']" + by (metis list.simps(3) rev_exhaust) + then have "l' \ sep" + proof - + have "l' \ set (leaves_list ls)" + using leaves_tail_split by force + then have "l' \ set (leaves (Node ls' sub))" + using ls_tail_split + by auto + moreover have "Laligned (Node ls' sub) sep" + using assms split_conc[OF assms(3)] Cons ls_tail_split + using Laligned_split_left[of ls' sub sep rs t u] + by simp + ultimately show ?thesis + using Laligned_leaves_inbetween[of "Node ls' sub" sep] + by blast + qed + then have "l' < x" + using le_less_trans x_sm_sep by blast + then show ?thesis + using assms(2) ls_tail_split leaves_tail_split leaves_split x_sm_sep + using lrange_filter_sorted[of "leavesls'" l' "leaves_list rs @ leaves t" x] + by (auto simp add: lrange_filter_def) + qed +qed + + +lemma lrange_sorted_split_right: + assumes "split ts x = (ls, (sub,sep)#rs)" + and "sorted_less (leaves (Node ts t))" + and "Laligned (Node ts t) u" + shows "lrange_filter x (leaves_list ((sub,sep)#rs) @ leaves t) = lrange_filter x (leaves sub)@leaves_list rs@leaves t" +proof - + from assms have "x \ sep" + proof - + from assms have "sorted_less (separators ts)" + by (meson Laligned_sorted_inorder sorted_cons sorted_inorder_separators sorted_snoc) + then show ?thesis + using split_req(3) + using assms + by fastforce + qed + moreover have leaves_split: "leaves (Node ts t) = leaves_list ls @ leaves sub @ leaves_list rs @ leaves t" + using split_conc[OF assms(1)] by auto + ultimately show ?thesis + proof (cases "leaves_list rs @ leaves t") + case Nil + then show ?thesis + by (metis assms(1) leaves_split same_append_eq self_append_conv split_tree.leaves_split split_tree_axioms) + next + case (Cons r' rs') + then have "sep < r'" + by (metis (mono_tags, lifting) Laligned_split_right aligned_leaves_inbetween append.right_neutral append_assoc assms(1) assms(3) concat.simps(1) leaves_conc list.set_intros(1) list.simps(8) split_tree.split_conc split_tree_axioms) + then have "x < r'" + using \x \ sep\ by auto + moreover have "sorted_less (leaves_list ((sub,sep)#rs) @ leaves t)" + using assms sorted_wrt_append split_conc + by fastforce + ultimately show ?thesis + using lrange_filter_sorted[of "leaves sub" "r'" "rs'" x] Cons + by auto + qed +qed + + +theorem lrange_set: + assumes "sorted_less (leaves t)" + and "aligned l t u" + shows "lrange t x = lrange_filter x (leaves t)" + using assms +proof(induction t x arbitrary: l u rule: lrange.induct) + case (1 ks x) + then show ?case + using lrange_list_req + by auto +next + case (2 ts t x) + then obtain ls rs where list_split: "split ts x = (ls, rs)" + by (meson surj_pair) + then have list_conc: "ts = ls @ rs" + using split_conc by auto + show ?case + proof (cases rs) + case Nil + then have "lrange (Node ts t) x = lrange t x" + by (simp add: list_split) + also have "\ = lrange_filter x (leaves t)" + by (metis "2.IH"(1) "2.prems"(1) "2.prems"(2) align_last' list_split local.Nil sorted_leaves_induct_last) + also have "\ = lrange_filter x (leaves (Node ts t))" + by (metis "2.prems"(1) "2.prems"(2) aligned_imp_Laligned leaves.simps(2) list_conc list_split local.Nil lrange_sorted_split same_append_eq self_append_conv split_tree.leaves_split split_tree_axioms) + finally show ?thesis . + next + case (Cons a list) + then obtain sub sep where a_split: "a = (sub,sep)" + by (cases a) + then have "lrange (Node ts t) x = lrange sub x @ leaves_list list @ leaves t" + using list_split Cons a_split + by auto + also have "\ = lrange_filter x (leaves sub) @ leaves_list list @ leaves t" + using "2.IH"(2)[of ls rs "(sub,sep)" list sub sep] + using "2.prems" a_split list_conc list_split local.Cons sorted_leaves_induct_subtree + align_sub + by (metis in_set_conv_decomp) + also have "\ = lrange_filter x (leaves (Node ts t))" + by (metis "2.prems"(1) "2.prems"(2) a_split aligned_imp_Laligned list_split local.Cons lrange_sorted_split lrange_sorted_split_right) + finally show ?thesis . + qed +qed + +text "Now the alternative explanation that first obtains the correct leaf node +and in a second step obtains the correct element from the leaf node." + +fun leaf_nodes_lrange:: "'a bplustree \ 'a \ 'a bplustree list" where + "leaf_nodes_lrange (Leaf ks) x = [Leaf ks]" | + "leaf_nodes_lrange (Node ts t) x = ( + case split ts x of (_,(sub,sep)#rs) \ ( + leaf_nodes_lrange sub x @ leaf_nodes_list rs @ leaf_nodes t + ) + | (_,[]) \ leaf_nodes_lrange t x + )" + +text "lrange proof" + + +(* lift to split *) + +lemma concat_leaf_nodes_leaves_list: "(concat (map leaves (leaf_nodes_list ts))) = leaves_list ts" + apply(induction ts) + subgoal by auto + subgoal using concat_leaf_nodes_leaves by auto + done + +theorem leaf_nodes_lrange_set: + assumes "sorted_less (leaves t)" + and "aligned l t u" + shows "suffix (lrange_filter x (leaves t)) (concat (map leaves (leaf_nodes_lrange t x)))" + using assms +proof(induction t x arbitrary: l u rule: lrange.induct) + case (1 ks x) + then show ?case + apply simp + by (metis lrange_suffix sorted_less_lrange) +next + case (2 ts t x) + then obtain ls rs where list_split: "split ts x = (ls, rs)" + by (meson surj_pair) + then have list_conc: "ts = ls @ rs" + using split_conc by auto + show ?case + proof (cases rs) + case Nil + then have *: "leaf_nodes_lrange (Node ts t) x = leaf_nodes_lrange t x" + by (simp add: list_split) + moreover have "suffix (lrange_filter x (leaves t)) (concat (map leaves (leaf_nodes_lrange t x)))" + by (metis "2.IH"(1) "2.prems"(1) "2.prems"(2) align_last' list_split local.Nil sorted_leaves_induct_last) + then have "suffix (lrange_filter x (leaves (Node ts t))) (concat (map leaves (leaf_nodes_lrange t x)))" + by (metis "2.prems"(1) "2.prems"(2) aligned_imp_Laligned leaves.simps(2) list_conc list_split local.Nil lrange_sorted_split same_append_eq self_append_conv split_tree.leaves_split split_tree_axioms) + ultimately show ?thesis by simp + next + case (Cons a list) + then obtain sub sep where a_split: "a = (sub,sep)" + by (cases a) + then have "leaf_nodes_lrange (Node ts t) x = leaf_nodes_lrange sub x @ leaf_nodes_list list @ leaf_nodes t" + using list_split Cons a_split + by auto + moreover have *: "suffix (lrange_filter x (leaves sub)) (concat (map leaves (leaf_nodes_lrange sub x)))" + by (metis "2.IH"(2) "2.prems"(1) "2.prems"(2) a_split align_sub in_set_conv_decomp list_conc list_split local.Cons sorted_leaves_induct_subtree) + then have "suffix (lrange_filter x (leaves (Node ts t))) (concat (map leaves (leaf_nodes_lrange sub x @ leaf_nodes_list list @ leaf_nodes t)))" + proof (goal_cases) + case 1 + have "lrange_filter x (leaves (Node ts t)) = lrange_filter x (leaves sub @ leaves_list list @ leaves t)" + by (metis (no_types, lifting) "2.prems"(1) "2.prems"(2) a_split aligned_imp_Laligned append.assoc concat_map_maps fst_conv list.simps(9) list_split local.Cons lrange_sorted_split maps_simps(1)) + also have "\ = lrange_filter x (leaves sub) @ leaves_list list @ leaves t" + by (metis "2.prems"(1) "2.prems"(2) a_split aligned_imp_Laligned calculation list_split local.Cons lrange_sorted_split_right split_range.lrange_sorted_split split_range_axioms) + moreover have "(concat (map leaves (leaf_nodes_lrange sub x @ leaf_nodes_list list @ leaf_nodes t))) = (concat (map leaves (leaf_nodes_lrange sub x)) @ leaves_list list @ leaves t)" + using concat_leaf_nodes_leaves_list[of list] concat_leaf_nodes_leaves[of t] + by simp + ultimately show ?case + using * + by simp + qed + ultimately show ?thesis by simp + qed +qed + +lemma leaf_nodes_lrange_not_empty: "\ks list. leaf_nodes_lrange t x = (Leaf ks)#list \ (Leaf ks) \ set (leaf_nodes t)" + apply(induction t x rule: leaf_nodes_lrange.induct) + apply (auto split!: prod.splits list.splits) + by (metis Cons_eq_appendI fst_conv in_set_conv_decomp split_conc) + + +text "Note that, conveniently, this argument is purely syntactic, +we do not need to show that this has anything to do with linear orders" + +lemma leaf_nodes_lrange_pre_lrange: "leaf_nodes_lrange t x = (Leaf ks)#list \ lrange_list x ks @ (concat (map leaves list)) = lrange t x" +proof(induction t x arbitrary: ks list rule: leaf_nodes_lrange.induct) + case (1 ks x) + then show ?case by simp +next + case (2 ts t x ks list) + then show ?case + proof(cases "split ts x") + case split: (Pair ls rs) + then show ?thesis + proof (cases rs) + case Nil + then show ?thesis + using "2.IH"(1) "2.prems" split by auto + next + case (Cons subsep rss) + then show ?thesis + proof(cases subsep) + case sub_sep: (Pair sub sep) + thm "2.IH"(2) "2.prems" + have "\list'. leaf_nodes_lrange sub x = (Leaf ks)#list'" + using "2.prems" split Cons sub_sep leaf_nodes_lrange_not_empty[of sub x] + apply simp + by fastforce + then obtain list' where *: "leaf_nodes_lrange sub x = (Leaf ks)#list'" + by blast + moreover have "list = list'@concat (map (leaf_nodes \ fst) rss) @ leaf_nodes t" + using * + using "2.prems" split Cons sub_sep + by simp + ultimately show ?thesis + using split "2.IH"(2)[OF split[symmetric] Cons sub_sep[symmetric] *,symmetric] + Cons sub_sep concat_leaf_nodes_leaves_list[of rss] concat_leaf_nodes_leaves[of t] + by simp + qed + qed + qed +qed + +text "We finally obtain a function that is way easier to reason about in the imperative setting" +fun concat_leaf_nodes_lrange where + "concat_leaf_nodes_lrange t x = (case leaf_nodes_lrange t x of (Leaf ks)#list \ lrange_list x ks @ (concat (map leaves list)))" + +lemma concat_leaf_nodes_lrange_lrange: "concat_leaf_nodes_lrange t x = lrange t x" +proof - + obtain ks list where *: "leaf_nodes_lrange t x = (Leaf ks)#list" + using leaf_nodes_lrange_not_empty by blast + then have "concat_leaf_nodes_lrange t x = lrange_list x ks @ (concat (map leaves list))" + by simp + also have "\ = lrange t x" + using leaf_nodes_lrange_pre_lrange[OF *] + by simp + finally show ?thesis . +qed + +end + +context split_list +begin + +definition lrange_split where +"lrange_split l xs = (case split_list xs l of (ls,rs) \ rs)" + +lemma lrange_filter_split: + assumes "sorted_less xs" + and "split_list xs l = (ls,rs)" + shows "lrange_list l xs = rs" + find_theorems split_list +proof(cases rs) + case rs_Nil: Nil + then show ?thesis + proof(cases ls) + case Nil + then show ?thesis + using assms split_list_req(1)[of xs l ls rs] rs_Nil + by simp + next + case Cons + then obtain lss sep where snoc: "ls = lss@[sep]" + by (metis append_butlast_last_id list.simps(3)) + then have "sep < l" + using assms(1) assms(2) split_list_req(2) by blast + then show ?thesis + using lrange_list_sorted[of lss sep rs l] + snoc split_list_req(1)[OF assms(2)] + assms rs_Nil + by simp + qed +next + case ls_Cons: (Cons sep rss) + then have *: "l \ sep" + using assms(1) assms(2) split_list_req(3) by auto + then show ?thesis + proof(cases ls) + case Nil + then show ?thesis + using lrange_list_sorted[of ls sep rss l] + split_list_req(1)[OF assms(2)] assms + ls_Cons * + by simp + next + case Cons + then obtain lss sep2 where snoc: "ls = lss@[sep2]" + by (metis append_butlast_last_id list.simps(3)) + then have "sep2 < l" + using assms(1) assms(2) split_list_req(2) by blast + moreover have "sorted_less (lss@[sep2])" + using assms(1) assms(2) ls_Cons snoc sorted_mid_iff sorted_snoc split_list_req(1) by blast + ultimately show ?thesis + using lrange_list_sorted[of ls sep rss l] + lrange_list_sorted[of lss "sep2" "[]" l] + split_list_req(1)[OF assms(2)] assms + ls_Cons * snoc + by simp + qed +qed + +lemma lrange_split_req: + assumes "sorted_less xs" + shows "lrange_split l xs = lrange_filter l xs" + unfolding lrange_split_def + using lrange_filter_split[of xs l] assms + using sorted_less_lrange + by (simp split!: prod.splits) + +end + +context split_full +begin + +sublocale split_range split lrange_split + using lrange_split_req + by unfold_locales auto + +end + +end \ No newline at end of file diff --git a/thys/BTree/BPlusTree_Set.thy b/thys/BTree/BPlusTree_Set.thy new file mode 100644 --- /dev/null +++ b/thys/BTree/BPlusTree_Set.thy @@ -0,0 +1,3666 @@ +theory BPlusTree_Set + imports + BPlusTree_Split + "HOL-Data_Structures.Set_Specs" +begin + + +section "Set interpretation" + +(* obsolete fact *) +lemma insert_list_length[simp]: + assumes "sorted_less ks" + and "set (insert_list k ks) = set ks \ {k}" + and "sorted_less ks \ sorted_less (insert_list k ks)" + shows "length (insert_list k ks) = length ks + (if k \ set ks then 0 else 1)" +proof - + have "distinct (insert_list k ks)" + using assms(1) assms(3) strict_sorted_iff by blast + then have "length (insert_list k ks) = card (set (insert_list k ks))" + by (simp add: distinct_card) + also have "\ = card (set ks \ {k})" + using assms(2) by presburger + also have "\ = card (set ks) + (if k \ set ks then 0 else 1)" + by (cases "k \ set ks") (auto simp add: insert_absorb) + also have "\ = length ks + (if k \ set ks then 0 else 1)" + using assms(1) distinct_card strict_sorted_iff by auto + finally show ?thesis. +qed + +lemma delete_list_length[simp]: + assumes "sorted_less ks" + and "set (delete_list k ks) = set ks - {k}" + and "sorted_less ks \ sorted_less (delete_list k ks)" + shows "length (delete_list k ks) = length ks - (if k \ set ks then 1 else 0)" +proof - + have "distinct (delete_list k ks)" + using assms(1) assms(3) strict_sorted_iff by blast + then have "length (delete_list k ks) = card (set (delete_list k ks))" + by (simp add: distinct_card) + also have "\ = card (set ks - {k})" + using assms(2) by presburger + also have "\ = card (set ks) - (if k \ set ks then 1 else 0)" + by (cases "k \ set ks") (auto) + also have "\ = length ks - (if k \ set ks then 1 else 0)" + by (metis assms(1) distinct_card strict_sorted_iff) + finally show ?thesis. +qed + +lemma ins_list_length[simp]: + assumes "sorted_less ks" + shows "length (ins_list k ks) = length ks + (if k \ set ks then 0 else 1)" + using insert_list_length[of ks ins_list k] + by (simp add: assms set_ins_list sorted_ins_list) + +lemma del_list_length[simp]: + assumes "sorted_less ks" + shows "length (del_list k ks) = length ks - (if k \ set ks then 1 else 0)" + using delete_list_length[of ks ins_list k] + by (simp add: assms set_del_list sorted_del_list) + + +(* TODO what if we define a function "list_split" that returns + a split list for mapping arbitrary f (separators) and g (subtrees) +s.th. f :: 'a \ ('b::linorder) and g :: 'a \ 'a bplustree +this would allow for key,pointer pairs to be inserted into the tree *) +(* TODO what if the keys are the pointers? *) +locale split_set = split_tree: split_tree split + for split:: + "('a bplustree \ 'a::{linorder,order_top}) list \ 'a + \ ('a bplustree \ 'a) list \ ('a bplustree \ 'a) list" + + fixes isin_list :: "'a \ ('a::{linorder,order_top}) list \ bool" + and insert_list :: "'a \ ('a::{linorder,order_top}) list \ 'a list" + and delete_list :: "'a \ ('a::{linorder,order_top}) list \ 'a list" + assumes insert_list_req: + (* TODO locale that derives such a function from a split function similar to the above *) + "sorted_less ks \ isin_list x ks = (x \ set ks)" + "sorted_less ks \ insert_list x ks = ins_list x ks" + "sorted_less ks \ delete_list x ks = del_list x ks" +begin + +lemmas split_req = split_tree.split_req +lemmas split_conc = split_tree.split_req(1) +lemmas split_sorted = split_tree.split_req(2,3) + +lemma insert_list_length[simp]: + assumes "sorted_less ks" + shows "length (insert_list k ks) = length ks + (if k \ set ks then 0 else 1)" + using insert_list_req + by (simp add: assms) + +lemma set_insert_list[simp]: + "sorted_less ks \ set (insert_list k ks) = set ks \ {k}" + by (simp add: insert_list_req set_ins_list) + +lemma sorted_insert_list[simp]: + "sorted_less ks \ sorted_less (insert_list k ks)" + by (simp add: insert_list_req sorted_ins_list) + +lemma delete_list_length[simp]: + assumes "sorted_less ks" + shows "length (delete_list k ks) = length ks - (if k \ set ks then 1 else 0)" + using insert_list_req + by (simp add: assms) + +lemma set_delete_list[simp]: + "sorted_less ks \ set (delete_list k ks) = set ks - {k}" + by (simp add: insert_list_req set_del_list) + +lemma sorted_delete_list[simp]: + "sorted_less ks \ sorted_less (delete_list k ks)" + by (simp add: insert_list_req sorted_del_list) + + + +definition "empty_bplustree = (Leaf [])" + +subsection "Membership" + +fun isin:: "'a bplustree \ 'a \ bool" where + "isin (Leaf ks) x = (isin_list x ks)" | + "isin (Node ts t) x = ( + case split ts x of (_,(sub,sep)#rs) \ ( + isin sub x + ) + | (_,[]) \ isin t x + )" + + +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) + + +lemmas isin_simps2 = sorted_lems sorted_ConsD sorted_snocD + (*-----------------------------*) + +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 "Laligned (Node ts t) u" + and "sorted_less (leaves (Node ts t))" + and "split ts x = (ls, rs)" + shows "x \ set (leaves (Node ts t)) = (x \ set (leaves_list rs @ leaves t))" +proof (cases ls) + case Nil + then have "ts = rs" + using assms by (auto dest!: split_conc) + then show ?thesis by simp +next + case Cons + then obtain ls' sub sep where ls_tail_split: "ls = ls' @ [(sub,sep)]" + by (metis list.simps(3) rev_exhaust surj_pair) + then have x_sm_sep: "sep < x" + using split_req(2)[of ts x ls' sub sep rs] + using Laligned_sorted_separators[OF assms(1)] + using assms sorted_cons sorted_snoc + by blast + moreover have leaves_split: "leaves (Node ts t) = leaves_list ls @ leaves_list rs @ leaves t" + using assms(3) split_tree.leaves_split by blast + then show ?thesis + proof (cases "leaves_list ls") + case Nil + then show ?thesis + using leaves_split by auto + next + case Cons + then obtain leavesls' l' where leaves_tail_split: "leaves_list ls = leavesls' @ [l']" + by (metis list.simps(3) rev_exhaust) + then have "l' \ sep" + proof - + have "l' \ set (leaves_list ls)" + using leaves_tail_split by force + then have "l' \ set (leaves (Node ls' sub))" + using ls_tail_split + by auto + moreover have "Laligned (Node ls' sub) sep" + using assms split_conc[OF assms(3)] Cons ls_tail_split + using Laligned_split_left[of ls' sub sep rs t u] + by simp + ultimately show ?thesis + using Laligned_leaves_inbetween[of "Node ls' sub" sep] + by blast + qed + then show ?thesis + using assms(2) ls_tail_split leaves_tail_split leaves_split x_sm_sep + using isin_sorted[of "leavesls'" l' "leaves_list rs @ leaves t" x] + by auto + qed +qed + +lemma isin_sorted_split_right: + assumes "split ts x = (ls, (sub,sep)#rs)" + and "sorted_less (leaves (Node ts t))" + and "Laligned (Node ts t) u" + shows "x \ set (leaves_list ((sub,sep)#rs) @ leaves t) = (x \ set (leaves sub))" +proof - + from assms have "x \ sep" + proof - + from assms have "sorted_less (separators ts)" + by (meson Laligned_sorted_inorder sorted_cons sorted_inorder_separators sorted_snoc) + then show ?thesis + using split_req(3) + using assms + by fastforce + qed + moreover have leaves_split: "leaves (Node ts t) = leaves_list ls @ leaves sub @ leaves_list rs @ leaves t" + using split_conc[OF assms(1)] by auto + ultimately show ?thesis + proof (cases "leaves_list rs @ leaves t") + case Nil + then show ?thesis + using leaves_split by auto + next + case (Cons r' rs') + then have "sep < r'" + by (metis Laligned_split_right aligned_leaves_inbetween assms(1) assms(3) leaves.simps(2) list.set_intros(1) split_set.split_conc split_set_axioms) + then have "x < r'" + using \x \ sep\ by auto + moreover have "sorted_less (leaves_list ((sub,sep)#rs) @ leaves t)" + using assms sorted_wrt_append split_conc + by fastforce + ultimately show ?thesis + using isin_sorted[of "leaves sub" "r'" "rs'" x] Cons + by auto + qed +qed + + +theorem isin_set_inorder: + assumes "sorted_less (leaves t)" + and "aligned l t u" + shows "isin t x = (x \ set (leaves t))" + using assms +proof(induction t x arbitrary: l u rule: isin.induct) + case (2 ts t x) + then obtain ls rs where list_split: "split ts x = (ls, rs)" + by (meson surj_pair) + then have list_conc: "ts = ls @ rs" + using split_conc by auto + show ?case + proof (cases rs) + case Nil + then have "isin (Node ts t) x = isin t x" + by (simp add: list_split) + also have "\ = (x \ set (leaves t))" + using "2.IH"(1)[of ls rs] list_split Nil + using "2.prems" sorted_leaves_induct_last align_last' + by metis + also have "\ = (x \ set (leaves (Node ts t)))" + using isin_sorted_split + using "2.prems" list_split list_conc Nil + by (metis aligned_imp_Laligned leaves.simps(2) leaves_conc same_append_eq self_append_conv) + finally show ?thesis . + next + case (Cons a list) + then obtain sub sep where a_split: "a = (sub,sep)" + by (cases a) + then have "isin (Node ts t) x = isin sub x" + using list_split Cons a_split + by auto + also have "\ = (x \ set (leaves sub))" + using "2.IH"(2)[of ls rs "(sub,sep)" list sub sep] + using "2.prems" a_split list_conc list_split local.Cons sorted_leaves_induct_subtree + align_sub + by (metis in_set_conv_decomp) + also have "\ = (x \ set (leaves (Node ts t)))" + using isin_sorted_split + using isin_sorted_split_right "2.prems" list_split Cons a_split + using aligned_imp_Laligned by blast + finally show ?thesis . + qed +qed (auto simp add: insert_list_req) + + +theorem isin_set_Linorder: + assumes "sorted_less (leaves t)" + and "Laligned t u" + shows "isin t x = (x \ set (leaves t))" + using assms +proof(induction t x arbitrary: u rule: isin.induct) + case (2 ts t x) + then obtain ls rs where list_split: "split ts x = (ls, rs)" + by (meson surj_pair) + then have list_conc: "ts = ls @ rs" + using split_conc by auto + show ?case + proof (cases rs) + case Nil + then have "isin (Node ts t) x = isin t x" + by (simp add: list_split) + also have "\ = (x \ set (leaves t))" + by (metis "2.IH"(1) "2.prems"(1) "2.prems"(2) Lalign_Llast list_split local.Nil sorted_leaves_induct_last) + also have "\ = (x \ set (leaves (Node ts t)))" + using isin_sorted_split + using "2.prems" list_split list_conc Nil + by simp + finally show ?thesis . + next + case (Cons a list) + then obtain sub sep where a_split: "a = (sub,sep)" + by (cases a) + then have "isin (Node ts t) x = isin sub x" + using list_split Cons a_split + by auto + also have "\ = (x \ set (leaves sub))" + using "2.IH"(2)[of ls rs "(sub,sep)" list sub sep] + using "2.prems" a_split list_conc list_split local.Cons sorted_leaves_induct_subtree + align_sub + by (metis Lalign_Llast Laligned_split_left) + also have "\ = (x \ set (leaves (Node ts t)))" + using isin_sorted_split + using isin_sorted_split_right "2.prems" list_split Cons a_split + by simp + finally show ?thesis . + qed +qed (auto simp add: insert_list_req) + +corollary isin_set_Linorder_top: + assumes "sorted_less (leaves t)" + and "Laligned t top" + shows "isin t x = (x \ set (leaves t))" + using assms isin_set_Linorder + by simp + +subsection "Insertion" + +text "The insert function requires an auxiliary data structure +and auxiliary invariant functions." + +datatype 'b up\<^sub>i = T\<^sub>i "'b bplustree" | Up\<^sub>i "'b bplustree" 'b "'b bplustree" + +fun order_up\<^sub>i where + "order_up\<^sub>i k (T\<^sub>i sub) = order k sub" | + "order_up\<^sub>i k (Up\<^sub>i l a r) = (order k l \ order k r)" + +fun root_order_up\<^sub>i where + "root_order_up\<^sub>i k (T\<^sub>i sub) = root_order k sub" | + "root_order_up\<^sub>i k (Up\<^sub>i l a r) = (order k l \ order k r)" + + +fun height_up\<^sub>i where + "height_up\<^sub>i (T\<^sub>i t) = height t" | + "height_up\<^sub>i (Up\<^sub>i l a r) = max (height l) (height r)" + +fun bal_up\<^sub>i where + "bal_up\<^sub>i (T\<^sub>i t) = bal t" | + "bal_up\<^sub>i (Up\<^sub>i l a r) = (height l = height r \ bal l \ bal r)" + +fun inorder_up\<^sub>i where + "inorder_up\<^sub>i (T\<^sub>i t) = inorder t" | + "inorder_up\<^sub>i (Up\<^sub>i l a r) = inorder l @ [a] @ inorder r" + +fun leaves_up\<^sub>i where + "leaves_up\<^sub>i (T\<^sub>i t) = leaves t" | + "leaves_up\<^sub>i (Up\<^sub>i l a r) = leaves l @ leaves r" + +fun aligned_up\<^sub>i where + "aligned_up\<^sub>i l (T\<^sub>i t) u = aligned l t u" | + "aligned_up\<^sub>i l (Up\<^sub>i lt a rt) u = (aligned l lt a \ aligned a rt u)" + +fun Laligned_up\<^sub>i where + "Laligned_up\<^sub>i (T\<^sub>i t) u = Laligned t u" | + "Laligned_up\<^sub>i (Up\<^sub>i lt a rt) u = (Laligned lt a \ aligned a rt u)" + +text "The following function merges two nodes and returns separately split nodes + if an overflow occurs" + +(* note here that splitting away the last element is actually very nice + from the implementation perspective *) +fun node\<^sub>i:: "nat \ ('a bplustree \ 'a) list \ 'a bplustree \ 'a up\<^sub>i" where + "node\<^sub>i k ts t = ( + if length ts \ 2*k then T\<^sub>i (Node ts t) + else ( + case split_half ts of (ls, rs) \ + case last ls of (sub,sep) \ + Up\<^sub>i (Node (butlast ls) sub) sep (Node rs t) + ) + )" + +fun Lnode\<^sub>i:: "nat \ 'a list \ 'a up\<^sub>i" where + "Lnode\<^sub>i k ts = ( + if length ts \ 2*k then T\<^sub>i (Leaf ts) + else ( + case split_half ts of (ls, rs) \ + Up\<^sub>i (Leaf ls) (last ls) (Leaf rs) + ) + )" + +fun ins:: "nat \ 'a \ 'a bplustree \ 'a up\<^sub>i" where + "ins k x (Leaf ks) = Lnode\<^sub>i k (insert_list x ks)" | + "ins k x (Node ts t) = ( + case split ts x of + (ls,(sub,sep)#rs) \ + (case ins k x sub of + Up\<^sub>i l a r \ + node\<^sub>i k (ls@(l,a)#(r,sep)#rs) t | + T\<^sub>i a \ + T\<^sub>i (Node (ls@(a,sep)#rs) t)) | + (ls, []) \ + (case ins k x t of + Up\<^sub>i l a r \ + node\<^sub>i k (ls@[(l,a)]) r | + T\<^sub>i a \ + T\<^sub>i (Node ls a) + ) +)" + + + +fun tree\<^sub>i::"'a up\<^sub>i \ 'a bplustree" where + "tree\<^sub>i (T\<^sub>i sub) = sub" | + "tree\<^sub>i (Up\<^sub>i l a r) = (Node [(l,a)] r)" + +fun insert::"nat \ 'a \ 'a bplustree \ 'a bplustree" where + "insert k x t = tree\<^sub>i (ins k x t)" + + +subsection "Proofs of functional correctness" + +lemma nodei_ti_simp: "node\<^sub>i k ts t = T\<^sub>i x \ x = Node ts t" + apply (cases "length ts \ 2*k") + apply (auto split!: list.splits prod.splits) + done + +lemma Lnodei_ti_simp: "Lnode\<^sub>i k ts = T\<^sub>i x \ x = Leaf ts" + apply (cases "length ts \ 2*k") + apply (auto split!: list.splits) + done + + +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) + + + +(* TODO way to use this for custom case distinction? *) +lemma node\<^sub>i_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 + then show ?thesis + using split_half_not_empty + by fastforce +qed + +lemma Lnode\<^sub>i_cases: "length xs \ k \ (\ls sep rs. split_half xs = (ls@[sep],rs))" +proof - + have "\ length xs \ k \ length xs \ 1" + by linarith + then show ?thesis + using split_half_not_empty + by fastforce +qed + +lemma root_order_tree\<^sub>i: "root_order_up\<^sub>i (Suc k) t = root_order (Suc k) (tree\<^sub>i t)" + apply (cases t) + apply auto + done + +lemma length_take_left: "length (take ((length ts + 1) div 2) ts) = (length ts + 1) div 2" + apply (cases ts) + apply auto + done + +lemma node\<^sub>i_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_up\<^sub>i k (node\<^sub>i k ts t)" +proof (cases "length ts \ 2*k") + case True + then show ?thesis + using assms + by (simp add: node\<^sub>i.simps) +next + case False + then obtain ls sub sep rs where split_half_ts: + "take ((length ts + 1) div 2) ts = ls@[(sub,sep)]" + using split_half_not_empty[of ts] + by auto + then have length_ls: "length ls = (length ts + 1) div 2 - 1" + by (metis One_nat_def add_diff_cancel_right' add_self_div_2 bits_1_div_2 length_append length_take_left list.size(3) list.size(4) odd_one odd_succ_div_two) + also have "\ \ (4*k + 1) div 2" + using assms(2) by simp + also have "\ = 2*k" + by auto + finally have "length ls \ 2*k" + by simp + moreover have "length ls \ k" + using False length_ls by simp + moreover have "set (ls@[(sub,sep)]) \ set ts" + by (metis split_half_ts(1) set_take_subset) + ultimately have o_r: "order k (Node ls sub)" + using split_half_ts assms by auto + have + "butlast (take ((length ts + 1) div 2) ts) = ls" + "last (take ((length ts + 1) div 2) ts) = (sub,sep)" + using split_half_ts by auto + then show ?thesis + using o_r assms set_drop_subset[of _ ts] + by (auto simp add: False split_half_ts split!: prod.splits) +qed + +lemma node\<^sub>i_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 (node\<^sub>i k ts t) of T\<^sub>i t \ order k t | _ \ True" +proof (cases "length ts \ 2*k") + case True + then show ?thesis + using assms + by (simp add: node\<^sub>i.simps) +next + case False + then obtain sub sep ls where + "take ((length ts + 1) div 2) ts = ls@[(sub,sep)]" + using split_half_not_empty[of ts] + by fastforce + then show ?thesis + using assms by simp +qed + + +lemma node\<^sub>i_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_up\<^sub>i k (node\<^sub>i k ts t)" + apply(cases "node\<^sub>i k ts t") + using node\<^sub>i_root_order node\<^sub>i_order_helper assms apply fastforce + by (metis (full_types) assms le_0_eq nat_le_linear node\<^sub>i.elims node\<^sub>i_root_order order_up\<^sub>i.simps(2) root_order_up\<^sub>i.simps(2) up\<^sub>i.simps(4) verit_comp_simplify1(3)) + + +lemma Lnode\<^sub>i_root_order: + assumes "length ts > 0" + and "length ts \ 4*k" + shows "root_order_up\<^sub>i k (Lnode\<^sub>i k ts)" +proof (cases "length ts \ 2*k") + case True + then show ?thesis + using assms + by simp +next + case False + then obtain ls sep rs where split_half_ts: + "take ((length ts + 1) div 2) ts = ls@[sep]" + "drop ((length ts + 1) div 2) ts = rs" + using split_half_not_empty[of ts] + by auto + then have length_ls: "length ls = ((length ts + 1) div 2) - 1" + by (metis One_nat_def add_diff_cancel_right' add_self_div_2 bits_1_div_2 length_append length_take_left list.size(3) list.size(4) odd_one odd_succ_div_two) + also have "\ < (4*k + 1) div 2" + using assms(2) + by (smt (z3) Groups.add_ac(2) One_nat_def split_half_ts add.right_neutral diff_is_0_eq' div_le_mono le_add_diff_inverse le_neq_implies_less length_append length_take_left less_add_Suc1 less_imp_diff_less list.size(4) nat_le_linear not_less_eq plus_nat.simps(2)) + also have "\ = 2*k" + by auto + finally have "length ls < 2*k" + by simp + moreover have "length ls \ k" + using False length_ls by simp + ultimately have o_l: "order k (Leaf (ls@[sep]))" + using set_take_subset assms split_half_ts + by fastforce + then show ?thesis + using assms split_half_ts False + by auto +qed + +lemma Lnode\<^sub>i_order_helper: + assumes "length ts \ k" + and "length ts \ 4*k+1" + shows "case (Lnode\<^sub>i k ts) of T\<^sub>i t \ order k t | _ \ True" +proof (cases "length ts \ 2*k") + case True + then show ?thesis + using assms + by (simp add: node\<^sub>i.simps) +next + case False + then obtain sep ls where + "take ((length ts + 1) div 2) ts = ls@[sep]" + using split_half_not_empty[of ts] + by fastforce + then show ?thesis + using assms by simp +qed + + +lemma Lnode\<^sub>i_order: + assumes "length ts \ k" + and "length ts \ 4*k" + shows "order_up\<^sub>i k (Lnode\<^sub>i k ts)" + apply(cases "Lnode\<^sub>i k ts") + apply (metis Lnode\<^sub>i_order_helper One_nat_def add.right_neutral add_Suc_right assms(1) assms(2) le_imp_less_Suc less_le order_up\<^sub>i.simps(1) up\<^sub>i.simps(5)) + by (metis Lnode\<^sub>i.elims Lnode\<^sub>i_root_order assms(1) assms(2) diff_is_0_eq' le_0_eq le_add_diff_inverse mult_2 order_up\<^sub>i.simps(2) root_order_up\<^sub>i.simps(2) up\<^sub>i.simps(3) verit_comp_simplify1(3)) + +(* explicit proof *) +lemma ins_order: + "k > 0 \ sorted_less (leaves t) \ order k t \ order_up\<^sub>i k (ins k x t)" +proof(induction k x t rule: ins.induct) + case (1 k x ts) + then show ?case + by auto (* this proof requires both sorted_less and k > 0 *) +next + case (2 k x ts t) + then obtain ls rs where split_res: "split ts x = (ls, rs)" + by (meson surj_pair) + then have split_app: "ts = ls@rs" + using split_conc + by simp + + show ?case + proof (cases rs) + case Nil + then have "order_up\<^sub>i k (ins k x t)" + using 2 split_res sorted_leaves_induct_last + by auto + then show ?thesis + using Nil 2 split_app split_res Nil node\<^sub>i_order + by (auto split!: up\<^sub>i.splits simp del: node\<^sub>i.simps) + next + case (Cons a list) + then obtain sub sep where a_prod: "a = (sub, sep)" + by (cases a) + then have "sorted_less (leaves sub)" + using "2"(4) Cons sorted_leaves_induct_subtree split_app + by blast + then have "order_up\<^sub>i k (ins k x sub)" + using "2.IH"(2) "2.prems" a_prod local.Cons split_app split_res + by auto + then show ?thesis + using 2 split_app Cons length_append node\<^sub>i_order[of k "ls@_#_#list"] a_prod split_res + by (auto split!: up\<^sub>i.splits simp del: node\<^sub>i.simps simp add: order_impl_root_order) + qed +qed + + +(* notice this is almost a duplicate of ins_order *) +lemma ins_root_order: + assumes "k > 0" "sorted_less (leaves t)" "root_order k t" + shows "root_order_up\<^sub>i k (ins k x t)" +proof(cases t) + case (Leaf ks) + then show ?thesis + using assms by (auto simp add: Lnode\<^sub>i_order min_absorb2) (* this proof requires both sorted_less and k > 0 *) +next + case (Node ts t) + then obtain ls rs where split_res: "split ts x = (ls, rs)" + by (meson surj_pair) + then have split_app: "ls@rs = ts" + using split_conc + by fastforce + + show ?thesis + proof (cases rs) + case Nil + then have "order_up\<^sub>i k (ins k x t)" + using Node assms split_res sorted_leaves_induct_last + using ins_order[of k t] + by auto + then show ?thesis + using Nil Node split_app split_res assms node\<^sub>i_root_order + by (auto split!: up\<^sub>i.splits simp del: node\<^sub>i.simps simp add: order_impl_root_order) + next + case (Cons a list) + then obtain sub sep where a_prod: "a = (sub, sep)" + by (cases a) + then have "sorted_less (leaves sub)" + using Node assms(2) local.Cons sorted_leaves_induct_subtree split_app + by blast + then have "order_up\<^sub>i k (ins k x sub)" + using Node a_prod assms ins_order local.Cons split_app + by auto + then show ?thesis + using assms split_app Cons length_append Node node\<^sub>i_root_order a_prod split_res + by (auto split!: up\<^sub>i.splits simp del: node\<^sub>i.simps simp add: order_impl_root_order) + qed +qed + + + +lemma height_list_split: "height_up\<^sub>i (Up\<^sub>i (Node ls a) b (Node rs t)) = height (Node (ls@(a,b)#rs) t) " + by (induction ls) (auto simp add: max.commute) + +lemma node\<^sub>i_height: "height_up\<^sub>i (node\<^sub>i k ts t) = height (Node ts t)" +proof(cases "length ts \ 2*k") + case False + then obtain ls sub sep rs where + split_half_ts: "split_half ts = (ls@[(sub,sep)], rs)" + by (meson node\<^sub>i_cases) + then have "node\<^sub>i k ts t = Up\<^sub>i (Node ls (sub)) sep (Node rs t)" + using False by simp + then have "height_up\<^sub>i (node\<^sub>i k ts t) = height (Node (ls@(sub,sep)#rs) t)" + by (metis height_list_split) + also have "\ = height (Node ts t)" + by (metis (no_types, lifting) Pair_inject append_Cons append_eq_append_conv2 append_take_drop_id self_append_conv split_half.simps split_half_ts) + finally show ?thesis. +qed simp + + +lemma Lnode\<^sub>i_height: "height_up\<^sub>i (Lnode\<^sub>i k xs) = height (Leaf xs)" + by (auto) + +lemma bal_up\<^sub>i_tree: "bal_up\<^sub>i t = bal (tree\<^sub>i t)" + apply(cases t) + apply auto + done + +lemma bal_list_split: "bal (Node (ls@(a,b)#rs) t) \ bal_up\<^sub>i (Up\<^sub>i (Node ls a) b (Node rs t))" + by (auto simp add: image_constant_conv) + +lemma node\<^sub>i_bal: + assumes "bal (Node ts t)" + shows "bal_up\<^sub>i (node\<^sub>i k ts t)" + using assms +proof(cases "length ts \ 2*k") + case False + then obtain ls sub sep rs where + split_half_ts: "split_half ts = (ls@[(sub,sep)], rs)" + by (meson node\<^sub>i_cases) + then have "bal (Node (ls@(sub,sep)#rs) t)" + using assms append_take_drop_id[where n="(length ts + 1) div 2" and xs=ts] + by auto + then show ?thesis + using split_half_ts assms False + by (auto simp del: bal.simps bal_up\<^sub>i.simps dest!: bal_list_split[of ls sub sep rs t]) +qed simp + +lemma node\<^sub>i_aligned: + assumes "aligned l (Node ts t) u" + shows "aligned_up\<^sub>i l (node\<^sub>i k ts t) u" + using assms +proof (cases "length ts \ 2*k") + case False + then obtain ls sub sep rs where + split_half_ts: "split_half ts = (ls@[(sub,sep)], rs)" + by (meson node\<^sub>i_cases) + then have "aligned l (Node ls sub) sep" + by (metis aligned_split_left append.assoc append_Cons append_take_drop_id assms prod.sel(1) split_half.simps) + moreover have "aligned sep (Node rs t) u" + by (smt (z3) Pair_inject aligned_split_right append.assoc append_Cons append_Nil2 append_take_drop_id assms same_append_eq split_half.simps split_half_ts) + ultimately show ?thesis + using split_half_ts False by auto +qed simp + +lemma node\<^sub>i_Laligned: + assumes "Laligned (Node ts t) u" + shows "Laligned_up\<^sub>i (node\<^sub>i k ts t) u" + using assms +proof (cases "length ts \ 2*k") + case False + then obtain ls sub sep rs where + split_half_ts: "split_half ts = (ls@[(sub,sep)], rs)" + by (meson node\<^sub>i_cases) + then have "Laligned (Node ls sub) sep" + by (metis Laligned_split_left append.assoc append_Cons assms split_half_conc) + moreover have "aligned sep (Node rs t) u" + by (metis Laligned_split_right append.assoc append_Cons append_Nil2 assms same_append_eq split_half_conc split_half_ts) + ultimately show ?thesis + using split_half_ts False by auto +qed simp + + +lemma length_right_side: "length xs > 1 \ length (drop ((length xs + 1) div 2) xs) > 0" + by auto + +lemma Lnode\<^sub>i_aligned: + assumes "aligned l (Leaf ks) u" + and "sorted_less ks" + and "k > 0" + shows "aligned_up\<^sub>i l (Lnode\<^sub>i k ks) u" + using assms +proof (cases "length ks \ 2*k") + case False + then obtain ls sep rs where split_half_ts: + "take ((length ks + 1) div 2) ks = ls@[sep]" + "drop ((length ks + 1) div 2) ks = rs" + using split_half_not_empty[of ks] + by auto + moreover have "sorted_less (ls@[sep])" + by (metis append_take_drop_id assms(2) sorted_wrt_append split_half_ts(1)) + ultimately have "aligned l (Leaf (ls@[sep])) sep" + using split_half_conc[of ks "ls@[sep]" rs] assms sorted_snoc_iff[of ls sep] + by auto + moreover have "aligned sep (Leaf rs) u" + proof - + have "length rs > 0" + using False assms(3) split_half_ts(2) by fastforce + then obtain sep' rs' where "rs = sep' # rs'" + by (cases rs) auto + moreover have "sep < sep'" + by (metis append_take_drop_id assms(2) calculation in_set_conv_decomp sorted_mid_iff sorted_snoc_iff split_half_ts(1) split_half_ts(2)) + moreover have "sorted_less rs" + by (metis append_take_drop_id assms(2) sorted_wrt_append split_half_ts(2)) + ultimately show ?thesis + using split_half_ts split_half_conc[of ks "ls@[sep]" rs] assms + by auto + qed + ultimately show ?thesis + using split_half_ts False by auto +qed simp + +lemma height_up\<^sub>i_merge: "height_up\<^sub>i (Up\<^sub>i 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_up\<^sub>i (ins k x t) = height t" +proof(induction k x t rule: ins.induct) + case (2 k x ts t) + then obtain ls rs where split_list: "split ts x = (ls,rs)" + by (meson surj_pair) + then have split_append: "ts = ls@rs" + using split_conc + by auto + then show ?case + proof (cases rs) + case Nil + then have height_sub: "height_up\<^sub>i (ins k x t) = height t" + using 2 by (simp add: split_list) + then show ?thesis + proof (cases "ins k x t") + case (T\<^sub>i a) + then have "height (Node ts t) = height (Node ts a)" + using height_sub + by simp + then show ?thesis + using T\<^sub>i Nil split_list split_append + by simp + next + case (Up\<^sub>i l a r) + then have "height (Node ls t) = height (Node (ls@[(l,a)]) r)" + using height_bplustree_order height_sub by (induction ls) auto + then show ?thesis using 2 Nil split_list Up\<^sub>i split_append + by (simp del: node\<^sub>i.simps add: node\<^sub>i_height) + qed + next + case (Cons a list) + then obtain sub sep where a_split: "a = (sub,sep)" + by (cases a) auto + then have height_sub: "height_up\<^sub>i (ins k x sub) = height sub" + by (metis "2.IH"(2) a_split Cons split_list) + then show ?thesis + proof (cases "ins k x sub") + case (T\<^sub>i a) + then have "height a = height sub" + using height_sub by auto + then have "height (Node (ls@(sub,sep)#rs) t) = height (Node (ls@(a,sep)#rs) t)" + by auto + then show ?thesis + using T\<^sub>i height_sub Cons 2 split_list a_split split_append + by (auto simp add: image_Un max.commute finite_set_ins_swap) + next + case (Up\<^sub>i l a r) + then have "height (Node (ls@(sub,sep)#list) t) = height (Node (ls@(l,a)#(r,sep)#list) t)" + using height_up\<^sub>i_merge height_sub + by fastforce + then show ?thesis + using Up\<^sub>i Cons 2 split_list a_split split_append + by (auto simp del: node\<^sub>i.simps simp add: node\<^sub>i_height image_Un max.commute finite_set_ins_swap) + 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_up\<^sub>i (ins k x t)" +proof(induction k x t rule: ins.induct) + case (2 k x ts t) + then obtain ls rs where split_res: "split ts x = (ls, rs)" + by (meson surj_pair) + then have split_app: "ts = ls@rs" + using split_conc + by fastforce + + show ?case + proof (cases rs) + case Nil + then show ?thesis + proof (cases "ins k x t") + case (T\<^sub>i a) + then have "bal (Node ls a)" unfolding bal.simps + by (metis "2.IH"(1) "2.prems" append_Nil2 bal.simps(2) bal_up\<^sub>i.simps(1) height_up\<^sub>i.simps(1) ins_height local.Nil split_app split_res) + then show ?thesis + using Nil T\<^sub>i 2 split_res + by simp + next + case (Up\<^sub>i l a r) + then have + "(\x\set (subtrees (ls@[(l,a)])). bal x)" + "(\x\set (subtrees ls). height r = height x)" + using 2 Up\<^sub>i Nil split_res split_app + by simp_all (metis height_up\<^sub>i.simps(2) ins_height max_def) + then show ?thesis unfolding ins.simps + using Up\<^sub>i Nil 2 split_res + by (simp del: node\<^sub>i.simps add: node\<^sub>i_bal) + qed + next + case (Cons a list) + then obtain sub sep where a_prod: "a = (sub, sep)" by (cases a) + then have "bal_up\<^sub>i (ins k x sub)" using 2 split_res + using a_prod local.Cons split_app by auto + show ?thesis + proof (cases "ins k x sub") + case (T\<^sub>i x1) + then have "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_up\<^sub>i.simps(1) ins_height local.Cons plus_1_eq_Suc split_app) + then show ?thesis + using split_app Cons T\<^sub>i 2 split_res a_prod + by auto + next + case (Up\<^sub>i l a r) + (* The only case where explicit reasoning is required - likely due to the insertion of 2 elements in the list *) + then have + "\x \ set (subtrees (ls@(l,a)#(r,sep)#list)). bal x" + using Up\<^sub>i split_app Cons 2 \bal_up\<^sub>i (ins k x sub)\ by auto + moreover have "\x \ set (subtrees (ls@(l,a)#(r,sep)#list)). height x = height t" + using Up\<^sub>i split_app Cons 2 \bal_up\<^sub>i (ins k x sub)\ ins_height split_res a_prod + apply auto + by (metis height_up\<^sub>i.simps(2) sup.idem sup_nat_def) + ultimately show ?thesis using Up\<^sub>i Cons 2 split_res a_prod + by (simp del: node\<^sub>i.simps add: node\<^sub>i_bal) + qed + qed +qed simp + +(* ins acts as ins_list wrt inorder *) + +(* "simple enough" to be automatically solved *) +lemma node\<^sub>i_leaves: "leaves_up\<^sub>i (node\<^sub>i k ts t) = leaves (Node ts t)" +proof (cases "length ts \ 2*k") + case False + then obtain ls sub sep rs where + split_half_ts: "split_half ts = (ls@[(sub,sep)], rs)" + by (meson node\<^sub>i_cases) + then have "leaves_up\<^sub>i (node\<^sub>i k ts t) = leaves_list ls @ leaves sub @ leaves_list rs @ leaves t" + using False by auto + also have "\ = leaves (Node ts t)" + using split_half_ts split_half_conc[of ts "ls@[(sub,sep)]" rs] by auto + finally show ?thesis. +qed simp + +corollary node\<^sub>i_leaves_simps: + "node\<^sub>i k ts t = T\<^sub>i t' \ leaves t' = leaves (Node ts t)" + "node\<^sub>i k ts t = Up\<^sub>i l a r \ leaves l @ leaves r = leaves (Node ts t)" + apply (metis leaves_up\<^sub>i.simps(1) node\<^sub>i_leaves) + by (metis leaves_up\<^sub>i.simps(2) node\<^sub>i_leaves) + +lemma Lnode\<^sub>i_leaves: "leaves_up\<^sub>i (Lnode\<^sub>i k xs) = leaves (Leaf xs)" +proof (cases "length xs \ 2*k") + case False + then obtain ls sub sep rs where + split_half_ts: "split_half xs = (ls@[sep], rs)" + by (meson Lnode\<^sub>i_cases) + then have "leaves_up\<^sub>i (Lnode\<^sub>i k xs) = ls @ sep # rs" + using False by auto + also have "\ = leaves (Leaf xs)" + using split_half_ts split_half_conc[of xs "ls@[sep]" rs] by auto + finally show ?thesis. +qed simp + +corollary Lnode\<^sub>i_leaves_simps: + "Lnode\<^sub>i k xs = T\<^sub>i t \ leaves t = leaves (Leaf xs)" + "Lnode\<^sub>i k xs = Up\<^sub>i l a r \ leaves l @ leaves r = leaves (Leaf xs)" + apply (metis leaves_up\<^sub>i.simps(1) Lnode\<^sub>i_leaves) + by (metis leaves_up\<^sub>i.simps(2) Lnode\<^sub>i_leaves) + + + +(* 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 "Laligned (Node ts t) u" + and "sorted_less (leaves (Node ts t))" + and "split ts x = (ls, rs)" + shows "ins_list x (leaves (Node ts t)) = leaves_list ls @ ins_list x (leaves_list rs @ leaves t)" +proof (cases ls) + case Nil + then show ?thesis + using assms by (auto dest!: split_conc) +next + case Cons + then obtain ls' sub sep where ls_tail_split: "ls = ls' @ [(sub,sep)]" + by (metis list.distinct(1) rev_exhaust surj_pair) + have sorted_inorder: "sorted_less (inorder (Node ts t))" + using Laligned_sorted_inorder assms(1) sorted_cons sorted_snoc by blast + moreover have x_sm_sep: "sep < x" + using split_req(2)[of ts x ls' sub sep rs] + using sorted_inorder_separators[of ts t] sorted_inorder + using assms ls_tail_split + by auto + moreover have leaves_split: "leaves (Node ts t) = leaves_list ls @ leaves_list rs @ leaves t" + using assms(3) split_tree.leaves_split by blast + then show ?thesis + proof (cases "leaves_list ls") + case Nil + then show ?thesis + by (metis append_self_conv2 leaves_split) + next + case Cons + then obtain leavesls' l' where leaves_tail_split: "leaves_list ls = leavesls' @ [l']" + by (metis list.simps(3) rev_exhaust) + then have "l' \ sep" + proof - + have "l' \ set (leaves_list ls)" + using leaves_tail_split by force + then have "l' \ set (leaves (Node ls' sub))" + using ls_tail_split + by auto + moreover have "Laligned (Node ls' sub) sep" + using assms split_conc[OF assms(3)] Cons ls_tail_split + using Laligned_split_left[of ls' sub sep rs t u] + by simp + ultimately show ?thesis + using Laligned_leaves_inbetween[of "Node ls' sub" sep] + by blast + qed + moreover have "sorted_less (leaves_list ls)" + using assms(2) leaves_split sorted_wrt_append by auto + ultimately show ?thesis + using assms(2) ls_tail_split leaves_tail_split leaves_split x_sm_sep + using ins_list_sorted[of leavesls' l' x "leaves_list rs@leaves t"] + by auto + qed +qed + +lemma ins_list_split_right: + assumes "split ts x = (ls, (sub,sep)#rs)" + and "sorted_less (leaves (Node ts t))" + and "Laligned (Node ts t) u" + shows "ins_list x (leaves_list ((sub,sep)#rs) @ leaves t) = ins_list x (leaves sub) @ leaves_list rs @ leaves t" +proof - + from assms have x_sm_sep: "x \ sep" + proof - + from assms have "sorted_less (separators ts)" + using Laligned_sorted_separators sorted_cons sorted_snoc by blast + then show ?thesis + using split_req(3) + using assms + by blast + qed + then show ?thesis + proof (cases "leaves_list rs @ leaves t") + case Nil + moreover have "leaves_list ((sub,sep)#rs) @ leaves t = leaves sub @ leaves_list rs @ leaves t" + by simp + ultimately show ?thesis + by (metis self_append_conv) + next + case (Cons r' rs') + then have "sep < r'" + by (metis aligned_leaves_inbetween Laligned_split_right assms(1) assms(3) leaves.simps(2) list.set_intros(1) split_set.split_conc split_set_axioms) + then have "x < r'" + using \x \ sep\ by auto + moreover have "sorted_less (leaves sub @ [r'])" + proof - + have "sorted_less (leaves_list ls @ leaves sub @ leaves_list rs @ leaves t)" + using assms(1) assms(2) split_tree.leaves_split split_set_axioms by fastforce + then show ?thesis + using assms + by (metis Cons sorted_mid_iff sorted_wrt_append) + qed + ultimately show ?thesis + using ins_list_sorted[of "leaves sub" r' x rs'] Cons + by auto + qed +qed + + +(* 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 aligned_insert_list: "sorted_less ks \ l < x \ x \ u \ aligned l (Leaf ks) u \ aligned l (Leaf (insert_list x ks)) u" + using insert_list_req + by (simp add: set_ins_list) + +lemma align_subst_two: "aligned l (Node (ts@[(sub,sep)]) t) u \ aligned sep lt a \ aligned a rt u \ aligned l (Node (ts@[(sub,sep),(lt,a)]) rt) u" + apply(induction ts arbitrary: l) + apply auto + done + +lemma align_subst_three: "aligned l (Node (ls@(subl,sepl)#(subr,sepr)#rs) t) u \ aligned sepl lt a \ aligned a rt sepr \ aligned l (Node (ls@(subl,sepl)#(lt,a)#(rt,sepr)#rs) t) u" + apply(induction ls arbitrary: l) + apply auto + done + + +declare node\<^sub>i.simps [simp del] +declare node\<^sub>i_leaves [simp add] + +lemma ins_inorder: + assumes "k > 0" + and "aligned l t u" + and "sorted_less (leaves t)" + and "root_order k t" + and "l < x" "x \ u" + shows "(leaves_up\<^sub>i (ins k x t)) = ins_list x (leaves t) \ aligned_up\<^sub>i l (ins k x t) u" + using assms +proof(induction k x t arbitrary: l u rule: ins.induct) + case (1 k x ks) + then show ?case + proof (safe, goal_cases) + case _: 1 + then show ?case + using 1 insert_list_req by auto + next + case 2 + from 1 have "aligned l (Leaf (insert_list x ks)) u" + by (metis aligned_insert_list leaves.simps(1)) + moreover have "sorted_less (insert_list x ks)" + using "1.prems"(3) split_set.insert_list_req split_set_axioms + by auto + ultimately show ?case + using Lnode\<^sub>i_aligned[of l "insert_list x ks" u k] 1 + by (auto simp del: Lnode\<^sub>i.simps split_half.simps) + qed +next + case (2 k x ts t) + then obtain ls rs where list_split: "split ts x = (ls,rs)" + by (cases "split ts x") + then have list_conc: "ts = ls@rs" + using split_set.split_conc split_set_axioms by blast + then show ?case + proof (cases rs) + case Nil + then obtain ts' sub' sep' where "ts = ts'@[(sub',sep')]" + apply(cases ts) + using 2 list_conc Nil apply(simp) + by (metis isin.cases list.distinct(1) rev_exhaust) + have IH: "leaves_up\<^sub>i (ins k x t) = ins_list x (leaves t) \ aligned_up\<^sub>i sep' (ins k x t) u" + proof - + (* we need to fulfill all these IH requirements *) + note "2.IH"(1)[OF sym[OF list_split] Nil "2.prems"(1), of sep' u] + have "sorted_less (leaves t)" + using "2.prems"(3) sorted_leaves_induct_last by blast + moreover have "sep' < x" + using split_req[of ts x] list_split + by (metis "2.prems"(2) \ts = ts' @ [(sub', sep')]\ aligned_sorted_separators local.Nil self_append_conv sorted_cons sorted_snoc) + moreover have "aligned sep' t u" + using "2.prems"(2) \ts = ts' @ [(sub', sep')]\ align_last by blast + ultimately show ?thesis + using "2.IH"(1)[OF sym[OF list_split] Nil "2.prems"(1), of sep' u] + using "2.prems" list_split local.Nil sorted_leaves_induct_last + using order_impl_root_order + by auto + qed + show ?thesis + proof (cases "ins k x t") + case (T\<^sub>i a) + have IH: "leaves a = ins_list x (leaves t) \ aligned sep' a u" + using IH T\<^sub>i by force + show ?thesis + proof(safe, goal_cases) + case 1 + have "leaves_up\<^sub>i (ins k x (Node ts t)) = leaves_list ls @ leaves a" + using list_split T\<^sub>i Nil by (auto simp add: list_conc) + also have "\ = leaves_list ls @ (ins_list x (leaves t))" + by (simp add: IH) + also have "\ = ins_list x (leaves (Node ts t))" + using ins_list_split + using "2.prems" list_split Nil + by (metis aligned_imp_Laligned append_self_conv2 concat.simps(1) list.simps(8)) + finally show ?case . + next + case 2 + have "aligned_up\<^sub>i l (ins k x (Node ts t)) u = aligned l (Node ts a) u" + using Nil T\<^sub>i list_split list_conc by simp + moreover have "aligned l (Node ts a) u" + using "2.prems"(2) + by (metis IH \ts = ts' @ [(sub', sep')]\ aligned_subst_last) + ultimately show ?case + by auto + qed + next + case (Up\<^sub>i lt a rt) + then have IH:"leaves_up\<^sub>i (Up\<^sub>i lt a rt) = ins_list x (leaves t) \ aligned_up\<^sub>i sep' (Up\<^sub>i lt a rt) u" + using IH by auto + + show ?thesis + proof (safe, goal_cases) + case 1 + have "leaves_up\<^sub>i (ins k x (Node ts t)) = leaves_list ls @ leaves_up\<^sub>i (Up\<^sub>i lt a rt)" + using list_split Up\<^sub>i Nil by (auto simp add: list_conc) + also have "\ = leaves_list ls @ ins_list x (leaves t)" + using IH by simp + also have "\ = ins_list x (leaves (Node ts t))" + using ins_list_split + using "2.prems" list_split local.Nil + by (metis aligned_imp_Laligned append_self_conv2 concat.simps(1) list.simps(8)) + finally show ?case. + next + case 2 + have "aligned_up\<^sub>i l (ins k x (Node ts t)) u = aligned_up\<^sub>i l (node\<^sub>i k (ts @ [(lt, a)]) rt) u" + using Nil Up\<^sub>i list_split list_conc node\<^sub>i_aligned by simp + moreover have "aligned l (Node (ts@[(lt,a)]) rt) u" + using "2.prems"(2) IH \ts = ts' @ [(sub', sep')]\ align_subst_two by fastforce + ultimately show ?case + using node\<^sub>i_aligned + by auto + qed + qed + next + case (Cons h list) + then obtain sub sep where h_split: "h = (sub,sep)" + by (cases h) + + then have sorted_inorder_sub: "sorted_less (leaves sub)" + using "2.prems" list_conc Cons sorted_leaves_induct_subtree + by fastforce + moreover have order_sub: "order k sub" + using "2.prems" list_conc Cons h_split + by auto + then show ?thesis +(* TODO way to show this cleanly without distinguishing cases for ls? *) + proof (cases ls) + case Nil + then have aligned_sub: "aligned l sub sep" + using "2.prems"(2) list_conc h_split Cons + by auto + then have IH: "leaves_up\<^sub>i (ins k x sub) = ins_list x (leaves sub) \ aligned_up\<^sub>i l (ins k x sub) sep" + proof - + have "x \ sep" + using "2.prems"(2) aligned_sorted_separators h_split list_split local.Cons sorted_cons sorted_snoc split_set.split_req(3) split_set_axioms + by blast + then show ?thesis + using "2.IH"(2)[OF sym[OF list_split] Cons sym[OF h_split], of l sep] + using "2.prems" list_split local.Nil aligned_sub sorted_inorder_sub order_sub + using order_impl_root_order + by auto + qed + then show ?thesis + proof (cases "ins k x sub") + case (T\<^sub>i a) + have IH:"leaves a = ins_list x (leaves sub) \ aligned l a sep" + using T\<^sub>i IH by (auto) + show ?thesis + proof (safe, goal_cases) + case 1 + have "leaves_up\<^sub>i (ins k x (Node ts t)) = leaves_list ls @ leaves a @ leaves_list list @ leaves t" + using h_split list_split T\<^sub>i Cons by simp + also have "\ = leaves_list ls @ ins_list x (leaves sub) @ leaves_list list @ leaves t" + using IH by simp + also have "\ = ins_list x (leaves (Node ts t))" + using ins_list_split ins_list_split_right + using list_split "2.prems" Cons h_split + by (metis aligned_imp_Laligned) + finally show ?case. + next + case 2 + have "aligned_up\<^sub>i l (ins k x (Node ts t)) u = aligned l (Node ((a,sep)#list) t) u" + using Nil Cons list_conc list_split h_split T\<^sub>i by simp + moreover have "aligned l (Node ((a,sep)#list) t) u" + using aligned_sub "2.prems"(2) IH h_split list_conc Cons Nil + by auto + ultimately show ?case + by auto + qed + next + case (Up\<^sub>i lt a rt) + then have IH:"leaves_up\<^sub>i (Up\<^sub>i lt a rt) = ins_list x (leaves sub) \ aligned_up\<^sub>i l (Up\<^sub>i lt a rt) sep" + using IH h_split list_split Cons sorted_inorder_sub + by auto + show ?thesis + proof (safe, goal_cases) + case 1 + have "leaves_up\<^sub>i (ins k x (Node ts t)) = leaves_list ls @ leaves lt @ leaves rt @ leaves_list list @ leaves t" + using h_split list_split Up\<^sub>i Cons by simp + also have "\ = leaves_list ls @ ins_list x (leaves sub) @ leaves_list list @ leaves t" + using IH by simp + also have "\ = ins_list x (leaves (Node ts t))" + using ins_list_split ins_list_split_right + using list_split "2.prems" Cons h_split + by (metis aligned_imp_Laligned) + finally show ?case. + next + case 2 + have "aligned_up\<^sub>i l (ins k x (Node ts t)) u = aligned_up\<^sub>i l (node\<^sub>i k ((lt,a)#(rt,sep)#list) t) u" + using Nil Cons list_conc list_split h_split Up\<^sub>i by simp + moreover have "aligned l (Node ((lt,a)#(rt,sep)#list) t) u" + using aligned_sub "2.prems"(2) IH h_split list_conc Cons Nil + by auto + ultimately show ?case + using node\<^sub>i_aligned by auto + qed + qed + next + case ls_split': Cons + then obtain ls' sub' sep' where ls_split: "ls = ls'@[(sub',sep')]" + by (metis list.discI old.prod.exhaust snoc_eq_iff_butlast) + then have aligned_sub: "aligned sep' sub sep" + using "2.prems"(2) list_conc h_split Cons + using align_last aligned_split_left by blast + then have IH: "leaves_up\<^sub>i (ins k x sub) = ins_list x (leaves sub) \ aligned_up\<^sub>i sep' (ins k x sub) sep" + proof - + have "x \ sep" + using "2.prems"(2) aligned_sorted_separators h_split list_split local.Cons sorted_cons sorted_snoc split_set.split_req(3) split_set_axioms + by blast + moreover have "sep' < x" + using "2.prems"(2) aligned_sorted_separators list_split ls_split sorted_cons sorted_snoc split_set.split_req(2) split_set_axioms + by blast + ultimately show ?thesis + using "2.IH"(2)[OF sym[OF list_split] Cons sym[OF h_split], of sep' sep] + using "2.prems" list_split ls_split aligned_sub sorted_inorder_sub order_sub + using order_impl_root_order + by auto + qed + then show ?thesis + proof (cases "ins k x sub") + case (T\<^sub>i a) + have IH:"leaves a = ins_list x (leaves sub) \ aligned sep' a sep" + using T\<^sub>i IH by (auto) + show ?thesis + proof (safe, goal_cases) + case 1 + have "leaves_up\<^sub>i (ins k x (Node ts t)) = leaves_list ls @ leaves a @ leaves_list list @ leaves t" + using h_split list_split T\<^sub>i Cons by simp + also have "\ = leaves_list ls @ ins_list x (leaves sub) @ leaves_list list @ leaves t" + using IH by simp + also have "\ = ins_list x (leaves (Node ts t))" + using ins_list_split ins_list_split_right + using list_split "2.prems" Cons h_split + by (metis aligned_imp_Laligned) + finally show ?case. + next + case 2 + have "aligned_up\<^sub>i l (ins k x (Node ts t)) u = aligned l (Node (ls'@(sub',sep')#(a,sep)#list) t) u" + using Nil Cons list_conc list_split h_split T\<^sub>i ls_split by simp + moreover have "aligned l (Node (ls'@(sub',sep')#(a,sep)#list) t) u" + using aligned_sub "2.prems"(2) IH h_split list_conc Cons Nil ls_split + using aligned_subst by fastforce + ultimately show ?case + by auto + qed + next + case (Up\<^sub>i lt a rt) + then have IH:"leaves_up\<^sub>i (Up\<^sub>i lt a rt) = ins_list x (leaves sub) \ aligned_up\<^sub>i sep' (Up\<^sub>i lt a rt) sep" + using IH h_split list_split Cons sorted_inorder_sub + by auto + show ?thesis + proof (safe, goal_cases) + case 1 + have "leaves_up\<^sub>i (ins k x (Node ts t)) = leaves_list ls @ leaves lt @ leaves rt @ leaves_list list @ leaves t" + using h_split list_split Up\<^sub>i Cons by simp + also have "\ = leaves_list ls @ ins_list x (leaves sub) @ leaves_list list @ leaves t" + using IH by simp + also have "\ = ins_list x (leaves (Node ts t))" + using ins_list_split ins_list_split_right + using list_split "2.prems" Cons h_split + by (metis aligned_imp_Laligned) + finally show ?case. + next + case 2 + have "aligned_up\<^sub>i l (ins k x (Node ts t)) u = aligned_up\<^sub>i l (node\<^sub>i k (ls'@(sub',sep')#(lt,a)#(rt,sep)#list) t) u" + using Nil Cons list_conc list_split h_split Up\<^sub>i ls_split by simp + moreover have "aligned l (Node (ls'@(sub',sep')#(lt,a)#(rt,sep)#list) t) u" + using aligned_sub "2.prems"(2) IH h_split list_conc Cons Nil ls_split align_subst_three + by auto + ultimately show ?case + using node\<^sub>i_aligned by auto + qed + qed + qed + qed +qed + +declare node\<^sub>i.simps [simp add] +declare node\<^sub>i_leaves [simp del] + +lemma Laligned_insert_list: "sorted_less ks \ x \ u \ Laligned (Leaf ks) u \ Laligned (Leaf (insert_list x ks)) u" + using insert_list_req + by (simp add: set_ins_list) + +lemma Lalign_subst_two: "Laligned (Node (ts@[(sub,sep)]) t) u \ aligned sep lt a \ aligned a rt u \ Laligned (Node (ts@[(sub,sep),(lt,a)]) rt) u" + apply(induction ts) + apply (auto) + by (meson align_subst_two aligned.simps(2)) + +lemma Lalign_subst_three: "Laligned (Node (ls@(subl,sepl)#(subr,sepr)#rs) t) u \ aligned sepl lt a \ aligned a rt sepr \ Laligned (Node (ls@(subl,sepl)#(lt,a)#(rt,sepr)#rs) t) u" + apply(induction ls) + apply auto + by (meson align_subst_three aligned.simps(2)) + +lemma Lnode\<^sub>i_Laligned: + assumes "Laligned (Leaf ks) u" + and "sorted_less ks" + and "k > 0" + shows "Laligned_up\<^sub>i (Lnode\<^sub>i k ks) u" + using assms +proof (cases "length ks \ 2*k") + case False + then obtain ls sep rs where split_half_ts: + "take ((length ks + 1) div 2) ks = ls@[sep]" + "drop ((length ks + 1) div 2) ks = rs" + using split_half_not_empty[of ks] + by auto + moreover have "sorted_less (ls@[sep])" + by (metis append_take_drop_id assms(2) sorted_wrt_append split_half_ts(1)) + ultimately have "Laligned (Leaf (ls@[sep])) sep" + using split_half_conc[of ks "ls@[sep]" rs] assms sorted_snoc_iff[of ls sep] + by auto + moreover have "aligned sep (Leaf rs) u" + proof - + have "length rs > 0" + using False assms(3) split_half_ts(2) by fastforce + then obtain sep' rs' where "rs = sep' # rs'" + by (cases rs) auto + moreover have "sep < sep'" + by (metis append_take_drop_id assms(2) calculation in_set_conv_decomp sorted_mid_iff sorted_snoc_iff split_half_ts(1) split_half_ts(2)) + moreover have "sorted_less rs" + by (metis append_take_drop_id assms(2) sorted_wrt_append split_half_ts(2)) + ultimately show ?thesis + using split_half_ts split_half_conc[of ks "ls@[sep]" rs] assms + by auto + qed + ultimately show ?thesis + using split_half_ts False by auto +qed simp + +declare node\<^sub>i.simps [simp del] +declare node\<^sub>i_leaves [simp add] + +lemma ins_Linorder: + assumes "k > 0" + and "Laligned t u" + and "sorted_less (leaves t)" + and "root_order k t" + and "x \ u" + shows "(leaves_up\<^sub>i (ins k x t)) = ins_list x (leaves t) \ Laligned_up\<^sub>i (ins k x t) u" + using assms +proof(induction k x t arbitrary: u rule: ins.induct) + case (1 k x ks) + then show ?case + proof (safe, goal_cases) + case _: 1 + then show ?case + using 1 insert_list_req by auto + next + case 2 + from 1 have "Laligned (Leaf (insert_list x ks)) u" + by (metis Laligned_insert_list leaves.simps(1)) + moreover have "sorted_less (insert_list x ks)" + using "1.prems"(3) split_set.insert_list_req split_set_axioms + by auto + ultimately show ?case + using Lnode\<^sub>i_Laligned[of "insert_list x ks" u k] 1 + by (auto simp del: Lnode\<^sub>i.simps split_half.simps) + qed +next + case (2 k x ts t) + then obtain ls rs where list_split: "split ts x = (ls,rs)" + by (cases "split ts x") + then have list_conc: "ts = ls@rs" + using split_set.split_conc split_set_axioms by blast + then show ?case + proof (cases rs) + case Nil + then obtain ts' sub' sep' where "ts = ts'@[(sub',sep')]" + apply(cases ts) + using 2 list_conc Nil apply(simp) + by (metis isin.cases list.distinct(1) rev_exhaust) + have IH: "leaves_up\<^sub>i (ins k x t) = ins_list x (leaves t) \ aligned_up\<^sub>i sep' (ins k x t) u" +(* this is now a case covered by the previous proof *) + proof - + (* we need to fulfill all these IH requirements *) + note ins_inorder[of k] + have "sorted_less (leaves t)" + using "2.prems"(3) sorted_leaves_induct_last by blast + moreover have "sep' < x" + using split_req[of ts x] list_split + by (metis "2.prems"(2) Laligned_sorted_separators \ts = ts' @ [(sub', sep')]\ local.Nil self_append_conv sorted_snoc) + moreover have "aligned sep' t u" + using "2.prems"(2) Lalign_last \ts = ts' @ [(sub', sep')]\ by blast + ultimately show ?thesis + by (meson "2.prems"(1) "2.prems"(4) "2.prems"(5) ins_inorder order_impl_root_order root_order.simps(2)) + qed + show ?thesis + proof (cases "ins k x t") + case (T\<^sub>i a) + have IH: "leaves a = ins_list x (leaves t) \ aligned sep' a u" + using IH T\<^sub>i by force + show ?thesis + proof(safe, goal_cases) + case 1 + have "leaves_up\<^sub>i (ins k x (Node ts t)) = leaves_list ls @ leaves a" + using list_split T\<^sub>i Nil by (auto simp add: list_conc) + also have "\ = leaves_list ls @ (ins_list x (leaves t))" + by (simp add: IH) + also have "\ = ins_list x (leaves (Node ts t))" + using ins_list_split + using "2.prems" list_split Nil + by auto + finally show ?case . + next + case 2 + have "Laligned_up\<^sub>i (ins k x (Node ts t)) u = Laligned (Node ts a) u" + using Nil T\<^sub>i list_split list_conc by simp + moreover have "Laligned (Node ts a) u" + using "2.prems"(2) + by (metis IH \ts = ts' @ [(sub', sep')]\ Laligned_subst_last) + ultimately show ?case + by auto + qed + next + case (Up\<^sub>i lt a rt) + then have IH:"leaves_up\<^sub>i (Up\<^sub>i lt a rt) = ins_list x (leaves t) \ aligned_up\<^sub>i sep' (Up\<^sub>i lt a rt) u" + using IH by auto + + show ?thesis + proof (safe, goal_cases) + case 1 + have "leaves_up\<^sub>i (ins k x (Node ts t)) = leaves_list ls @ leaves_up\<^sub>i (Up\<^sub>i lt a rt)" + using list_split Up\<^sub>i Nil by (auto simp add: list_conc) + also have "\ = leaves_list ls @ ins_list x (leaves t)" + using IH by simp + also have "\ = ins_list x (leaves (Node ts t))" + using ins_list_split + using "2.prems" list_split local.Nil by auto + finally show ?case. + next + case 2 + have "Laligned_up\<^sub>i (ins k x (Node ts t)) u = Laligned_up\<^sub>i (node\<^sub>i k (ts @ [(lt, a)]) rt) u" + using Nil Up\<^sub>i list_split list_conc node\<^sub>i_aligned by simp + moreover have "Laligned (Node (ts@[(lt,a)]) rt) u" + using "2.prems"(2) IH \ts = ts' @ [(sub', sep')]\ Lalign_subst_two by fastforce + ultimately show ?case + using node\<^sub>i_Laligned + by auto + qed + qed + next + case (Cons h list) + then obtain sub sep where h_split: "h = (sub,sep)" + by (cases h) + + then have sorted_inorder_sub: "sorted_less (leaves sub)" + using "2.prems" list_conc Cons sorted_leaves_induct_subtree + by fastforce + moreover have order_sub: "order k sub" + using "2.prems" list_conc Cons h_split + by auto + then show ?thesis +(* TODO way to show this cleanly without distinguishing cases for ls? *) + proof (cases ls) + case Nil + then have aligned_sub: "Laligned sub sep" + using "2.prems"(2) list_conc h_split Cons + by auto + then have IH: "leaves_up\<^sub>i (ins k x sub) = ins_list x (leaves sub) \ Laligned_up\<^sub>i (ins k x sub) sep" + proof - + have "x \ sep" + using "2.prems"(2) Laligned_sorted_separators h_split list_split local.Cons sorted_snoc split_set.split_req(3) split_set_axioms + by blast + then show ?thesis + using "2.IH"(2)[OF sym[OF list_split] Cons sym[OF h_split], of sep] + using "2.prems" list_split local.Nil aligned_sub sorted_inorder_sub order_sub + using order_impl_root_order + by auto + qed + then show ?thesis + proof (cases "ins k x sub") + case (T\<^sub>i a) + have IH:"leaves a = ins_list x (leaves sub) \ Laligned a sep" + using T\<^sub>i IH by (auto) + show ?thesis + proof (safe, goal_cases) + case 1 + have "leaves_up\<^sub>i (ins k x (Node ts t)) = leaves_list ls @ leaves a @ leaves_list list @ leaves t" + using h_split list_split T\<^sub>i Cons by simp + also have "\ = leaves_list ls @ ins_list x (leaves sub) @ leaves_list list @ leaves t" + using IH by simp + also have "\ = ins_list x (leaves (Node ts t))" + using ins_list_split ins_list_split_right + using list_split "2.prems" Cons h_split by auto + finally show ?case. + next + case 2 + have "Laligned_up\<^sub>i (ins k x (Node ts t)) u = Laligned (Node ((a,sep)#list) t) u" + using Nil Cons list_conc list_split h_split T\<^sub>i by simp + moreover have "Laligned (Node ((a,sep)#list) t) u" + using aligned_sub "2.prems"(2) IH h_split list_conc Cons Nil + by auto + ultimately show ?case + by auto + qed + next + case (Up\<^sub>i lt a rt) + then have IH:"leaves_up\<^sub>i (Up\<^sub>i lt a rt) = ins_list x (leaves sub) \ Laligned_up\<^sub>i (Up\<^sub>i lt a rt) sep" + using IH h_split list_split Cons sorted_inorder_sub + by auto + show ?thesis + proof (safe, goal_cases) + case 1 + have "leaves_up\<^sub>i (ins k x (Node ts t)) = leaves_list ls @ leaves lt @ leaves rt @ leaves_list list @ leaves t" + using h_split list_split Up\<^sub>i Cons by simp + also have "\ = leaves_list ls @ ins_list x (leaves sub) @ leaves_list list @ leaves t" + using IH by simp + also have "\ = ins_list x (leaves (Node ts t))" + using ins_list_split ins_list_split_right + using list_split "2.prems" Cons h_split by auto + finally show ?case. + next + case 2 + have "Laligned_up\<^sub>i (ins k x (Node ts t)) u = Laligned_up\<^sub>i (node\<^sub>i k ((lt,a)#(rt,sep)#list) t) u" + using Nil Cons list_conc list_split h_split Up\<^sub>i by simp + moreover have "Laligned (Node ((lt,a)#(rt,sep)#list) t) u" + using aligned_sub "2.prems"(2) IH h_split list_conc Cons Nil + by auto + ultimately show ?case + using node\<^sub>i_Laligned by auto + qed + qed + next + case ls_split': Cons + then obtain ls' sub' sep' where ls_split: "ls = ls'@[(sub',sep')]" + by (metis list.discI old.prod.exhaust snoc_eq_iff_butlast) + then have aligned_sub: "aligned sep' sub sep" + using "2.prems"(2) list_conc h_split Cons + using Lalign_last Laligned_split_left + by blast + then have IH: "leaves_up\<^sub>i (ins k x sub) = ins_list x (leaves sub) \ aligned_up\<^sub>i sep' (ins k x sub) sep" + proof - + have "x \ sep" + using "2.prems"(2) Laligned_sorted_separators h_split list_split local.Cons sorted_snoc split_set.split_req(3) split_set_axioms + by blast + moreover have "sep' < x" + using "2.prems"(2) Laligned_sorted_separators list_split ls_split sorted_cons sorted_snoc split_set.split_req(2) split_set_axioms + by blast + ultimately show ?thesis + using "2.prems"(1) aligned_sub ins_inorder order_sub sorted_inorder_sub + using order_impl_root_order + by blast + qed + then show ?thesis + proof (cases "ins k x sub") + case (T\<^sub>i a) + have IH:"leaves a = ins_list x (leaves sub) \ aligned sep' a sep" + using T\<^sub>i IH by (auto) + show ?thesis + proof (safe, goal_cases) + case 1 + have "leaves_up\<^sub>i (ins k x (Node ts t)) = leaves_list ls @ leaves a @ leaves_list list @ leaves t" + using h_split list_split T\<^sub>i Cons by simp + also have "\ = leaves_list ls @ ins_list x (leaves sub) @ leaves_list list @ leaves t" + using IH by simp + also have "\ = ins_list x (leaves (Node ts t))" + using ins_list_split ins_list_split_right + using list_split "2.prems" Cons h_split by auto + finally show ?case. + next + case 2 + have "Laligned_up\<^sub>i (ins k x (Node ts t)) u = Laligned (Node (ls'@(sub',sep')#(a,sep)#list) t) u" + using Nil Cons list_conc list_split h_split T\<^sub>i ls_split by simp + moreover have "Laligned (Node (ls'@(sub',sep')#(a,sep)#list) t) u" + using aligned_sub "2.prems"(2) IH h_split list_conc Cons Nil ls_split + using Laligned_subst by fastforce + ultimately show ?case + by auto + qed + next + case (Up\<^sub>i lt a rt) + then have IH:"leaves_up\<^sub>i (Up\<^sub>i lt a rt) = ins_list x (leaves sub) \ aligned_up\<^sub>i sep' (Up\<^sub>i lt a rt) sep" + using IH h_split list_split Cons sorted_inorder_sub + by auto + show ?thesis + proof (safe, goal_cases) + case 1 + have "leaves_up\<^sub>i (ins k x (Node ts t)) = leaves_list ls @ leaves lt @ leaves rt @ leaves_list list @ leaves t" + using h_split list_split Up\<^sub>i Cons by simp + also have "\ = leaves_list ls @ ins_list x (leaves sub) @ leaves_list list @ leaves t" + using IH by simp + also have "\ = ins_list x (leaves (Node ts t))" + using ins_list_split ins_list_split_right + using list_split "2.prems" Cons h_split by auto + finally show ?case. + next + case 2 + have "Laligned_up\<^sub>i (ins k x (Node ts t)) u = Laligned_up\<^sub>i (node\<^sub>i k (ls'@(sub',sep')#(lt,a)#(rt,sep)#list) t) u" + using Nil Cons list_conc list_split h_split Up\<^sub>i ls_split by simp + moreover have "Laligned (Node (ls'@(sub',sep')#(lt,a)#(rt,sep)#list) t) u" + using aligned_sub "2.prems"(2) IH h_split list_conc Cons Nil ls_split Lalign_subst_three + by auto + ultimately show ?case + using node\<^sub>i_Laligned by auto + qed + qed + qed + qed +qed + +declare node\<^sub>i.simps [simp add] +declare node\<^sub>i_leaves [simp del] + + +thm ins.induct +thm bplustree.induct + +(* wrapped up insert invariants *) + +lemma tree\<^sub>i_bal: "bal_up\<^sub>i u \ bal (tree\<^sub>i u)" + apply(cases u) + apply(auto) + done + +lemma tree\<^sub>i_order: "\k > 0; root_order_up\<^sub>i k u\ \ root_order k (tree\<^sub>i u)" + apply(cases u) + apply(auto simp add: order_impl_root_order) + done + +lemma tree\<^sub>i_inorder: "inorder_up\<^sub>i u = inorder (tree\<^sub>i u)" + apply (cases u) + apply auto + done + +lemma tree\<^sub>i_leaves: "leaves_up\<^sub>i u = leaves (tree\<^sub>i u)" + apply (cases u) + apply auto + done + +lemma tree\<^sub>i_aligned: "aligned_up\<^sub>i l a u \ aligned l (tree\<^sub>i a) u" + apply (cases a) + apply auto + done + +lemma tree\<^sub>i_Laligned: "Laligned_up\<^sub>i a u \ Laligned (tree\<^sub>i a) u" + apply (cases a) + apply auto + done + +lemma insert_bal: "bal t \ bal (insert k x t)" + using ins_bal + by (simp add: tree\<^sub>i_bal) + +lemma insert_order: "\k > 0; sorted_less (leaves t); root_order k t\ \ root_order k (insert k x t)" + using ins_root_order + by (simp add: tree\<^sub>i_order) + + +lemma insert_inorder: + assumes "k > 0" "root_order k t" "sorted_less (leaves t)" "aligned l t u" "l < x" "x \ u" + shows "leaves (insert k x t) = ins_list x (leaves t)" + and "aligned l (insert k x t) u" + using ins_inorder assms + by (simp_all add: tree\<^sub>i_leaves tree\<^sub>i_aligned) + +lemma insert_Linorder: + assumes "k > 0" "root_order k t" "sorted_less (leaves t)" "Laligned t u" "x \ u" + shows "leaves (insert k x t) = ins_list x (leaves t)" + and "Laligned (insert k x t) u" + using ins_Linorder insert_inorder assms + by (simp_all add: tree\<^sub>i_leaves tree\<^sub>i_Laligned) + +corollary insert_Linorder_top: + assumes "k > 0" "root_order k t" "sorted_less (leaves t)" "Laligned t top" + shows "leaves (insert k x t) = ins_list x (leaves t)" + and "Laligned (insert k x t) top" + using insert_Linorder top_greatest assms by simp_all + +subsection "Deletion" + +text "The following deletion method is inspired by Bauer (70) and Fielding (??). +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 ms) sep rs (Leaf ts) = ( + if length ms \ k \ length ts \ k then + Node (ls@(Leaf ms,sep)#rs) (Leaf ts) + else ( + case rs of [] \ ( + case Lnode\<^sub>i k (ms@ts) of + T\<^sub>i u \ + Node ls u | + Up\<^sub>i l a r \ + Node (ls@[(l,a)]) r) | + (Leaf rrs,rsep)#rs \ ( + case Lnode\<^sub>i k (ms@rrs) of + T\<^sub>i u \ + Node (ls@(u,rsep)#rs) (Leaf ts) | + Up\<^sub>i l a r \ + Node (ls@(l,a)#(r,rsep)#rs) (Leaf ts)) +))" | + "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 node\<^sub>i k (mts@(mt,sep)#tts) tt of + T\<^sub>i u \ + Node ls u | + Up\<^sub>i l a r \ + Node (ls@[(l,a)]) r) | + (Node rts rt,rsep)#rs \ ( + case node\<^sub>i k (mts@(mt,sep)#rts) rt of + T\<^sub>i u \ + Node (ls@(u,rsep)#rs) (Node tts tt) | + Up\<^sub>i l a r \ + Node (ls@(l,a)#(r,rsep)#rs) (Node tts tt)) +))" + + +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 del where + "del k x (Leaf xs) = (Leaf (delete_list x xs))" | + "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) \ ( + rebalance_middle_tree k ls (del k x sub) sep rs t + ) +)" + +fun reduce_root where + "reduce_root (Leaf xs) = (Leaf xs)" | + "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 xs) = (length xs \ 2*k)" | + "almost_order k (Node ts t) = ( + (length ts \ 2*k) \ + (\s \ set (subtrees ts). order k s) \ + order k t +)" + + + +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") + case 0 + then obtain ts subs where "t = Leaf ts" "sub = Leaf subs" using height_Leaf assms + by metis + moreover have "rs = (rsub,rsep) # list \ rsub = Node rts rt \ False" + for rsub rsep list rts rt + proof (goal_cases) + case 1 + then have "height rsub = height t" + using assms(2) by auto + then have "height rsub = 0" + using 0 by simp + then show ?case + using "1"(2) height_Leaf by blast + qed + ultimately show ?thesis + by (auto split!: list.splits bplustree.splits) +next + case (Suc nat) + then obtain tts tt where t_node: "t = Node tts tt" + using height_Leaf by (cases t) simp + then obtain mts mt where sub_node: "sub = Node mts mt" + using assms by (cases sub) simp + then show ?thesis + proof (cases "length mts \ k \ length tts \ k") + case False + then show ?thesis + proof (cases rs) + case Nil + then have "height_up\<^sub>i (node\<^sub>i k (mts@(mt,sep)#tts) tt) = height (Node (mts@(mt,sep)#tts) tt)" + using node\<^sub>i_height by blast + also have "\ = max (height t) (height sub)" + by (metis assms(1) height_up\<^sub>i.simps(2) height_list_split sub_node t_node) + finally have height_max: "height_up\<^sub>i (node\<^sub>i k (mts @ (mt, sep) # tts) tt) = max (height t) (height sub)" by simp + then show ?thesis + proof (cases "node\<^sub>i k (mts@(mt,sep)#tts) tt") + case (T\<^sub>i u) + then have "height u = max (height t) (height sub)" using height_max by simp + then have "height (Node ls u) = height (Node (ls@[(sub,sep)]) t)" + by (induction ls) (auto simp add: max.commute) + then show ?thesis using Nil False T\<^sub>i + by (simp add: sub_node t_node) + next + case (Up\<^sub>i l a r) + then have "height (Node (ls@[(sub,sep)]) t) = height (Node (ls@[(l,a)]) r)" + using assms(1) height_max by (induction ls) auto + then show ?thesis + using Up\<^sub>i Nil sub_node t_node by auto + qed + next + case (Cons a list) + then obtain rsub rsep where a_split: "a = (rsub, rsep)" + by (cases a) + then obtain rts rt where r_node: "rsub = Node rts rt" + using assms(2) Cons height_Leaf Suc by (cases rsub) simp_all + + then have "height_up\<^sub>i (node\<^sub>i k (mts@(mt,sep)#rts) rt) = height (Node (mts@(mt,sep)#rts) rt)" + using node\<^sub>i_height by blast + also have "\ = max (height rsub) (height sub)" + by (metis r_node height_up\<^sub>i.simps(2) height_list_split max.commute sub_node) + finally have height_max: "height_up\<^sub>i (node\<^sub>i k (mts @ (mt, sep) # rts) rt) = max (height rsub) (height sub)" by simp + then show ?thesis + proof (cases "node\<^sub>i k (mts@(mt,sep)#rts) rt") + case (T\<^sub>i u) + then have "height u = max (height rsub) (height sub)" + using height_max by simp + then show ?thesis + using T\<^sub>i False Cons r_node a_split sub_node t_node by auto + next + case (Up\<^sub>i l a r) + then have height_max: "max (height l) (height r) = max (height rsub) (height sub)" + using height_max by auto + then show ?thesis + using Cons a_split r_node Up\<^sub>i 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 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) + then obtain ls list where list_split: "split ts x = (ls, list)" by (cases "split ts x") + then show ?case + proof(cases list) + case Nil + then have "height (del k x t) = height t" + using 2 list_split + by (simp add: order_impl_root_order) + moreover obtain lls sub sep where "ls = lls@[(sub,sep)]" + using split_conc 2 list_split Nil + by (metis append_Nil2 less_nat_zero_code list.size(3) old.prod.exhaust rev_exhaust root_order.simps(2)) + moreover have "Node ls t = Node ts t" using split_conc Nil list_split by auto + ultimately show ?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) + then have 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) + + have height_t_sub: "height t = height sub" + using "2.prems"(3) a_split list_split local.Cons split_set.split_set(1) split_set_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) some_child_sub(1) split_set(1)) + then have "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 + also have "\ = height (Node (ls@(sub,sep)#rs) t)" + using height_t_sub "2.prems" height_t_del + by auto + also have "\ = height (Node ts t)" + using 2 a_split list_split Cons split_set(1) split_conc + by auto + finally show ?thesis + using Cons a_split list_split 2 + by simp + 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 "leaves (rebalance_middle_tree k ls sub sep rs t) = leaves (Node (ls@(sub,sep)#rs) t)" + apply(cases sub; cases t) + using assms + apply (auto + split!: bplustree.splits up\<^sub>i.splits list.splits + simp del: node\<^sub>i.simps Lnode\<^sub>i.simps + simp add: node\<^sub>i_leaves_simps Lnode\<^sub>i_leaves_simps + ) + done + +lemma rebalance_last_tree_inorder: + assumes "height t = height sub" + and "ts = list@[(sub,sep)]" + shows "leaves (rebalance_last_tree k ts t) = leaves (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 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_up\<^sub>i (Up\<^sub>i (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 + moreover have "bal b" + using assms by auto + moreover have "\x\set (subtrees as) \ {a} \ set (subtrees bs). height x = height b" + using assms height_bal_subtrees_merge + unfolding bal_up\<^sub>i.simps + by blast + ultimately show ?thesis + by auto +qed + +lemma node\<^sub>i_bal_up\<^sub>i: + assumes "bal_up\<^sub>i (node\<^sub>i k ts t)" + shows "bal (Node ts t)" + using assms +proof(cases "length ts \ 2*k") + case False + then obtain ls sub sep rs where split_list: "split_half ts = (ls@[(sub,sep)], rs)" + using node\<^sub>i_cases by blast + then have "node\<^sub>i k ts t = Up\<^sub>i (Node ls sub) sep (Node rs t)" + using False by auto + moreover have "ts = ls@(sub,sep)#rs" + by (metis append_Cons append_Nil2 append_eq_append_conv2 local.split_list same_append_eq split_half_conc) + ultimately show ?thesis + using bal_list_merge[of ls sub sep rs t] assms + by (simp del: bal.simps bal_up\<^sub>i.simps) +qed simp + +lemma node\<^sub>i_bal_simp: "bal_up\<^sub>i (node\<^sub>i k ts t) = bal (Node ts t)" + using node\<^sub>i_bal node\<^sub>i_bal_up\<^sub>i by blast + +lemma rebalance_middle_tree_bal: + assumes "bal (Node (ls@(sub,sep)#rs) t)" + shows "bal (rebalance_middle_tree k ls sub sep rs t)" +proof (cases t) + case t_node: (Leaf txs) + then obtain mxs where sub_node: "sub = Leaf mxs" + using assms by (cases sub) (auto simp add: t_node) + then have sub_heights: "height sub = height t" "bal sub" "bal t" + apply (metis Suc_inject assms bal_split_left(1) bal_split_left(2) height_bal_tree) + apply (meson assms bal.simps(2) bal_split_left(1)) + using assms bal.simps(2) by blast + show ?thesis + proof (cases "length mxs \ k \ length txs \ k") + case True + then show ?thesis + using t_node sub_node assms + by (auto simp del: bal.simps) + next + case False + then show ?thesis + proof (cases rs) + case Nil + have "height_up\<^sub>i (Lnode\<^sub>i k (mxs@txs)) = height (Leaf (mxs@txs))" + using Lnode\<^sub>i_height by blast + also have "\ = 0" + by simp + also have "\ = height t" + using height_bal_tree sub_heights(3) t_node by fastforce + finally have "height_up\<^sub>i (Lnode\<^sub>i k (mxs@txs)) = height t" . + moreover have "bal_up\<^sub>i (Lnode\<^sub>i k (mxs@txs))" + by (simp add: bal_up\<^sub>i.elims(3) height_Leaf height_up\<^sub>i.simps(2) max_nat.neutr_eq_iff) + ultimately show ?thesis + apply (cases "Lnode\<^sub>i k (mxs@txs)") + using assms Nil sub_node t_node by auto + next + case (Cons r rs) + then obtain rsub rsep where r_split: "r = (rsub,rsep)" by (cases r) + then have rsub_height: "height rsub = height t" "bal rsub" + using assms Cons by auto + then obtain rxs where r_node: "rsub = Leaf rxs" + apply(cases rsub) using assms t_node by auto + have "height_up\<^sub>i (Lnode\<^sub>i k (mxs@rxs)) = height (Leaf (mxs@rxs))" + using Lnode\<^sub>i_height by blast + also have "\ = 0" + by auto + also have "\ = height rsub" + using height_bal_tree r_node rsub_height(2) by fastforce + finally have 1: "height_up\<^sub>i (Lnode\<^sub>i k (mxs@rxs)) = height rsub" . + moreover have 2: "bal_up\<^sub>i (Lnode\<^sub>i k (mxs@rxs))" + by simp + ultimately show ?thesis + proof (cases "Lnode\<^sub>i k (mxs@rxs)") + case (T\<^sub>i u) + then have "bal (Node (ls@(u,rsep)#rs) t)" + using 1 2 Cons assms t_node subtrees_split sub_heights r_split rsub_height + unfolding bal.simps by (auto simp del: height_bplustree.simps) + then show ?thesis + using Cons assms t_node sub_node r_split r_node False T\<^sub>i + by (auto simp del: node\<^sub>i.simps bal.simps) + next + case (Up\<^sub>i l a r) + then have "bal (Node (ls@(l,a)#(r,rsep)#rs) t)" + using 1 2 Cons assms t_node subtrees_split sub_heights r_split rsub_height + unfolding bal.simps by (auto simp del: height_bplustree.simps) + then show ?thesis + using Cons assms t_node sub_node r_split r_node False Up\<^sub>i + by (auto simp del: node\<^sub>i.simps bal.simps) + qed + qed + qed +next + case t_node: (Node tts tt) + then obtain mts mt where sub_node: "sub = Node mts mt" + using assms 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 + then show ?thesis + using t_node sub_node assms + by (auto simp del: bal.simps) + next + case False + then show ?thesis + proof (cases rs) + case Nil + have "height_up\<^sub>i (node\<^sub>i k (mts@(mt,sep)#tts) tt) = height (Node (mts@(mt,sep)#tts) tt)" + using node\<^sub>i_height by blast + also have "\ = Suc (height tt)" + by (metis height_bal_tree height_up\<^sub>i.simps(2) height_list_split max.idem sub_heights(1) sub_heights(3) sub_node t_node) + also have "\ = height t" + using height_bal_tree sub_heights(3) t_node by fastforce + finally have "height_up\<^sub>i (node\<^sub>i k (mts@(mt,sep)#tts) tt) = height t" by simp + moreover have "bal_up\<^sub>i (node\<^sub>i k (mts@(mt,sep)#tts) tt)" + by (metis bal_list_merge bal_up\<^sub>i.simps(2) node\<^sub>i_bal sub_heights(1) sub_heights(2) sub_heights(3) sub_node t_node) + ultimately show ?thesis + apply (cases "node\<^sub>i k (mts@(mt,sep)#tts) tt") + using assms Nil sub_node t_node by auto + next + case (Cons r rs) + then obtain rsub rsep where r_split: "r = (rsub,rsep)" by (cases r) + then have rsub_height: "height rsub = height t" "bal rsub" + using assms Cons by auto + then obtain rts rt where r_node: "rsub = (Node rts rt)" + apply(cases rsub) using t_node by simp + have "height_up\<^sub>i (node\<^sub>i k (mts@(mt,sep)#rts) rt) = height (Node (mts@(mt,sep)#rts) rt)" + using node\<^sub>i_height by blast + also have "\ = Suc (height rt)" + by (metis Un_iff \height rsub = height t\ assms bal.simps(2) bal_split_last(1) height_bal_tree height_up\<^sub>i.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) + also have "\ = height rsub" + using height_bal_tree r_node rsub_height(2) by fastforce + finally have 1: "height_up\<^sub>i (node\<^sub>i k (mts@(mt,sep)#rts) rt) = height rsub" . + moreover have 2: "bal_up\<^sub>i (node\<^sub>i k (mts@(mt,sep)#rts) rt)" + by (metis bal_list_merge bal_up\<^sub>i.simps(2) node\<^sub>i_bal r_node rsub_height(1) rsub_height(2) sub_heights(1) sub_heights(2) sub_node) + ultimately show ?thesis + proof (cases "node\<^sub>i k (mts@(mt,sep)#rts) rt") + case (T\<^sub>i u) + then have "bal (Node (ls@(u,rsep)#rs) t)" + using 1 2 Cons assms t_node subtrees_split sub_heights r_split rsub_height + unfolding bal.simps by (auto simp del: height_bplustree.simps) + then show ?thesis + using Cons assms t_node sub_node r_split r_node False T\<^sub>i + by (auto simp del: node\<^sub>i.simps bal.simps) + next + case (Up\<^sub>i l a r) + then have "bal (Node (ls@(l,a)#(r,rsep)#rs) t)" + using 1 2 Cons assms t_node subtrees_split sub_heights r_split rsub_height + unfolding bal.simps by (auto simp del: height_bplustree.simps) + then show ?thesis + using Cons assms t_node sub_node r_split r_node False Up\<^sub>i + by (auto simp del: node\<^sub>i.simps bal.simps) + qed + qed + qed +qed + + +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 Leaf_merge_aligned: "aligned l (Leaf ms) m \ aligned m (Leaf rs) r \ aligned l (Leaf (ms@rs)) r" + by auto + +lemma Node_merge_aligned: " + inbetween aligned l mts mt sep \ + inbetween aligned sep tts tt u \ + inbetween aligned l (mts @ (mt, sep) # tts) tt u" + apply(induction mts arbitrary: l) + apply auto + done + +lemma aligned_subst_last_merge: "aligned l (Node (ts'@[(sub', sep'),(sub,sep)]) t) u \ aligned sep' t' u \ + aligned l (Node (ts'@[(sub', sep')]) t') u" + apply (induction ts' arbitrary: l) + apply auto + done + +lemma aligned_subst_last_merge_two: "aligned l (Node (ts@[(sub',sep'),(sub,sep)]) t) u \ aligned sep' lt a \ aligned a rt u \ aligned l (Node (ts@[(sub',sep'),(lt,a)]) rt) u" + apply(induction ts arbitrary: l) + apply auto + done + +lemma aligned_subst_merge: "aligned l (Node (ls@(lsub, lsep)#(sub,sep)#(rsub,rsep)#rs) t) u \ aligned lsep sub' rsep \ + aligned l (Node (ls@(lsub, lsep)#(sub', rsep)#rs) t) u" + apply (induction ls arbitrary: l) + apply auto + done + +lemma aligned_subst_merge_two: "aligned l (Node (ls@(lsub, lsep)#(sub,sep)#(rsub,rsep)#rs) t) u \ aligned lsep sub' a \ + aligned a rsub' rsep \ aligned l (Node (ls@(lsub, lsep)#(sub',a)#(rsub', rsep)#rs) t) u" + apply(induction ls arbitrary: l) + apply auto + done + +lemma rebalance_middle_tree_aligned: + assumes "aligned l (Node (ls@(sub,sep)#rs) t) u" + and "height t = height sub" + and "sorted_less (leaves (Node (ls@(sub,sep)#rs) t))" + and "k > 0" + and "case rs of (rsub,rsep) # list \ height rsub = height t | [] \ True" + shows "aligned l (rebalance_middle_tree k ls sub sep rs t) u" +proof (cases t) + case t_node: (Leaf txs) + then obtain mxs where sub_node: "sub = Leaf mxs" + using assms by (cases sub) (auto simp add: t_node) + show ?thesis + proof (cases "length mxs \ k \ length txs \ k") + case True + then show ?thesis + using t_node sub_node assms + by (auto simp del: bal.simps) + next + case False + then show ?thesis + proof (cases rs) + case rs_nil: Nil + then have sorted_leaves: "sorted_less (mxs@txs)" + using assms(3) rs_nil t_node sub_node sorted_wrt_append + by auto + then show ?thesis + proof (cases ls) + case ls_nil: Nil + then have "aligned l (Leaf (mxs@txs)) u" + using t_node sub_node assms rs_nil False + using assms + by auto + then have "aligned_up\<^sub>i l (Lnode\<^sub>i k (mxs@txs)) u" + using Lnode\<^sub>i_aligned sorted_leaves assms by blast + then show ?thesis + using False t_node sub_node rs_nil ls_nil + by (auto simp del: Lnode\<^sub>i.simps split!: up\<^sub>i.split) + next + case Cons + then obtain ls' lsub lsep where ls_Cons: "ls = ls'@[(lsub,lsep)]" + by (metis list.discI old.prod.exhaust snoc_eq_iff_butlast) + then have "aligned lsep (Leaf (mxs@txs)) u" + using Leaf_merge_aligned + using align_last aligned_split_left assms(1) t_node rs_nil sub_node + by blast + moreover have "sorted_less (mxs@txs)" + using assms(3) rs_nil t_node sub_node + by (auto simp add: sorted_wrt_append) + ultimately have "aligned_up\<^sub>i lsep (Lnode\<^sub>i k (mxs@txs)) u" + using Lnode\<^sub>i_aligned assms(4) by blast + then show ?thesis + using False t_node sub_node rs_nil ls_Cons assms + using aligned_subst_last_merge[of l ls' lsub lsep sub sep t u] + using aligned_subst_last_merge_two[of l ls' lsub lsep sub sep t u] + by (auto simp del: Lnode\<^sub>i.simps split!: up\<^sub>i.split) + qed + next + case rs_Cons: (Cons r rs) + then obtain rsub rsep where r_split[simp]: "r = (rsub,rsep)" by (cases r) + then have "height rsub = 0" + using \\thesis. (\mxs. sub = Leaf mxs \ thesis) \ thesis\ assms(2) assms(5) rs_Cons + by fastforce + then obtain rxs where rs_Leaf[simp]: "rsub = Leaf rxs" + by (cases rsub) auto + then have sorted_leaves: "sorted_less (mxs@rxs)" + using assms(3) rs_Cons sub_node sorted_wrt_append r_split + by (auto simp add: sorted_wrt_append) + then show ?thesis + proof (cases ls) + case ls_nil: Nil + then have "aligned l (Leaf (mxs@rxs)) rsep" + using sub_node assms rs_Cons False + by auto + then have "aligned_up\<^sub>i l (Lnode\<^sub>i k (mxs@rxs)) rsep" + using Lnode\<^sub>i_aligned sorted_leaves assms by blast + then show ?thesis + using False t_node sub_node rs_Cons ls_nil assms + by (auto simp del: Lnode\<^sub>i.simps split!: up\<^sub>i.split) + next + case Cons + then obtain ls' lsub lsep where ls_Cons: "ls = ls'@[(lsub,lsep)]" + by (metis list.discI old.prod.exhaust snoc_eq_iff_butlast) + then have "aligned lsep (Leaf (mxs@rxs)) rsep" + using Leaf_merge_aligned + using align_last aligned_split_left assms(1) t_node rs_Cons sub_node + by (metis aligned.elims(2) aligned_split_right bplustree.distinct(1) bplustree.inject(2) inbetween.simps(2) r_split rs_Leaf) + then have "aligned_up\<^sub>i lsep (Lnode\<^sub>i k (mxs@rxs)) rsep" + using Lnode\<^sub>i_aligned assms(4) sorted_leaves by blast + then show ?thesis + using False t_node sub_node rs_Cons ls_Cons assms + using aligned_subst_merge[of l ls' lsub lsep sub sep rsub rsep rs] + using aligned_subst_merge_two[of l ls' lsub lsep sub sep rsub rsep rs t u] + by (auto simp del: Lnode\<^sub>i.simps split!: up\<^sub>i.split) + qed + qed + qed +next + case t_node: (Node tts tt) + then obtain mts mt where sub_node: "sub = Node mts mt" + using assms by (cases sub) (auto simp add: t_node) + show ?thesis + proof (cases "length tts \ k \ length mts \ k") + case True + then show ?thesis + using t_node sub_node assms + by (auto simp del: bal.simps) + next + case False + then show ?thesis + proof (cases rs) + case rs_nil: Nil + then have sorted_leaves: "sorted_less (leaves_list mts @ leaves mt @ leaves_list tts @ leaves tt)" + using assms(3) rs_nil t_node sub_node + by (auto simp add: sorted_wrt_append) + then show ?thesis + proof (cases ls) + case ls_nil: Nil + then have "aligned l (Node (mts@(mt,sep)#tts) tt) u" + using t_node sub_node assms rs_nil False + by (auto simp add: Node_merge_aligned) + then have "aligned_up\<^sub>i l (node\<^sub>i k (mts@(mt,sep)#tts) tt) u" + using node\<^sub>i_aligned sorted_leaves assms by blast + then show ?thesis + using False t_node sub_node rs_nil ls_nil + by (auto simp del: node\<^sub>i.simps split!: up\<^sub>i.split) + next + case Cons + then obtain ls' lsub lsep where ls_Cons: "ls = ls'@[(lsub,lsep)]" + by (metis list.discI old.prod.exhaust snoc_eq_iff_butlast) + then have "aligned lsep (Node (mts@(mt,sep)#tts) tt) u" + using t_node sub_node assms rs_nil False ls_Cons + by (metis Node_merge_aligned align_last aligned.simps(2) aligned_split_left) + then have "aligned_up\<^sub>i lsep (node\<^sub>i k (mts@(mt,sep)#tts) tt) u" + using node\<^sub>i_aligned assms(4) sorted_leaves by blast + then show ?thesis + using False t_node sub_node rs_nil ls_Cons assms + using aligned_subst_last_merge[of l ls' lsub lsep sub sep t u] + using aligned_subst_last_merge_two[of l ls' lsub lsep sub sep t u] + by (auto simp del: node\<^sub>i.simps split!: up\<^sub>i.split) + qed + next + case rs_Cons: (Cons r rs) + then obtain rsub rsep where r_split[simp]: "r = (rsub,rsep)" + by (cases r) + then have "height rsub \ 0" + using assms rs_Cons t_node by auto + then obtain rts rt where rs_Node: "rsub = Node rts rt" + by (cases rsub) auto + have "sorted_less (leaves sub @ leaves rsub)" + using assms(3) rs_Cons r_split + by (simp add: sorted_wrt_append) + then have sorted_leaves: "sorted_less (leaves_list mts @ leaves mt @ leaves_list rts @ leaves rt)" + by (simp add: rs_Node sub_node) + then show ?thesis + proof (cases ls) + case ls_nil: Nil + then have "aligned l (Node (mts@(mt,sep)#rts) rt) rsep" + using sub_node assms rs_Cons False rs_Node + by (metis Node_merge_aligned aligned.simps(2) append_self_conv2 inbetween.simps(2) r_split) + then have "aligned_up\<^sub>i l (node\<^sub>i k (mts@(mt,sep)#rts) rt) rsep" + using node\<^sub>i_aligned sorted_leaves assms by blast + then show ?thesis + using False t_node sub_node rs_Cons ls_nil assms rs_Node + by (auto simp del: node\<^sub>i.simps split!: up\<^sub>i.split) + next + case Cons + then obtain ls' lsub lsep where ls_Cons: "ls = ls'@[(lsub,lsep)]" + by (metis list.discI old.prod.exhaust snoc_eq_iff_butlast) + then have "aligned lsep (Node (mts@(mt,sep)#rts) rt) rsep" + using Node_merge_aligned + using align_last aligned_split_left assms(1) t_node rs_Cons sub_node + by (metis aligned.simps(2) aligned_split_right inbetween.simps(2) r_split rs_Node) + then have "aligned_up\<^sub>i lsep (node\<^sub>i k (mts@(mt,sep)#rts) rt) rsep" + using sorted_leaves node\<^sub>i_aligned assms(4) by blast + then show ?thesis + using False t_node sub_node rs_Cons ls_Cons assms rs_Node + using aligned_subst_merge[of l ls' lsub lsep sub sep rsub rsep rs] + using aligned_subst_merge_two[of l ls' lsub lsep sub sep rsub rsep rs t u] + by (auto simp del: node\<^sub>i.simps split!: up\<^sub>i.split) + qed + qed + qed +qed + +lemma Node_merge_Laligned: " + Laligned (Node mts mt) sep \ + inbetween aligned sep tts tt u \ + Laligned (Node (mts @ (mt, sep) # tts) tt) u" + apply(induction mts) + apply auto + using Node_merge_aligned by blast + +lemma Laligned_subst_last_merge: "Laligned (Node (ts'@[(sub', sep'),(sub,sep)]) t) u \ aligned sep' t' u \ + Laligned (Node (ts'@[(sub', sep')]) t') u" + apply (induction ts') + apply auto + by (metis (no_types, opaque_lifting) Node_merge_aligned aligned.simps(2) aligned_split_left inbetween.simps(1)) + +lemma Laligned_subst_last_merge_two: "Laligned (Node (ts@[(sub',sep'),(sub,sep)]) t) u \ aligned sep' lt a \ aligned a rt u \ Laligned (Node (ts@[(sub',sep'),(lt,a)]) rt) u" + apply(induction ts) + apply auto + by (meson aligned.simps(2) aligned_subst_last_merge_two) + +lemma Laligned_subst_merge: "Laligned (Node (ls@(lsub, lsep)#(sub,sep)#(rsub,rsep)#rs) t) u \ aligned lsep sub' rsep \ + Laligned (Node (ls@(lsub, lsep)#(sub', rsep)#rs) t) u" + apply (induction ls) + apply auto + by (meson aligned.simps(2) aligned_subst_merge) + +lemma Laligned_subst_merge_two: "Laligned (Node (ls@(lsub, lsep)#(sub,sep)#(rsub,rsep)#rs) t) u \ aligned lsep sub' a \ + aligned a rsub' rsep \ Laligned (Node (ls@(lsub, lsep)#(sub',a)#(rsub', rsep)#rs) t) u" + apply(induction ls) + apply auto + by (meson aligned.simps(2) aligned_subst_merge_two) + +lemma xs_front: "xs @ [(a,b)] = (x,y)#xs' \ xs @ [(a,b),(c,d)] = (z,zz)#xs'' \ (x,y) = (z,zz)" + apply(induction xs) + apply auto + done + +lemma rebalance_middle_tree_Laligned: + assumes "Laligned (Node (ls@(sub,sep)#rs) t) u" + and "height t = height sub" + and "sorted_less (leaves (Node (ls@(sub,sep)#rs) t))" + and "k > 0" + and "case rs of (rsub,rsep) # list \ height rsub = height t | [] \ True" + shows "Laligned (rebalance_middle_tree k ls sub sep rs t) u" +proof (cases t) + case t_node: (Leaf txs) + then obtain mxs where sub_node: "sub = Leaf mxs" + using assms by (cases sub) (auto simp add: t_node) + show ?thesis + proof (cases "length mxs \ k \ length txs \ k") + case True + then show ?thesis + using t_node sub_node assms + by auto + next + case False + then show ?thesis + proof (cases rs) + case rs_nil: Nil + then have sorted_leaves: "sorted_less (mxs@txs)" + using assms(3) rs_nil t_node sub_node sorted_wrt_append + by auto + then show ?thesis + proof (cases ls) + case ls_nil: Nil + then have "Laligned (Leaf (mxs@txs)) u" + using t_node sub_node assms rs_nil False + using assms + by auto + then have "Laligned_up\<^sub>i (Lnode\<^sub>i k (mxs@txs)) u" + using Lnode\<^sub>i_Laligned sorted_leaves assms by blast + then show ?thesis + using False t_node sub_node rs_nil ls_nil + by (auto simp del: Lnode\<^sub>i.simps split!: up\<^sub>i.split) + next + case Cons + then obtain ls' lsub lsep where ls_Cons: "ls = ls'@[(lsub,lsep)]" + by (metis list.discI old.prod.exhaust snoc_eq_iff_butlast) + then have "aligned lsep (Leaf (mxs@txs)) u" + using Leaf_merge_aligned Lalign_last Laligned_split_left assms(1) rs_nil sub_node t_node + by blast + moreover have "sorted_less (mxs@txs)" + using assms(3) rs_nil t_node sub_node + by (auto simp add: sorted_wrt_append) + ultimately have "aligned_up\<^sub>i lsep (Lnode\<^sub>i k (mxs@txs)) u" + using Lnode\<^sub>i_aligned assms(4) by blast + then show ?thesis + using False t_node sub_node rs_nil ls_Cons assms + using Laligned_subst_last_merge[of ls' lsub lsep sub sep t u] + using Laligned_subst_last_merge_two[of ls' lsub lsep sub sep t u] + by (auto simp del: Lnode\<^sub>i.simps split!: up\<^sub>i.split) + qed + next + case rs_Cons: (Cons r rs) + then obtain rsub rsep where r_split[simp]: "r = (rsub,rsep)" by (cases r) + then have "height rsub = 0" + using \\thesis. (\mxs. sub = Leaf mxs \ thesis) \ thesis\ assms(2) assms(5) rs_Cons + by fastforce + then obtain rxs where rs_Leaf[simp]: "rsub = Leaf rxs" + by (cases rsub) auto + then have sorted_leaves: "sorted_less (mxs@rxs)" + using assms(3) rs_Cons sub_node sorted_wrt_append r_split + by (auto simp add: sorted_wrt_append) + then show ?thesis + proof (cases ls) + case ls_nil: Nil + then have "Laligned (Leaf (mxs@rxs)) rsep" + using sub_node assms rs_Cons False + by auto + then have "Laligned_up\<^sub>i (Lnode\<^sub>i k (mxs@rxs)) rsep" + using Lnode\<^sub>i_Laligned sorted_leaves assms by blast + then show ?thesis + using False t_node sub_node rs_Cons ls_nil assms + by (auto simp del: Lnode\<^sub>i.simps split!: up\<^sub>i.split) + next + case Cons + then obtain ls' lsub lsep where ls_Cons: "ls = ls'@[(lsub,lsep)]" + by (metis list.discI old.prod.exhaust snoc_eq_iff_butlast) + then have "aligned lsep (Leaf (mxs@rxs)) rsep" + using Leaf_merge_aligned + using assms(1) t_node rs_Cons sub_node + by (metis Lalign_last Laligned_split_left Laligned_split_right aligned.elims(2) bplustree.distinct(1) bplustree.inject(2) inbetween.simps(2) r_split rs_Leaf) + then have "aligned_up\<^sub>i lsep (Lnode\<^sub>i k (mxs@rxs)) rsep" + using Lnode\<^sub>i_aligned assms(4) sorted_leaves by blast + then show ?thesis + using False t_node sub_node rs_Cons ls_Cons assms + using Laligned_subst_merge[of ls' lsub lsep sub sep rsub rsep rs] + using Laligned_subst_merge_two[of ls' lsub lsep sub sep rsub rsep rs t u] + by (auto simp del: Lnode\<^sub>i.simps split!: up\<^sub>i.split) + qed + qed + qed +next + case t_node: (Node tts tt) + then obtain mts mt where sub_node: "sub = Node mts mt" + using assms by (cases sub) (auto simp add: t_node) + show ?thesis + proof (cases "length tts \ k \ length mts \ k") + case True + then show ?thesis + using t_node sub_node assms + by (auto simp del: bal.simps) + next + case False + then show ?thesis + proof (cases rs) + case rs_nil: Nil + then have sorted_leaves: "sorted_less (leaves_list mts @ leaves mt @ leaves_list tts @ leaves tt)" + using assms(3) rs_nil t_node sub_node + by (auto simp add: sorted_wrt_append) + then show ?thesis + proof (cases ls) + case ls_nil: Nil + then have "Laligned (Node (mts@(mt,sep)#tts) tt) u" + using t_node sub_node assms rs_nil False + by (metis Lalign_last Laligned_nonempty_Node Node_merge_Laligned aligned.simps(2) append_self_conv2) + then have "Laligned_up\<^sub>i (node\<^sub>i k (mts@(mt,sep)#tts) tt) u" + using node\<^sub>i_Laligned sorted_leaves assms by blast + then show ?thesis + using False t_node sub_node rs_nil ls_nil + by (auto simp del: node\<^sub>i.simps split!: up\<^sub>i.split) + next + case Cons + then obtain ls' lsub lsep where ls_Cons: "ls = ls'@[(lsub,lsep)]" + by (metis list.discI old.prod.exhaust snoc_eq_iff_butlast) + then have "aligned lsep (Node (mts@(mt,sep)#tts) tt) u" + using t_node sub_node assms rs_nil False ls_Cons + by (metis Lalign_last Laligned_split_left Node_merge_aligned aligned.simps(2)) + then have "aligned_up\<^sub>i lsep (node\<^sub>i k (mts@(mt,sep)#tts) tt) u" + using node\<^sub>i_aligned assms(4) sorted_leaves by blast + then show ?thesis + using False t_node sub_node rs_nil ls_Cons assms + using Laligned_subst_last_merge[of ls' lsub lsep sub sep t u] + using Laligned_subst_last_merge_two[of ls' lsub lsep sub sep t u] + by (auto simp del: node\<^sub>i.simps bal.simps height_bplustree.simps split!: up\<^sub>i.split list.splits) + qed + next + case rs_Cons: (Cons r rs) + then obtain rsub rsep where r_split[simp]: "r = (rsub,rsep)" + by (cases r) + then have "height rsub \ 0" + using assms rs_Cons t_node by auto + then obtain rts rt where rs_Node: "rsub = Node rts rt" + by (cases rsub) auto + have "sorted_less (leaves sub @ leaves rsub)" + using assms(3) rs_Cons r_split + by (simp add: sorted_wrt_append) + then have sorted_leaves: "sorted_less (leaves_list mts @ leaves mt @ leaves_list rts @ leaves rt)" + by (simp add: rs_Node sub_node) + then show ?thesis + proof (cases ls) + case ls_nil: Nil + then have "Laligned (Node (mts@(mt,sep)#rts) rt) rsep" + using sub_node assms rs_Cons False rs_Node + by (metis Laligned_nonempty_Node Node_merge_Laligned aligned.simps(2) append_self_conv2 inbetween.simps(2) r_split) + then have "Laligned_up\<^sub>i (node\<^sub>i k (mts@(mt,sep)#rts) rt) rsep" + using node\<^sub>i_Laligned by blast + then show ?thesis + using False t_node sub_node rs_Cons ls_nil assms rs_Node + by (auto simp del: node\<^sub>i.simps split!: up\<^sub>i.split) + next + case Cons + then obtain ls' lsub lsep where ls_Cons: "ls = ls'@[(lsub,lsep)]" + by (metis list.discI old.prod.exhaust snoc_eq_iff_butlast) + then have "aligned lsep (Node (mts@(mt,sep)#rts) rt) rsep" + using Node_merge_aligned + using assms(1) t_node rs_Cons sub_node + by (metis Lalign_last Laligned_split_left Laligned_split_right aligned.simps(2) inbetween.simps(2) r_split rs_Node) + then have "aligned_up\<^sub>i lsep (node\<^sub>i k (mts@(mt,sep)#rts) rt) rsep" + using sorted_leaves node\<^sub>i_aligned assms(4) by blast + then show ?thesis + using False t_node sub_node rs_Cons ls_Cons assms rs_Node + using Laligned_subst_merge[of ls' lsub lsep sub sep rsub rsep rs] + using Laligned_subst_merge_two[of ls' lsub lsep sub sep rsub rsep rs t u] + by (auto simp del: node\<^sub>i.simps split!: up\<^sub>i.split) + qed + qed + qed +qed + +lemma rebalance_last_tree_aligned: + assumes "aligned l (Node (ls@[(sub,sep)]) t) u" + and "height t = height sub" + and "sorted_less (leaves (Node (ls@[(sub,sep)]) t))" + and "k > 0" + shows "aligned l (rebalance_last_tree k (ls@[(sub,sep)]) t) u" + using rebalance_middle_tree_aligned[of l ls sub sep "[]" t u k] assms + by auto + +lemma rebalance_last_tree_Laligned: + assumes "Laligned (Node (ls@[(sub,sep)]) t) u" + and "height t = height sub" + and "sorted_less (leaves (Node (ls@[(sub,sep)]) t))" + and "k > 0" + shows "Laligned (rebalance_last_tree k (ls@[(sub,sep)]) t) u" + using rebalance_middle_tree_Laligned[of ls sub sep "[]" t u k] assms + by auto + +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) + then obtain ls rs where list_split: "split ts x = (ls,rs)" + by (cases "split ts x") + then show ?case + proof (cases rs) + case Nil + then have "bal (del k x t)" using 2 list_split + by (simp add: order_impl_root_order) + moreover have "height (del k x t) = height t" + using 2 del_height by (simp add: order_impl_root_order) + moreover have "ts \ []" using 2 by auto + ultimately have "bal (rebalance_last_tree k ts (del k x t))" + using 2 Nil rebalance_last_tree_bal + by simp + then have "bal (rebalance_last_tree k ls (del k x t))" + using list_split split_conc Nil by fastforce + then show ?thesis + using 2 list_split Nil + by auto + next + case (Cons r rs) + then obtain sub sep where r_split: "r = (sub,sep)" by (cases r) + then have sub_height: "height sub = height t" "bal sub" + using 2 Cons list_split split_set(1) by fastforce+ + then have "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)) + moreover have "bal (Node (ls@(sub,sep)#rs) t)" + using "2.prems"(3) list_split Cons r_split split_conc by blast + ultimately have "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 + then have "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 + then show ?thesis + using 2 list_split Cons r_split by auto + 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 txs) + then obtain subxs where "sub = Leaf subxs" + using height_Leaf assms by metis + then show ?thesis + using assms Leaf + by (auto split!: list.splits bplustree.splits) +next + case t_node: (Node tts tt) + then obtain mts mt where sub_node: "sub = Node mts mt" + using assms by (cases sub) (auto) + then show ?thesis + proof(cases "length mts \ k \ length tts \ k") + case True + then have "order k sub" using assms + by (simp add: sub_node) + then show ?thesis + using True t_node sub_node assms by auto + next + case False + then show ?thesis + proof (cases rs) + case Nil + have "order_up\<^sub>i k (node\<^sub>i k (mts@(mt,sep)#tts) tt)" + using node\<^sub>i_order[of k "mts@(mt,sep)#tts" tt] assms(1,3) t_node sub_node + by (auto simp del: order_up\<^sub>i.simps node\<^sub>i.simps) + then show ?thesis + apply(cases "node\<^sub>i k (mts@(mt,sep)#tts) tt") + using assms t_node sub_node False Nil apply (auto simp del: node\<^sub>i.simps) + done + next + case (Cons r rs) + then obtain rsub rsep where r_split: "r = (rsub,rsep)" by (cases r) + then have rsub_height: "height rsub = height t" + using assms Cons by auto + then obtain rts rt where r_node: "rsub = (Node rts rt)" + apply(cases rsub) using t_node by simp + have "order_up\<^sub>i k (node\<^sub>i k (mts@(mt,sep)#rts) rt)" + using node\<^sub>i_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_up\<^sub>i.simps node\<^sub>i.simps) + then show ?thesis + apply(cases "node\<^sub>i k (mts@(mt,sep)#rts) rt") + using assms t_node sub_node False Cons r_split r_node apply (auto simp del: node\<^sub>i.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 txs) + then obtain subxs where "sub = Leaf subxs" + using height_Leaf assms by metis + then show ?thesis + using assms Leaf + by (auto split!: list.splits bplustree.splits) +next + case t_node: (Node tts tt) + then obtain mts mt where sub_node: "sub = Node mts mt" + using assms by (cases sub) (auto) + then show ?thesis + proof(cases "length mts \ k \ length tts \ k") + case True + then have "order k sub" using assms + by (simp add: sub_node) + then show ?thesis + using True t_node sub_node assms by auto + next + case False + have "order_up\<^sub>i k (node\<^sub>i k (mts@(mt,sep)#tts) tt)" + using node\<^sub>i_order[of k "mts@(mt,sep)#tts" tt] assms t_node sub_node + by (auto simp del: order_up\<^sub>i.simps node\<^sub>i.simps) + then show ?thesis + apply(cases "node\<^sub>i k (mts@(mt,sep)#tts) tt") + using assms t_node sub_node False Nil apply (auto simp del: node\<^sub>i.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 del_order: + assumes "k > 0" + and "root_order k t" + and "bal t" + and "sorted (leaves t)" + shows "almost_order k (del k x t)" + using assms +proof (induction k x t rule: del.induct) + case (1 k x xs) + then show ?case + by auto +next + case (2 k x ts t) + then obtain ls list where list_split: "split ts x = (ls, list)" by (cases "split ts x") + then show ?case + proof (cases list) + case Nil + then have "almost_order k (del k x t)" using 2 list_split + by (simp add: order_impl_root_order sorted_wrt_append) + moreover obtain lls lsub lsep where ls_split: "ls = lls@[(lsub,lsep)]" + using 2 Nil list_split + by (metis append_Nil length_0_conv less_nat_zero_code old.prod.exhaust rev_exhaust root_order.simps(2) split_conc) + moreover have "height t = height (del k x t)" using del_height 2 + by (simp add: order_impl_root_order) + moreover have "length ls = length ts" + using Nil list_split + by (auto dest: split_length) + ultimately have "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) + then show ?thesis + using 2 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) + then have "almost_order k (del k x sub)" using 2 list_split Cons r_split order_impl_root_order + by (metis bal.simps(2) root_order.simps(2) some_child_sub(1) sorted_leaves_induct_subtree split_conc split_set(1)) + moreover have "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)) + ultimately have "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 list_split by auto + then show ?thesis using 2 Cons r_split list_split by auto + qed +qed + +(* sortedness of delete by inorder *) +(* generalize del_list_sorted since its cumbersome to express inorder_list ts as xs @ [a] +note that the proof scheme is almost identical to ins_list_sorted + *) +(* TODO lift to leaves *) +thm del_list_sorted + +lemma del_list_split: + assumes "Laligned (Node ts t) u" + and "sorted_less (leaves (Node ts t))" + and "split ts x = (ls, rs)" + shows "del_list x (leaves (Node ts t)) = leaves_list ls @ del_list x (leaves_list rs @ leaves t)" +proof (cases ls) + case Nil + then show ?thesis + using assms by (auto dest!: split_conc) +next + case Cons + then obtain ls' sub sep where ls_tail_split: "ls = ls' @ [(sub,sep)]" + by (metis list.distinct(1) rev_exhaust surj_pair) + have sorted_inorder: "sorted_less (inorder (Node ts t))" + using Laligned_sorted_inorder assms(1) sorted_cons sorted_snoc by blast + moreover have "sep < x" + using split_req(2)[of ts x ls' sub sep rs] + using assms ls_tail_split sorted_inorder sorted_inorder_separators + by blast + moreover have leaves_split: "leaves (Node ts t) = leaves_list ls @ leaves_list rs @ leaves t" + using assms(3) split_tree.leaves_split by blast + then show ?thesis + proof (cases "leaves_list ls") + case Nil + then show ?thesis + by (metis append_self_conv2 leaves_split) + next + case Cons + then obtain leavesls' l' where leaves_tail_split: "leaves_list ls = leavesls' @ [l']" + by (metis list.simps(3) rev_exhaust) + then have "l' \ sep" + proof - + have "l' \ set (leaves_list ls)" + using leaves_tail_split by force + then have "l' \ set (leaves (Node ls' sub))" + using ls_tail_split + by auto + moreover have "Laligned (Node ls' sub) sep" + using assms split_conc[OF assms(3)] Cons ls_tail_split + using Laligned_split_left + by simp + ultimately show ?thesis + using Laligned_leaves_inbetween[of "Node ls' sub" sep] + by blast + qed + moreover have "sorted_less (leaves (Node ts t))" + using assms sorted_wrt_append split_conc by fastforce + ultimately show ?thesis using assms(2) split_conc[OF assms(3)] leaves_tail_split + using del_list_sorted[of "leavesls'" l' "leaves_list rs @ leaves t" x] \sep < x\ + by auto + qed +qed + +corollary del_list_split_aligned: + assumes "aligned l (Node ts t) u" + and "sorted_less (leaves (Node ts t))" + and "split ts x = (ls, rs)" + shows "del_list x (leaves (Node ts t)) = leaves_list ls @ del_list x (leaves_list rs @ leaves t)" + using aligned_imp_Laligned assms(1) assms(2) assms(3) del_list_split by blast + +(* del sorted requires sortedness of the full list so we need to change the right specialization a bit *) + +lemma del_list_split_right: + assumes "Laligned (Node ts t) u" + and "sorted_less (leaves (Node ts t))" + and "split ts x = (ls, (sub,sep)#rs)" + shows "del_list x (leaves_list ((sub,sep)#rs) @ leaves t) = del_list x (leaves sub) @ leaves_list rs @ leaves t" +proof - + have sorted_inorder: "sorted_less (inorder (Node ts t))" + using Laligned_sorted_inorder assms(1) sorted_cons sorted_snoc by blast + from assms have "x \ sep" + proof - + from assms have "sorted_less (separators ts)" + using sorted_inorder_separators sorted_inorder by blast + then show ?thesis + using split_req(3) + using assms + by fastforce + qed + then show ?thesis + proof (cases "leaves_list rs @ leaves t") + case Nil + moreover have "leaves_list ((sub,sep)#rs) @ leaves t = leaves sub @ leaves_list rs @ leaves t" + by simp + ultimately show ?thesis + by (metis self_append_conv) + next + case (Cons r' rs') + then have "sep < r'" + by (metis aligned_leaves_inbetween Laligned_split_right assms(1) assms(3) leaves.simps(2) list.set_intros(1) split_set.split_conc split_set_axioms) + then have "x < r'" + using \x \ sep\ by auto + moreover have "sorted_less (leaves sub @ leaves_list rs @ leaves t)" + proof - + have "sorted_less (leaves_list ls @ leaves sub @ leaves_list rs @ leaves t)" + using assms + by (auto dest!: split_conc) + then show ?thesis + using assms + by (metis Cons sorted_wrt_append) + qed + ultimately show ?thesis + using del_list_sorted[of "leaves sub" r' rs'] Cons + by auto + qed +qed + +corollary del_list_split_right_aligned: + assumes "aligned l (Node ts t) u" + and "sorted_less (leaves (Node ts t))" + and "split ts x = (ls, (sub,sep)#rs)" + shows "del_list x (leaves_list ((sub,sep)#rs) @ leaves t) = del_list x (leaves sub) @ leaves_list rs @ leaves t" + using aligned_imp_Laligned assms(1) assms(2) assms(3) split_set.del_list_split_right split_set_axioms by blast + +thm del_list_idem + +lemma del_inorder: + assumes "k > 0" + and "root_order k t" + and "bal t" + and "sorted_less (leaves t)" + and "aligned l t u" + and "l < x" "x \ u" + shows "leaves (del k x t) = del_list x (leaves t) \ aligned l (del k x t) u" + using assms +proof (induction k x t arbitrary: l u rule: del.induct) + case (1 k x xs) + then have "leaves (del k x (Leaf xs)) = del_list x (leaves (Leaf xs))" + by (simp add: insert_list_req) + moreover have "aligned l (del k x (Leaf xs)) u" + proof - + have "l < u" + using "1.prems"(6) "1.prems"(7) by auto + moreover have "\x \ set xs - {x}. l < x \ x \ u" + using "1.prems"(5) by auto + ultimately show ?thesis + using set_del_list insert_list_req + by (metis "1"(4) aligned.simps(1) del.simps(1) leaves.simps(1)) + qed + ultimately show ?case + by simp +next + case (2 k x ts t l u) + then obtain ls rs where list_split: "split ts x = (ls, rs)" + by (meson surj_pair) + then have list_conc: "ts = ls @ rs" + using split_set.split_conc split_set_axioms by blast + show ?case + proof (cases rs) + case Nil + then obtain ls' lsub lsep where ls_split: "ls = ls' @ [(lsub,lsep)]" + by (metis "2.prems"(2) append_Nil2 list.size(3) list_conc old.prod.exhaust root_order.simps(2) snoc_eq_iff_butlast zero_less_iff_neq_zero) + then have IH: "leaves (del k x t) = del_list x (leaves t) \ aligned lsep (del k x t) u" + using "2.IH"(1)[OF list_split[symmetric] Nil, of lsep u] + by (metis (no_types, lifting) "2.prems"(1) "2.prems"(2) "2.prems"(3) "2.prems"(4) "2.prems"(5) "2.prems"(7) \ls = ls' @ [(lsub, lsep)]\ align_last aligned_sorted_separators bal.simps(2) list_conc list_split local.Nil order_impl_root_order root_order.simps(2) self_append_conv sorted_cons sorted_leaves_induct_last sorted_snoc split_set.split_req(2) split_set_axioms) + have "leaves (del k x (Node ts t)) = leaves (rebalance_last_tree k ts (del k x t))" + using list_split Nil list_conc by auto + also have "\ = leaves_list ts @ leaves (del k x t)" + proof - + obtain ts' sub sep where ts_split: "ts = ts' @ [(sub, sep)]" + using \ls = ls' @ [(lsub, lsep)]\ list_conc local.Nil by blast + then have "height sub = height t" + using "2.prems"(3) by auto + moreover have "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)) + ultimately show ?thesis + using rebalance_last_tree_inorder + using ts_split by auto + qed + also have "\ = leaves_list ts @ del_list x (leaves t)" + using IH by blast + also have "\ = del_list x (leaves (Node ts t))" + by (metis "2.prems"(4) "2.prems"(5) aligned_imp_Laligned append_self_conv2 concat.simps(1) list.simps(8) list_conc list_split local.Nil self_append_conv split_set.del_list_split split_set_axioms) + finally have 0: "leaves (del k x (Node ts t)) = del_list x (leaves (Node ts t))" . + moreover have "aligned l (del k x (Node ts t)) u" + proof - + have "aligned l (Node ls (del k x t)) u" + using IH list_conc Nil "2.prems" ls_split + using aligned_subst_last + by (metis self_append_conv) + moreover have "sorted_less (leaves (Node ls (del k x t)))" + using "2.prems"(4) \leaves_list ts @ del_list x (leaves t) = del_list x (leaves (Node ts t))\ \leaves_list ts @ leaves (del k x t) = leaves_list ts @ del_list x (leaves t)\ list_conc local.Nil sorted_del_list + by auto + ultimately have "aligned l (rebalance_last_tree k ls (del k x t)) u" + using rebalance_last_tree_aligned + by (metis (no_types, lifting) "2.prems"(1) "2.prems"(2) "2.prems"(3) UnCI bal.simps(2) del_height list.set_intros(1) list_conc ls_split order_impl_root_order root_order.simps(2) set_append some_child_sub(1)) + then show ?thesis using list_split ls_split "2.prems" Nil + by simp + qed + ultimately show ?thesis + by simp + next + case (Cons h rs) + then obtain sub sep where h_split: "h = (sub,sep)" + by (cases h) + then have node_sorted_split: + "sorted_less (leaves (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+ + { + assume IH: "leaves (del k x sub) = del_list x (leaves sub)" + have "leaves (del k x (Node ts t)) = leaves (rebalance_middle_tree k ls (del k x sub) sep rs t)" + using Cons list_split h_split "2.prems" + by auto + also have "\ = leaves (Node (ls@(del k x sub, sep)#rs) t)" + using rebalance_middle_tree_inorder[of t "del k x sub" rs] + by (smt (verit) "2.prems"(1) "2.prems"(2) "2.prems"(3) bal.simps(2) bal_sub_height del_height h_split list_split local.Cons node_sorted_split(3) order_impl_root_order rebalance_middle_tree_inorder root_order.simps(2) some_child_sub(1) split_set(1)) + also have "\ = leaves_list ls @ leaves (del k x sub) @ leaves_list rs @ leaves t" + by auto + also have "\ = leaves_list ls @ del_list x (leaves sub @ leaves_list rs @ leaves t)" + using del_list_split_right_aligned[of l ts t u x ls sub sep rs] + using list_split Cons "2.prems"(4,5) h_split IH list_conc + by auto + also have "\ = del_list x (leaves_list ls @ leaves sub @ leaves_list rs @ leaves t)" + using del_list_split_aligned[of l ts t u x ls "(sub,sep)#rs"] + using list_split Cons "2.prems"(4,5) h_split IH list_conc + by auto + finally have "leaves (del k x (Node ts t)) = del_list x (leaves (Node ts t))" + using list_conc Cons h_split + by auto + } + then show ?thesis + proof (cases ls) + case Nil + then have IH: "leaves (del k x sub) = del_list x (leaves sub) \ aligned l (del k x sub) sep" + using "2.IH"(2)[OF list_split[symmetric] Cons h_split[symmetric], of l sep] + by (metis "2.prems"(1) "2.prems"(2) "2.prems"(5) "2.prems"(6) aligned.simps(2) aligned_sorted_separators append_self_conv2 bal.simps(2) h_split inbetween.simps(2) list.set_intros(1) list_conc list_split local.Cons local.Nil node_sorted_split(1) node_sorted_split(3) order_impl_root_order root_order.simps(2) some_child_sub(1) sorted_cons sorted_leaves_induct_subtree sorted_snoc split_set.split_req(3) split_set_axioms) + then have "leaves (del k x (Node ts t)) = del_list x (leaves (Node ts t))" + using \leaves (del k x sub) = del_list x (leaves sub) \ leaves (del k x (Node ts t)) = del_list x (leaves (Node ts t))\ by blast + then have "sorted_less (leaves (del k x (Node ts t)))" + using "2.prems"(4) sorted_del_list by auto + then have sorted_leaves: "sorted_less (leaves (Node (ls@(del k x sub, sep)#rs) t))" + using list_split Cons h_split + using rebalance_middle_tree_inorder[of t "del k x sub" rs k ls sep] + using "2.prems"(4) "2.prems"(5) IH \leaves (del k x (Node ts t)) = del_list x (leaves (Node ts t))\ del_list_split_aligned del_list_split_right_aligned + by auto + from IH have "aligned l (del k x (Node ts t)) u" + proof - + have "aligned l (Node (ls@(del k x sub, sep)#rs) t) u" + using "2.prems"(5) IH h_split list_conc local.Cons local.Nil by auto + then have "aligned l (rebalance_middle_tree k ls (del k x sub) sep rs t) u" + using rebalance_middle_tree_aligned sorted_leaves + by (smt (verit, best) "2.prems"(1) "2.prems"(2) "2.prems"(3) append_self_conv2 bal.simps(2) bal_sub_height del_height h_split list.set_intros(1) list_conc local.Cons local.Nil order_impl_root_order root_order.simps(2) some_child_sub(1)) + then show ?thesis + using list_split Cons h_split + by auto + qed + then show ?thesis + using \leaves (del k x (Node ts t)) = del_list x (leaves (Node ts t))\ by blast + next + case _: (Cons a list) + then obtain ls' lsub lsep where l_split: "ls = ls'@[(lsub,lsep)]" + by (metis list.discI old.prod.exhaust snoc_eq_iff_butlast) + then have "aligned lsep sub sep" + using "2.prems"(5) align_last aligned_split_left h_split list_conc local.Cons + by blast + then have IH: "leaves (del k x sub) = del_list x (leaves sub) \ aligned lsep (del k x sub) sep" + using "2.IH"(2)[OF list_split[symmetric] Cons h_split[symmetric], of lsep sep] + by (metis "2.prems"(1) "2.prems"(2) "2.prems"(5) aligned_sorted_separators bal.simps(2) bal_split_left(1) h_split l_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_cons sorted_leaves_induct_subtree sorted_snoc split_set.split_req(2) split_set.split_req(3) split_set_axioms split_set(1)) + then have "leaves (del k x (Node ts t)) = del_list x (leaves (Node ts t))" + using \leaves (del k x sub) = del_list x (leaves sub) \ leaves (del k x (Node ts t)) = del_list x (leaves (Node ts t))\ by blast + then have "sorted_less (leaves (del k x (Node ts t)))" + using "2.prems"(4) sorted_del_list by auto + then have sorted_leaves: "sorted_less (leaves (Node (ls@(del k x sub, sep)#rs) t))" + using list_split Cons h_split + using rebalance_middle_tree_inorder[of t "del k x sub" rs k ls sep] + using "2.prems"(4) "2.prems"(5) IH \leaves (del k x (Node ts t)) = del_list x (leaves (Node ts t))\ del_list_split_aligned del_list_split_right_aligned + by auto + from IH have "aligned l (del k x (Node ts t)) u" + proof - + have "aligned l (Node (ls@(del k x sub, sep)#rs) t) u" + using "2.prems"(5) IH h_split list_conc local.Cons l_split + using aligned_subst by fastforce + then have "aligned l (rebalance_middle_tree k ls (del k x sub) sep rs t) u" + using rebalance_middle_tree_aligned sorted_leaves + by (smt (verit, best) "2.prems"(1) "2.prems"(2) "2.prems"(3) bal.simps(2) bal_sub_height del_height h_split list_split local.Cons node_sorted_split(3) order_impl_root_order root_order.simps(2) some_child_sub(1) split_set(1)) + then show ?thesis + using list_split Cons h_split + by auto + qed + then show ?thesis + using \leaves (del k x (Node ts t)) = del_list x (leaves (Node ts t))\ by blast + qed + qed +qed + +lemma del_Linorder: + assumes "k > 0" + and "root_order k t" + and "bal t" + and "sorted_less (leaves t)" + and "Laligned t u" + and "x \ u" + shows "leaves (del k x t) = del_list x (leaves t) \ Laligned (del k x t) u" + using assms +proof (induction k x t arbitrary: u rule: del.induct) + case (1 k x xs) + then have "leaves (del k x (Leaf xs)) = del_list x (leaves (Leaf xs))" + by (simp add: insert_list_req) + moreover have "Laligned (del k x (Leaf xs)) u" + proof - + have "\x \ set xs - {x}. x \ u" + using "1.prems"(5) by auto + then show ?thesis + using set_del_list insert_list_req + by (metis "1"(4) Laligned.simps(1) del.simps(1) leaves.simps(1)) + qed + ultimately show ?case + by simp +next + case (2 k x ts t u) + then obtain ls rs where list_split: "split ts x = (ls, rs)" + by (meson surj_pair) + then have list_conc: "ts = ls @ rs" + using split_set.split_conc split_set_axioms by blast + show ?case + proof (cases rs) + case Nil + then obtain ls' lsub lsep where ls_split: "ls = ls' @ [(lsub,lsep)]" + by (metis "2.prems"(2) append_Nil2 list.size(3) list_conc old.prod.exhaust root_order.simps(2) snoc_eq_iff_butlast zero_less_iff_neq_zero) + then have IH: "leaves (del k x t) = del_list x (leaves t) \ aligned lsep (del k x t) u" + by (metis (no_types, lifting) "2.prems"(1) "2.prems"(2) "2.prems"(3) "2.prems"(4) "2.prems"(5) "2.prems"(6) Lalign_last Laligned_sorted_separators bal.simps(2) del_inorder list_conc list_split local.Nil order_impl_root_order root_order.simps(2) self_append_conv sorted_leaves_induct_last sorted_snoc split_set.split_req(2) split_set_axioms) + have "leaves (del k x (Node ts t)) = leaves (rebalance_last_tree k ts (del k x t))" + using list_split Nil list_conc by auto + also have "\ = leaves_list ts @ leaves (del k x t)" + proof - + obtain ts' sub sep where ts_split: "ts = ts' @ [(sub, sep)]" + using \ls = ls' @ [(lsub, lsep)]\ list_conc local.Nil by blast + then have "height sub = height t" + using "2.prems"(3) by auto + moreover have "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)) + ultimately show ?thesis + using rebalance_last_tree_inorder + using ts_split by auto + qed + also have "\ = leaves_list ts @ del_list x (leaves t)" + using IH by blast + also have "\ = del_list x (leaves (Node ts t))" + by (metis "2.prems"(4) "2.prems"(5) append_self_conv2 concat.simps(1) list.simps(8) list_conc list_split local.Nil self_append_conv split_set.del_list_split split_set_axioms) + finally have 0: "leaves (del k x (Node ts t)) = del_list x (leaves (Node ts t))" . + moreover have "Laligned (del k x (Node ts t)) u" + proof - + have "Laligned (Node ls (del k x t)) u" + using IH list_conc Nil "2.prems" ls_split + by (metis Laligned_subst_last self_append_conv) + moreover have "sorted_less (leaves (Node ls (del k x t)))" + using "2.prems"(4) \leaves_list ts @ del_list x (leaves t) = del_list x (leaves (Node ts t))\ \leaves_list ts @ leaves (del k x t) = leaves_list ts @ del_list x (leaves t)\ list_conc local.Nil sorted_del_list + by auto + ultimately have "Laligned (rebalance_last_tree k ls (del k x t)) u" + using rebalance_last_tree_Laligned + by (metis (no_types, lifting) "2.prems"(1) "2.prems"(2) "2.prems"(3) UnCI bal.simps(2) del_height list.set_intros(1) list_conc ls_split order_impl_root_order root_order.simps(2) set_append some_child_sub(1)) + then show ?thesis using list_split ls_split "2.prems" Nil + by simp + qed + ultimately show ?thesis + by simp + next + case (Cons h rs) + then obtain sub sep where h_split: "h = (sub,sep)" + by (cases h) + then have node_sorted_split: + "sorted_less (leaves (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+ + { + assume IH: "leaves (del k x sub) = del_list x (leaves sub)" + have "leaves (del k x (Node ts t)) = leaves (rebalance_middle_tree k ls (del k x sub) sep rs t)" + using Cons list_split h_split "2.prems" + by auto + also have "\ = leaves (Node (ls@(del k x sub, sep)#rs) t)" + using rebalance_middle_tree_inorder[of t "del k x sub" rs] + by (smt (verit) "2.prems"(1) "2.prems"(2) "2.prems"(3) bal.simps(2) bal_sub_height del_height h_split list_split local.Cons node_sorted_split(3) order_impl_root_order rebalance_middle_tree_inorder root_order.simps(2) some_child_sub(1) split_set(1)) + also have "\ = leaves_list ls @ leaves (del k x sub) @ leaves_list rs @ leaves t" + by auto + also have "\ = leaves_list ls @ del_list x (leaves sub @ leaves_list rs @ leaves t)" + using del_list_split_right[of ts t u x ls sub sep rs] + using list_split Cons "2.prems"(4,5) h_split IH list_conc + by auto + also have "\ = del_list x (leaves_list ls @ leaves sub @ leaves_list rs @ leaves t)" + using del_list_split[of ts t u x ls "(sub,sep)#rs"] + using list_split Cons "2.prems"(4,5) h_split IH list_conc + by auto + finally have "leaves (del k x (Node ts t)) = del_list x (leaves (Node ts t))" + using list_conc Cons h_split + by auto + } + then show ?thesis + proof (cases ls) + case Nil + then have IH: "leaves (del k x sub) = del_list x (leaves sub) \ Laligned (del k x sub) sep" + by (smt (verit, ccfv_threshold) "2.IH"(2) "2.prems"(1) "2.prems"(2) "2.prems"(5) Laligned_nonempty_Node Laligned_sorted_separators append_self_conv2 bal.simps(2) h_split list.set_intros(1) list_conc 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_leaves_induct_subtree sorted_wrt_append split_set.split_req(3) split_set_axioms) + then have "leaves (del k x (Node ts t)) = del_list x (leaves (Node ts t))" + using \leaves (del k x sub) = del_list x (leaves sub) \ leaves (del k x (Node ts t)) = del_list x (leaves (Node ts t))\ by blast + then have "sorted_less (leaves (del k x (Node ts t)))" + using "2.prems"(4) sorted_del_list by auto + then have sorted_leaves: "sorted_less (leaves (Node (ls@(del k x sub, sep)#rs) t))" + using list_split Cons h_split + using rebalance_middle_tree_inorder[of t "del k x sub" rs k ls sep] + using "2.prems"(4) "2.prems"(5) IH \leaves (del k x (Node ts t)) = del_list x (leaves (Node ts t))\ del_list_split del_list_split_right + by auto + from IH have "Laligned (del k x (Node ts t)) u" + proof - + have "Laligned (Node (ls@(del k x sub, sep)#rs) t) u" + using "2.prems"(5) IH h_split list_conc local.Cons local.Nil by auto + then have "Laligned (rebalance_middle_tree k ls (del k x sub) sep rs t) u" + using rebalance_middle_tree_Laligned sorted_leaves + by (smt (verit, best) "2.prems"(1) "2.prems"(2) "2.prems"(3) append_self_conv2 bal.simps(2) bal_sub_height del_height h_split list.set_intros(1) list_conc local.Cons local.Nil order_impl_root_order root_order.simps(2) some_child_sub(1)) + then show ?thesis + using list_split Cons h_split + by auto + qed + then show ?thesis + using \leaves (del k x (Node ts t)) = del_list x (leaves (Node ts t))\ by blast + next + case _: (Cons a list) + then obtain ls' lsub lsep where l_split: "ls = ls'@[(lsub,lsep)]" + by (metis list.discI old.prod.exhaust snoc_eq_iff_butlast) + then have "aligned lsep sub sep" + using "2.prems"(5) Lalign_last Laligned_split_left h_split list_conc local.Cons by blast + then have IH: "leaves (del k x sub) = del_list x (leaves sub) \ aligned lsep (del k x sub) sep" + by (metis "2.prems"(1) "2.prems"(2) "2.prems"(5) Laligned_sorted_separators bal.simps(2) bal_split_left(1) del_inorder h_split l_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_leaves_induct_subtree sorted_snoc split_set.split_req(2) split_set.split_req(3) split_set_axioms split_set(1)) + then have "leaves (del k x (Node ts t)) = del_list x (leaves (Node ts t))" + using \leaves (del k x sub) = del_list x (leaves sub) \ leaves (del k x (Node ts t)) = del_list x (leaves (Node ts t))\ by blast + then have "sorted_less (leaves (del k x (Node ts t)))" + using "2.prems"(4) sorted_del_list by auto + then have sorted_leaves: "sorted_less (leaves (Node (ls@(del k x sub, sep)#rs) t))" + using list_split Cons h_split + using rebalance_middle_tree_inorder[of t "del k x sub" rs k ls sep] + using "2.prems"(4) "2.prems"(5) IH \leaves (del k x (Node ts t)) = del_list x (leaves (Node ts t))\ del_list_split del_list_split_right + by auto + from IH have "Laligned (del k x (Node ts t)) u" + proof - + have "Laligned (Node (ls@(del k x sub, sep)#rs) t) u" + using "2.prems"(5) IH h_split list_conc local.Cons l_split + using Laligned_subst by fastforce + then have "Laligned (rebalance_middle_tree k ls (del k x sub) sep rs t) u" + using rebalance_middle_tree_Laligned sorted_leaves + by (smt (verit, best) "2.prems"(1) "2.prems"(2) "2.prems"(3) bal.simps(2) bal_sub_height del_height h_split list_split local.Cons node_sorted_split(3) order_impl_root_order root_order.simps(2) some_child_sub(1) split_set(1)) + then show ?thesis + using list_split Cons h_split + by auto + qed + then show ?thesis + using \leaves (del k x (Node ts t)) = del_list x (leaves (Node ts t))\ by blast + qed + qed +qed + +lemma reduce_root_order: "\k > 0; almost_order k t\ \ root_order k (reduce_root t)" + apply(cases t) + apply(auto split!: list.splits simp add: order_impl_root_order) + done + +lemma reduce_root_bal: "bal (reduce_root t) = bal t" + apply(cases t) + apply(auto split!: list.splits) + done + + +lemma reduce_root_inorder: "leaves (reduce_root t) = leaves t" + apply (cases t) + apply (auto split!: list.splits) + done + +lemma reduce_root_Laligned: "Laligned (reduce_root t) u = Laligned t u" + apply(cases t) + apply (auto split!: list.splits) + done + +lemma delete_order: "\k > 0; bal t; root_order k t; sorted_less (leaves 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_Linorder: + assumes "k > 0" "root_order k t" "sorted_less (leaves t)" "Laligned t u" "bal t" "x \ u" + shows "leaves (delete k x t) = del_list x (leaves t)" + and "Laligned (delete k x t) u" + using reduce_root_Laligned[of "del k x t" u] reduce_root_inorder[of "del k x t"] + using del_Linorder[of k t u x] + using assms + by simp_all + +corollary delete_Linorder_top: + assumes "k > 0" "root_order k t" "sorted_less (leaves t)" "Laligned t top" "bal t" + shows "leaves (delete k x t) = del_list x (leaves t)" + and "Laligned (delete k x t) top" + using assms delete_Linorder top_greatest + by simp_all + +(* 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" + +fun invar_leaves where "invar_leaves k t = ( + bal t \ + root_order k t \ + Laligned t top +)" + +interpretation S_ordered: Set_by_Ordered where + empty = empty_bplustree and + insert = "insert (Suc k)" and + delete = "delete (Suc k)" and + isin = "isin" and + inorder = "leaves" and + inv = "invar_leaves (Suc k)" +proof (standard, goal_cases) + case (2 s x) + then show ?case + using isin_set_Linorder_top + by simp +next + case (3 s x) + then show ?case + using insert_Linorder_top + by simp +next + case (4 s x) + then show ?case using delete_Linorder_top + by auto +next + case (6 s x) + then show ?case using insert_order insert_bal insert_Linorder_top + by auto +next + case (7 s x) + then show ?case using delete_order delete_bal delete_Linorder_top + by auto +qed (simp add: empty_bplustree_def)+ + + +(* if we remove this, it is not possible to remove the simp rules in subsequent contexts... *) +declare node\<^sub>i.simps[simp del] + +end + + (* 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) + + +lemmas isin_simps2 = sorted_lems sorted_ConsD sorted_snocD + (*-----------------------------*) + +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) + +context split_list +begin + +fun isin_list :: "'a \ 'a list \ bool" where + "isin_list x ks = (case split_list ks x of + (ls,Nil) \ False | + (ls,sep#rs) \ sep = x +)" + +fun insert_list where + "insert_list x ks = (case split_list ks x of + (ls,Nil) \ ls@[x] | + (ls,sep#rs) \ if sep = x then ks else ls@x#sep#rs +)" + +fun delete_list where + "delete_list x ks = (case split_list ks x of + (ls,Nil) \ ks | + (ls,sep#rs) \ if sep = x then ls@rs else ks +)" + +lemmas split_list_conc = split_list_req(1) +lemmas split_list_sorted = split_list_req(2,3) + + +(* lift to split *) + +lemma isin_sorted_split_list: +assumes "sorted_less xs" + and "split_list xs x = (ls, rs)" + shows "(x \ set xs) = (x \ set rs)" +proof (cases ls) + case Nil + then have "xs = rs" + using assms by (auto dest!: split_list_conc) + then show ?thesis by simp +next + case Cons + then obtain ls' sep where ls_tail_split: "ls = ls' @ [sep]" + by (metis list.simps(3) rev_exhaust) + then have x_sm_sep: "sep < x" + using split_list_req(2)[of xs x ls' sep rs] + using assms sorted_cons sorted_snoc + by blast + moreover have "xs = ls@rs" + using assms split_list_conc by simp + ultimately show ?thesis + using isin_sorted[of ls' sep rs] + using assms ls_tail_split + by auto +qed + +lemma isin_sorted_split_list_right: + assumes "split_list ts x = (ls, sep#rs)" + and "sorted_less ts" + shows "x \ set (sep#rs) = (x = sep)" +proof (cases rs) + case Nil + then show ?thesis + by simp +next + case (Cons sep' rs) + from assms have "x < sep'" + by (metis le_less less_trans list.set_intros(1) local.Cons sorted_Cons_iff sorted_wrt_append split_list_conc split_list_sorted(2)) + moreover have "ts = ls@sep#sep'#rs" + using split_list_conc[OF assms(1)] Cons by auto + moreover have "sorted_less (sep#sep'#rs)" + using Cons assms calculation(2) sorted_wrt_append by blast + ultimately show ?thesis + using isin_sorted[of "[sep]" sep' rs x] Cons + by simp +qed + + +theorem isin_list_set: + assumes "sorted_less xs" + shows "isin_list x xs = (x \ set xs)" + using assms + using isin_sorted_split_list[of xs x] + using isin_sorted_split_list_right[of xs x] + by (auto split!: list.splits) + +lemma insert_sorted_split_list: +assumes "sorted_less xs" + and "split_list xs x = (ls, rs)" + shows "ins_list x xs = ls @ ins_list x rs" +proof (cases ls) + case Nil + then have "xs = rs" + using assms by (auto dest!: split_list_conc) + then show ?thesis + using Nil by simp +next + case Cons + then obtain ls' sep where ls_tail_split: "ls = ls' @ [sep]" + by (metis list.simps(3) rev_exhaust) + then have x_sm_sep: "sep < x" + using split_list_req(2)[of xs x ls' sep rs] + using assms sorted_cons sorted_snoc + by blast + moreover have "xs = ls@rs" + using assms split_list_conc by simp + ultimately show ?thesis + using ins_list_sorted[of ls' sep x rs] + using assms ls_tail_split sorted_wrt_append[of "(<)" ls rs] + by auto +qed + +lemma insert_sorted_split_list_right: + assumes "split_list ts x = (ls, sep#rs)" + and "sorted_less ts" + and "x \ sep" + shows "ins_list x (sep#rs) = (x#sep#rs)" +proof - + have "x < sep" + by (meson assms(1) assms(2) assms(3) le_neq_trans split_list_sorted(2)) + then show ?thesis + using ins_list_sorted[of "[]" sep] + using assms + by auto +qed + + +theorem insert_list_set: + assumes "sorted_less xs" + shows "insert_list x xs = ins_list x xs" + using assms split_list_conc + using insert_sorted_split_list[of xs x] + using insert_sorted_split_list_right[of xs x] + by (auto split!: list.splits prod.splits) + +lemma delete_sorted_split_list: +assumes "sorted_less xs" + and "split_list xs x = (ls, rs)" + shows "del_list x xs = ls @ del_list x rs" +proof (cases ls) + case Nil + then have "xs = rs" + using assms by (auto dest!: split_list_conc) + then show ?thesis + using Nil by simp +next + case Cons + then obtain ls' sep where ls_tail_split: "ls = ls' @ [sep]" + by (metis list.simps(3) rev_exhaust) + then have x_sm_sep: "sep < x" + using split_list_req(2)[of xs x ls' sep rs] + using assms sorted_cons sorted_snoc + by blast + moreover have "xs = ls@rs" + using assms split_list_conc by simp + ultimately show ?thesis + using del_list_sorted[of ls' sep rs] + using assms ls_tail_split sorted_wrt_append[of "(<)" ls rs] + by auto +qed + +lemma delete_sorted_split_list_right: + assumes "split_list ts x = (ls, sep#rs)" + and "sorted_less ts" + and "x \ sep" + shows "del_list x (sep#rs) = sep#rs" +proof - + have "sorted_less (sep#rs)" + by (metis assms(1) assms(2) sorted_wrt_append split_list.split_list_conc split_list_axioms) + moreover have "x < sep" + by (meson assms(1) assms(2) assms(3) le_neq_trans split_list_sorted(2)) + ultimately show ?thesis + using del_list_sorted[of "[]" sep rs x] + by simp +qed + + +theorem delete_list_set: + assumes "sorted_less xs" + shows "delete_list x xs = del_list x xs" + using assms split_list_conc[of xs x] + using delete_sorted_split_list[of xs x] + using delete_sorted_split_list_right[of xs x] + by (auto split!: list.splits prod.splits) + +end + +context split_full +begin + +sublocale split_set split isin_list insert_list delete_list + using isin_list_set insert_list_set delete_list_set + by unfold_locales auto + +end + + +end diff --git a/thys/BTree/BPlusTree_Split.thy b/thys/BTree/BPlusTree_Split.thy new file mode 100644 --- /dev/null +++ b/thys/BTree/BPlusTree_Split.thy @@ -0,0 +1,107 @@ +theory BPlusTree_Split +imports BPlusTree +begin + +subsection "Auxiliary functions" + +(* a version of split half that assures the left side to be non-empty *) +fun split_half:: "_ list \ _ list \ _ list" where + "split_half xs = (take ((length xs + 1) div 2) xs, drop ((length xs + 1) div 2) xs)" + +lemma split_half_conc: "split_half xs = (ls, rs) = (xs = ls@rs \ length ls = (length xs + 1) div 2)" + by force + +lemma drop_not_empty: "xs \ [] \ drop (length xs div 2) xs \ []" + apply(induction xs) + apply(auto split!: list.splits) + done + +lemma take_not_empty: "xs \ [] \ take ((length xs + 1) div 2) xs \ []" + apply(induction xs) + apply(auto split!: list.splits) + done + +lemma split_half_not_empty: "length xs \ 1 \ \ls a rs. split_half xs = (ls@[a],rs)" + using take_not_empty + by (metis (no_types, opaque_lifting) Ex_list_of_length One_nat_def le_trans length_Cons list.size(4) nat_1_add_1 not_one_le_zero rev_exhaust split_half.simps take0 take_all_iff) + +subsection "The split function locale" + +text "Here, we abstract away the inner workings of the split function + for B-tree operations." + +lemma leaves_conc: "leaves (Node (ls@rs) t) = leaves_list ls @ leaves_list rs @ leaves t" + apply(induction ls) + apply auto + done + +locale split_tree = + fixes split :: "('a bplustree\'a::{linorder,order_top}) list \ 'a \ (('a bplustree\'a) list \ ('a bplustree\'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 + + lemmas split_conc = split_req(1) + lemmas split_sorted = split_req(2,3) + + + 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 + + + lemma leaves_split: "split ts x = (ls,rs) \ leaves (Node ts t) = leaves_list ls @ leaves_list rs @ leaves t" + using leaves_conc split_conc by blast + +end + +locale split_list = + fixes split_list :: "('a::{linorder,order_top}) list \ 'a \ 'a list \ 'a list" + assumes split_list_req: + "\split_list ks p = (kls,krs)\ \ ks = kls @ krs" + "\split_list ks p = (kls@[sep],krs); sorted_less ks\ \ sep < p" + "\split_list ks p = (kls,(sep)#krs); sorted_less ks\ \ p \ sep" + +locale split_full = split_tree: split_tree split + split_list split_list + for split:: + "('a bplustree \ 'a::{linorder,order_top}) list \ 'a + \ ('a bplustree \ 'a) list \ ('a bplustree \ 'a) list" + and split_list:: + "'a::{linorder,order_top} list \ 'a + \ 'a list \ 'a list" + +section "Abstract split functions" + +subsection "Linear split" + +text "Finally we show that the split axioms are feasible by providing an example split function" + +text "Linear split is similar to well known functions, therefore a quick proof can be done." + +fun linear_split where "linear_split xs x = (takeWhile (\(_,s). s(_,s). ss. ss. si k (bplustree_ls_insert_list x ks)" + by (simp add: bplustree_ls_insert_list_def) +declare bplustree_linear_search.ins.simps(2)[code] + +lemma [code]: "bplustree_ls_del k x (Leaf ks) = +Leaf (bplustree_ls_delete_list x ks)" + by (simp add: bplustree_ls_delete_list_def) +declare bplustree_linear_search.del.simps(2)[code] + +find_theorems bplustree_ls_isin + +text "Some examples follow to show that the implementation works + and the above lemmas make sense. The examples are visualized in the thesis." + +abbreviation "bplustree\<^sub>q \ bplustree_ls_isin" +abbreviation "bplustree\<^sub>i \ bplustree_ls_insert" +abbreviation "bplustree\<^sub>d \ bplustree_ls_delete" + +definition "uint8_max \ 2^8-1::nat" +declare uint8_max_def[simp] + +typedef uint8 = "{n::nat. n \ uint8_max}" + by auto + +setup_lifting type_definition_uint8 + +instantiation uint8 :: linorder +begin + +lift_definition less_eq_uint8 :: "uint8 \ uint8 \ bool" + is "(less_eq::nat \ nat \ bool)" . + +lift_definition less_uint8 :: "uint8 \ uint8 \ bool" + is "(less::nat \ nat \ bool)" . + +instance + by standard (transfer; auto)+ +end + +instantiation uint8 :: order_top +begin + +lift_definition top_uint8 :: uint8 is "uint8_max::nat" + by simp + + +instance + by standard (transfer; simp) +end + + +instantiation uint8 :: numeral +begin + +lift_definition one_uint8 :: uint8 is "1::nat" + by auto + +lift_definition plus_uint8 :: "uint8 \ uint8 \ uint8" + is "\a b. min (a + b) uint8_max" + by simp + +instance by standard (transfer; auto) +end + +instantiation uint8 :: equal +begin + +lift_definition equal_uint8 :: "uint8 \ uint8 \ bool" + is "(=)" . + +instance by standard (transfer; auto) +end + + +value "uint8_max" + +value "let k=2::nat; x::uint8 bplustree = (Node [(Node [(Leaf [1,2], 2),(Leaf [3,4], 4),(Leaf [5,6,7], 8)] (Leaf [9,10]), 10)] (Node [(Leaf [11,12,13,14], 14), (Leaf [15,17], 20)] (Leaf [21,22,23]))) in + root_order k x" +value "let k=2::nat; x::uint8 bplustree = (Node [(Node [(Leaf [1,2], 2),(Leaf [3,4], 4),(Leaf [5,6,7], 8)] (Leaf [9,10]), 10)] (Node [(Leaf [11,12,13,14], 14), (Leaf [15,17], 20)] (Leaf [21,22,23]))) in + bal x" +value "let k=2::nat; x::uint8 bplustree = (Node [(Node [(Leaf [1,2], 2),(Leaf [3,4], 4),(Leaf [5,6,7], 8)] (Leaf [9,10]), 10)] (Node [(Leaf [11,12,13,14], 14), (Leaf [15,17], 20)] (Leaf [50,55,56]))) in + sorted_less (leaves x)" +value "let k=2::nat; x::uint8 bplustree = (Node [(Node [(Leaf [1,2], 2),(Leaf [3,4], 4),(Leaf [5,6,7], 8)] (Leaf [9,10]), 10)] (Node [(Leaf [11,12,13,14], 14), (Leaf [15,17], 20)] (Leaf [50,55,56]))) in + Laligned x top" +value "let k=2::nat; x::uint8 bplustree = (Node [(Node [(Leaf [1,2], 2),(Leaf [3,4], 4),(Leaf [5,6,7], 8)] (Leaf [9,10]), 10)] (Node [(Leaf [11,12,13,14], 14), (Leaf [15,17], 20)] (Leaf [50,55,56]))) in + x" +value "let k=2::nat; x::uint8 bplustree = (Node [(Node [(Leaf [1,2], 2),(Leaf [3,4], 4),(Leaf [5,6,7], 8)] (Leaf [9,10]), 10)] (Node [(Leaf [11,12,13,14], 14), (Leaf [15,17], 20)] (Leaf [50,55,56]))) in + bplustree\<^sub>q x 4" +value "let k=2::nat; x::uint8 bplustree = (Node [(Node [(Leaf [1,2], 2),(Leaf [3,4], 4),(Leaf [5,6,7], 8)] (Leaf [9,10]), 10)] (Node [(Leaf [11,12,13,14], 14), (Leaf [15,17], 20)] (Leaf [50,55,56]))) in + bplustree\<^sub>q x 20" +value "let k=2::nat; x::uint8 bplustree = (Node [(Node [(Leaf [1,2], 2),(Leaf [3,4], 4),(Leaf [5,6,7], 8)] (Leaf [9,10]), 10)] (Node [(Leaf [11,12,13,14], 14), (Leaf [15,17], 20)] (Leaf [50,55,56]))) in + bplustree\<^sub>i k 9 x" +value "let k=2::nat; x::uint8 bplustree = (Node [(Node [(Leaf [1,2], 2),(Leaf [3,4], 4),(Leaf [5,6,7], 8)] (Leaf [9,10]), 10)] (Node [(Leaf [11,12,13,14], 14), (Leaf [15,17], 20)] (Leaf [50,55,56]))) in + bplustree\<^sub>i k 1 (bplustree\<^sub>i k 9 x)" +value "let k=2::nat; x::uint8 bplustree = (Node [(Node [(Leaf [1,2], 2),(Leaf [3,4], 4),(Leaf [5,6,7], 8)] (Leaf [9,10]), 10)] (Node [(Leaf [11,12,13,14], 14), (Leaf [15,17], 20)] (Leaf [50,55,56]))) in + bplustree\<^sub>d k 10 (bplustree\<^sub>i k 1 (bplustree\<^sub>i k 9 x))" +value "let k=2::nat; x::uint8 bplustree = (Node [(Node [(Leaf [1,2], 2),(Leaf [3,4], 4),(Leaf [5,6,7], 8)] (Leaf [9,10]), 10)] (Node [(Leaf [11,12,13,14], 14), (Leaf [15,17], 20)] (Leaf [50,55,56]))) in + bplustree\<^sub>d k 3 (bplustree\<^sub>d k 10 (bplustree\<^sub>i k 1 (bplustree\<^sub>i k 9 x)))" + + +end \ No newline at end of file diff --git a/thys/BTree/Basic_Assn.thy b/thys/BTree/Basic_Assn.thy --- a/thys/BTree/Basic_Assn.thy +++ b/thys/BTree/Basic_Assn.thy @@ -1,50 +1,195 @@ theory Basic_Assn imports "Refine_Imperative_HOL.Sepref_HOL_Bindings" "Refine_Imperative_HOL.Sepref_Basic" begin section "Auxilary imperative assumptions" text "The following auxiliary assertion types and lemmas were provided by Peter Lammich" subsection \List-Assn\ lemma list_assn_cong[fundef_cong]: "\ xs=xs'; ys=ys'; \x y. \ x\set xs; y\set ys \ \ A x y = A' x y \ \ list_assn A xs ys = list_assn A' xs' ys'" by (induction xs ys arbitrary: xs' ys' rule: list_assn.induct) auto lemma list_assn_app_one: "list_assn P (l1@[x]) (l1'@[y]) = list_assn P l1 l1' * P x y" by simp (* ------------------ ADDED by NM in course of btree_imp -------- *) lemma list_assn_len: "h \ list_assn A xs ys \ length xs = length ys" using list_assn_aux_ineq_len by fastforce lemma list_assn_append_Cons_left: "list_assn A (xs@x#ys) zs = (\\<^sub>A zs1 z zs2. list_assn A xs zs1 * A x z * list_assn A ys zs2 * \(zs1@z#zs2 = zs))" by (sep_auto simp add: list_assn_aux_cons_conv list_assn_aux_append_conv1 intro!: ent_iffI) -lemma list_assn_aux_append_Cons: +lemma list_assn_aux_append_Cons: shows "length xs = length zsl \ list_assn A (xs@x#ys) (zsl@z#zsr) = (list_assn A xs zsl * A x z * list_assn A ys zsr) " by (sep_auto simp add: mult.assoc) +lemma list_assn_prod_split: "list_assn (\x y. P x y * Q x y) as bs = list_assn P as bs * list_assn Q as bs" +proof(cases "length as = length bs") + case True + then show ?thesis + proof (induction rule: list_induct2) + case Nil + then show ?case by sep_auto + next + case (Cons x xs y ys) + show ?case + proof (rule ent_iffI, goal_cases) + case 1 + then show ?case + using Cons by sep_auto + next + case 2 + then show ?case + using Cons by sep_auto + qed + qed +next + case False + then show ?thesis + by (simp add: list_assn_aux_ineq_len) +qed (* -------------------------------------------- *) subsection \Prod-Assn\ lemma prod_assn_cong[fundef_cong]: - "\ p=p'; pi=pi'; A (fst p) (fst pi) = A' (fst p) (fst pi); B (snd p) (snd pi) = B' (snd p) (snd pi) \ - \ (A\\<^sub>aB) p pi = (A'\\<^sub>aB') p' pi'" + "\ p=p'; pi=pi'; A (fst p) (fst pi) = A' (fst p) (fst pi); B (snd p) (snd pi) = B' (snd p) (snd pi) \ + \ (A\\<^sub>aB) p pi = (A'\\<^sub>aB') p' pi'" apply (cases p; cases pi) by auto +subsection \Assertions and Magic Wand\ + +lemma entails_preI: "(\h. h \ P \ P \\<^sub>A Q) \ P \\<^sub>A Q" + unfolding entails_def + by auto + +lemma ent_true_drop_true: + "P*true\\<^sub>AQ*true \ P*R*true\\<^sub>AQ*true" + using assn_aci(10) ent_true_drop(1) by presburger + +(* TODO *) +lemma rem_true: "P*true \\<^sub>A Q*true \ P \\<^sub>AQ*true" + using enttD enttI_true by blast + +lemma assn_eq_split: + assumes "B = C" + shows "B \\<^sub>A C" + and "C \\<^sub>A B" + by (simp_all add: assms) + +lemma ent_ex_inst: "\\<^sub>Ax. P x \\<^sub>A Q \ P y \\<^sub>A Q" + using ent_trans by blast + +lemma ent_ex_inst2: "\\<^sub>Ax y. P x y \\<^sub>A Q \ P x y \\<^sub>A Q" + using ent_trans by blast + +lemma ent_wandI2: + assumes IMP: "P \\<^sub>A (Q -* R)" + shows "Q*P \\<^sub>A R" + using assms + unfolding entails_def +(* by (meson assms ent_fwd ent_mp ent_refl fr_rot mod_frame_fwd)*) +proof (clarsimp, goal_cases) + case (1 h as) + then obtain as1 as2 where "as = as1 \ as2" "as1 \ as2 = {}" "(h,as1) \ Q" "(h,as2) \ P" + by (metis mod_star_conv prod.inject) + then have "(h,as2) \ (Q-*R)" + by (simp add: "1"(1)) + then have "(h,as1\as2) \ Q * (Q-*R)" + by (simp add: \(h, as1) \ Q\ \as1 \ as2 = {}\ star_assnI) + then show ?case + using \as = as1 \ as2\ ent_fwd ent_mp by blast +qed + +lemma ent_wand: "(P \\<^sub>A (Q -* R)) = (Q*P \\<^sub>A R)" + using ent_wandI2 ent_wandI by blast + +lemma wand_ent_trans: + assumes "P' \\<^sub>A P" + and "Q \\<^sub>A Q'" + shows "P -* Q \\<^sub>A P' -* Q'" + by (meson assms(1) assms(2) ent_wand ent_frame_fwd ent_refl ent_trans) + +lemma wand_elim: "(P -* Q) * (Q -* R) \\<^sub>A (P -* R)" + by (metis ent_wand ent_frame_fwd ent_mp ent_refl star_assoc) + +lemma emp_wand_same: "emp \\<^sub>A (H -* H)" + by (simp add: ent_wandI) + +lemma emp_wand_equal: "(emp -* H) = H" + apply(intro ent_iffI) + apply (metis ent_mp norm_assertion_simps(1)) + by (simp add: ent_wandI) + +lemma pure_wand_equal: "P \ (\(P) -* H) = H" + by (simp add: emp_wand_equal) + +lemma pure_wand_ent: "(P \ (H1 \\<^sub>A H2)) \ H1 \\<^sub>A \(P) -* H2" + by (simp add: ent_wand) + +lemma "\(P \ Q) \\<^sub>A (\(P) -* \(Q))" + by (simp add: pure_wand_ent) + +lemma wand_uncurry: "(P*Q) -* R \\<^sub>A P -* (Q -* R)" + by (simp add: assn_aci ent_mp ent_wandI fr_rot) + +lemma wand_absorb: "(P -* Q) * R \\<^sub>A (P -* (Q * R))" + by (smt (z3) ent_mp ent_refl ent_star_mono ent_wandI star_aci(2) star_aci(3)) + +lemma wand_ent_self: "P \\<^sub>A Q -* (Q * P)" + by (simp add: ent_wandI) + +lemma wand_ent_cancel: "P * ((P * Q) -* R) \\<^sub>A Q -* R" + by (simp add: ent_wandI2 wand_uncurry) + + +lemma "\R. Q * R \\<^sub>A P" + using ent_mp by auto + +lemma "P \\<^sub>A Q * true \ P = Q * (Q -* P)" + apply(intro ent_iffI) +proof(goal_cases) + case 2 + then show ?case + by (simp add: ent_mp) +next + case test: 1 + show ?case + unfolding entails_def + apply clarsimp + proof (goal_cases) + case (1 a b) + then have "(a,b) \ Q * true" + using test entails_def + by blast + then obtain h as1 as2 where *: + "(a,b) = (h, as1 \ as2) \ as1 \ as2 = {} \ (h, as1) \ Q \ (h, as2) \ true" + using mod_star_conv by auto + then have "(h, as1 \ as2) \ P" "(a,b) = (h, as1 \ as2)" + using "1" by blast+ + then show ?case + apply simp + thm star_assnI + apply(intro star_assnI) + apply (simp_all add: *) + apply(intro wand_assnI) + apply (meson "*" models_in_range) + apply auto + oops + end \ No newline at end of file diff --git a/thys/BTree/Flatten_Iter.thy b/thys/BTree/Flatten_Iter.thy new file mode 100644 --- /dev/null +++ b/thys/BTree/Flatten_Iter.thy @@ -0,0 +1,390 @@ +theory Flatten_Iter + imports + Basic_Assn + "Separation_Logic_Imperative_HOL.Imp_List_Spec" + "HOL-Real_Asymp.Inst_Existentials" +begin + + +text "This locale takes an iterator that refines a list of elements that themselves +can be iterated and defines an iterator over the flattened list of lower level elements" + +locale flatten_iter = + inner_list: imp_list_iterate is_inner_list inner_is_it inner_it_init inner_it_has_next inner_it_next + + outer_list: imp_list_iterate is_outer_list outer_is_it outer_it_init outer_it_has_next outer_it_next + for is_outer_list :: "'l list \ 'm \ assn" + and outer_is_it :: "'l list \ 'm \ 'l list \ 'oit \ assn" + and outer_it_init :: "'m \ ('oit) Heap" + and outer_it_has_next :: "'oit \ bool Heap" + and outer_it_next :: "'oit \ ('l\'oit) Heap" + and is_inner_list :: "'a list \ 'l \ assn" + and inner_is_it :: "'a list \ 'l \ 'a list \ 'iit \ assn" + and inner_it_init :: "'l \ ('iit) Heap" + and inner_it_has_next :: "'iit \ bool Heap" + and inner_it_next :: "'iit \ ('a\'iit) Heap" +begin + +fun is_flatten_list :: "'a list \ 'm \ assn" where + "is_flatten_list ls lsi = (\\<^sub>A lsi' ls'. + is_outer_list lsi' lsi * list_assn is_inner_list ls' lsi' * \(ls = concat ls') +)" + +lemma flatten_prec: + "precise is_flatten_list" + apply (intro preciseI) + apply (auto) +proof (goal_cases) + case (1 aa b p F F' lsi' ls' lsi'a ls'a) + then have *: + "\G G'. (aa, b) \ list_assn is_inner_list ls'a lsi'a * G \\<^sub>A list_assn is_inner_list ls' lsi' * G'" + by (smt (z3) assn_aci(10) assn_times_comm) + + have "lsi' = lsi'a" + using 1 + by (metis outer_list.precise preciseD star_assoc) + moreover have "length ls'a = length lsi'a" "length ls' = length lsi'" + using 1 by (auto simp add: mod_and_dist dest!: mod_starD list_assn_len) + ultimately have "length ls' = length lsi'" "length lsi' = length lsi'a" "length lsi'a = length ls'a" + by auto + then show ?case + using * \lsi' = lsi'a\ + proof(induction ls' lsi' lsi'a ls'a arbitrary: p rule: list_induct4) + case Nil + then show ?case by auto + next + case (Cons x xs y ys z zs w ws) + then have "concat ws = concat xs" + apply simp + by (metis (no_types, opaque_lifting) ab_semigroup_mult_class.mult.left_commute star_assoc) + moreover have "x = w" + using "Cons.prems" preciseD[OF inner_list.precise, where h="(aa,b)"] + apply(simp) + using assn_times_assoc by fastforce + ultimately show ?case + by auto + qed +qed + +(*type_synonym flatten_it = "'iit \ 'oit"*) +fun is_flatten_it :: "'a list \ 'm \ 'a list \ ('oit \ 'iit option) \ assn" + where +"is_flatten_it ls lsi [] (oit, None) = + (\\<^sub>A lsi' lsi''. + list_assn is_inner_list lsi'' lsi' * + \(ls = (concat lsi'')) * + outer_is_it lsi' lsi [] oit +)" | +"is_flatten_it ls lsi ls2 (oit, Some iit) = + (\\<^sub>A lsi' ls2' ls1' lsi1 lsi2 lsim ls2m lsm ls1m. + list_assn is_inner_list ls1' lsi1 * + list_assn is_inner_list ls2' lsi2 * + \(ls2m \ [] \ ls2 = ls2m@(concat ls2') \ ls = (concat (ls1'@lsm#ls2'))) * + outer_is_it lsi' lsi lsi2 oit * + \(lsm = ls1m@ls2m \ lsi'=(lsi1@lsim#lsi2)) * + inner_is_it lsm lsim ls2m iit +) +" | +"is_flatten_it _ _ _ _ = false" + +partial_function (heap) flatten_it_adjust:: "'oit \ 'iit \ ('oit \ 'iit option) Heap" where +"flatten_it_adjust oit iit = do { + ihasnext \ inner_it_has_next iit; + if ihasnext then + return (oit, Some iit) + else do { + ohasnext \ outer_it_has_next oit; + if \ohasnext then + return (oit, None) + else do { + (next, oit) \ outer_it_next oit; + nextit \ inner_it_init next; + flatten_it_adjust oit nextit + } + } + } +" + +thm list_assn_len + +lemma flatten_it_adjust_rule: + " + flatten_it_adjust oit iit + \<^sub>t" +proof (induction ls2 arbitrary: ls1' ls1 ls2' lsim lsm1 lsm2 oit iit) + case Nil + then show ?case + apply(subst flatten_it_adjust.simps) + apply (sep_auto eintros del: exI heap add: inner_list.it_has_next_rule) + apply(inst_existentials "(ls1 @ lsim # [])" ls2' ls1' ls1 "[]::'l list" lsim lsm2 "lsm1@lsm2") + subgoal by auto + subgoal by (sep_auto) + apply (vcg (ss)) + apply (vcg (ss)) + apply (vcg (ss)) + apply (vcg (ss)) + apply (vcg (ss)) + apply (vcg (ss)) + apply (vcg (ss)) + subgoal + apply (vcg (ss)) + apply (sep_auto eintros del: exI) + apply(inst_existentials "(ls1 @ [lsim])" "ls1'@[lsm1]") + subgoal by auto + subgoal + apply(auto simp add: list_assn_app_one) + using inner_list.quit_iteration + by (smt (z3) assn_aci(9) assn_times_comm ent_true_drop(1) fr_refl) + done + done +next + case (Cons a ls2) + show ?case + apply(subst flatten_it_adjust.simps) + apply (sep_auto eintros del: exI heap add: inner_list.it_has_next_rule) + apply(inst_existentials "(ls1 @ lsim # a # ls2)" ls2' ls1' ls1 "a #ls2" lsim lsm2 "lsm1@lsm2") + subgoal by auto + subgoal by (sep_auto) + apply (vcg (ss)) + apply (vcg (ss)) + apply (vcg (ss)) + apply (vcg (ss)) + apply (vcg (ss)) + apply (vcg (ss)) + apply (vcg (ss)) + subgoal by simp + apply (vcg (ss)) + apply (vcg (ss)) + apply (vcg (ss)) + apply (vcg (ss)) + apply (vcg (ss)) + apply (vcg (ss)) + apply (vcg (ss)) + apply (vcg (ss)) + apply (case_tac ls2') + apply simp_all + apply (sep_auto eintros del: exI heap add: inner_list.it_init_rule) + subgoal for x oit aa list xa + supply R = "Cons.IH"[of "ls1'@[lsm1]" "ls1@[lsim]" list a oit "[]::'a list" aa xa, simplified] + thm R + find_theorems "_ \\<^sub>A _" "<_>_<_>" + supply Q = Hoare_Triple.cons_pre_rule[of +"inner_is_it aa a aa xa * outer_is_it (ls1 @ lsim # a # ls2) lsi ls2 oit * + inner_is_it lsm1 lsim [] iit * + list_assn is_inner_list ls1' ls1 * + list_assn is_inner_list list ls2 * + true" +"list_assn is_inner_list ls1' ls1 * is_inner_list lsm1 lsim * list_assn is_inner_list list ls2 * + outer_is_it (ls1 @ lsim # a # ls2) lsi ls2 oit * + inner_is_it aa a aa + xa * true" +] + thm Q + apply(rule Q) + prefer 2 + subgoal by (sep_auto heap add: R intro: inner_list.quit_iteration) + subgoal using inner_list.quit_iteration + by (smt (z3) assn_aci(10) assn_times_comm ent_refl_true ent_star_mono_true) + done + done +qed + +definition flatten_it_init :: "'m \ _ Heap" + where "flatten_it_init l = do { + oit \ outer_it_init l; + ohasnext \ outer_it_has_next oit; + if ohasnext then do { + (next, oit) \ outer_it_next oit; + nextit \ inner_it_init next; + flatten_it_adjust oit nextit + } else return (oit, None) +}" + +lemma flatten_it_init_rule[sep_heap_rules]: + " flatten_it_init p \<^sub>t" + unfolding flatten_it_init_def + apply simp + apply(rule norm_pre_ex_rule)+ + apply (vcg (ss)) + apply (vcg (ss)) + apply (vcg (ss)) + apply (vcg (ss)) + apply (vcg (ss)) + apply (vcg (ss)) + apply (vcg (ss)) + apply (vcg (ss)) + apply (vcg (ss)) + apply (vcg (ss)) + apply (vcg (ss)) + subgoal for lsi' ls' x xa + apply (vcg (ss)) + apply (vcg (ss)) + apply (vcg (ss)) + apply (vcg (ss)) + apply (vcg (ss)) + apply (vcg (ss)) + apply (vcg (ss)) + apply(case_tac lsi'; case_tac ls') + apply simp+ + apply(rule impI) + thm inner_list.it_init_rule + apply (vcg heap add: inner_list.it_init_rule) + subgoal for _ nxt oit a list aa lista xaa + supply R = flatten_it_adjust_rule[of "[]" "[]" lista list a p oit "[]" aa xaa, simplified] + thm R + apply (sep_auto heap add: R) + done + done + apply (sep_auto eintros del: exI) + apply(inst_existentials "[]::'l list" "[]::'a list list" "[]::'a list list" "[]::'l list" "[]::'l list") + apply simp_all + done + +definition flatten_it_next where + "flatten_it_next \ \(oit,iit). do { + (x, iit) \ inner_it_next (the iit); + (oit, iit) \ flatten_it_adjust oit iit; + return (x, (oit,iit)) + }" + +lemma flatten_it_next_rule: + " l' \ [] \ + + flatten_it_next it + <\(a,it'). is_flatten_it l p (tl l') it' * \(a=hd l')>\<^sub>t" + apply(subst flatten_it_next_def) + thm inner_list.it_next_rule + apply (vcg (ss)) + apply (vcg (ss)) + apply(case_tac iit; case_tac l') + apply simp_all + apply(rule norm_pre_ex_rule)+ + subgoal for oit iit a aa list lsi' ls2' ls1' lsi1 lsi2 lsim ls2m lsm ls1m + apply(vcg (ss)) + apply(vcg (ss)) + apply(vcg (ss)) + apply(vcg (ss)) + apply(vcg (ss)) + apply(vcg (ss)) + apply(vcg (ss)) + apply(vcg (ss)) + apply(vcg (ss)) + apply(case_tac ls2m) + apply simp_all + subgoal for _ _ iita lista + supply R = flatten_it_adjust_rule[of ls1' lsi1 ls2' lsi2 lsim p oit "ls1m@[aa]" "lista" iita, simplified] + thm R + apply (sep_auto heap add: R) + done + done + done + +definition flatten_it_has_next where + "flatten_it_has_next \ \(oit, iit). do { + return (iit \ None) +}" + +lemma flatten_it_has_next_rule[sep_heap_rules]: + " + flatten_it_has_next it + <\r. is_flatten_it l p l' it * \(r\l'\[])>\<^sub>t" + apply(subst flatten_it_has_next_def) + apply(sep_auto) + apply(case_tac iit, case_tac l') + apply simp_all + apply sep_auto + done + +declare mult.left_assoc[simp add] +lemma flatten_quit_iteration: + "is_flatten_it l p l' it \\<^sub>A is_flatten_list l p * true" + apply(cases it) + subgoal for oit iit + apply(cases iit; cases l') + proof (goal_cases) + case 1 + then show ?case + apply (sep_auto eintros del: exI) + subgoal for lsi' lsi'' + apply(inst_existentials lsi' lsi'') + subgoal by auto + subgoal by (metis (no_types, lifting) assn_aci(10) assn_times_comm fr_refl outer_list.quit_iteration) + done + done + next + case (2 lsim ll') + then show ?case + by (sep_auto eintros del: exI) + next + case (3 iit) + then show ?case + by (sep_auto eintros del: exI) + next + case (4 iit lsim ll') + then show ?case + apply (sep_auto eintros del: exI) + subgoal for lsi' ls2' ls1' lsi1 lsi2 lsima ls2m lsm ls1m + apply(inst_existentials "(lsi1 @ lsima # lsi2)" "ls1'@(ls1m@ls2m)#ls2'") + subgoal by auto + subgoal + apply(rule impI; rule entails_preI) + apply (auto dest!: mod_starD list_assn_len) + apply(simp add: + mult.commute[where ?b="outer_is_it (lsi1 @ lsima # lsi2) p lsi2 oit"] + mult.commute[where ?b="is_outer_list (lsi1 @ lsima # lsi2) p"] + mult.left_assoc) + apply(rule rem_true) + supply R = ent_star_mono_true[of + "outer_is_it (lsi1 @ lsima # lsi2) p lsi2 oit" + "is_outer_list (lsi1 @ lsima # lsi2) p" + "list_assn is_inner_list ls1' lsi1 * + list_assn is_inner_list ls2' lsi2 * + inner_is_it (ls1m @ ls2m) lsima ls2m iit" + " list_assn is_inner_list ls1' lsi1 * + is_inner_list (ls1m @ ls2m) lsima * + list_assn is_inner_list ls2' lsi2" + ,simplified] + thm R + apply(rule R) + subgoal by (rule outer_list.quit_iteration) + apply(simp add: + mult.commute[where ?b="inner_is_it (ls1m @ ls2m) lsima ls2m iit"] + mult.commute[where ?b="is_inner_list (ls1m @ ls2m) lsima"] + mult.left_assoc) + apply(rule rem_true) + supply R = ent_star_mono_true[of + "inner_is_it (ls1m @ ls2m) lsima ls2m iit" + "is_inner_list (ls1m @ ls2m) lsima" + "list_assn is_inner_list ls1' lsi1 * + list_assn is_inner_list ls2' lsi2" + " list_assn is_inner_list ls1' lsi1 * + list_assn is_inner_list ls2' lsi2" + ,simplified] + thm R + apply(rule R) + subgoal by (rule inner_list.quit_iteration) + subgoal by sep_auto + done + done + done + qed + done +declare mult.left_assoc[simp del] + +interpretation flatten_it: imp_list_iterate is_flatten_list is_flatten_it flatten_it_init flatten_it_has_next flatten_it_next + apply(unfold_locales) + subgoal + by (rule flatten_prec) + subgoal for l p + by (rule flatten_it_init_rule[of l p]) + subgoal for l' l p it + thm flatten_it_next_rule + by (rule flatten_it_next_rule[of l' l p it]) + subgoal for l p l' it + by (rule flatten_it_has_next_rule[of l p l' it]) + subgoal for l p l' it + by (rule flatten_quit_iteration[of l p l' it]) + done +end + +end \ No newline at end of file diff --git a/thys/BTree/Flatten_Iter_Spec.thy b/thys/BTree/Flatten_Iter_Spec.thy new file mode 100644 --- /dev/null +++ b/thys/BTree/Flatten_Iter_Spec.thy @@ -0,0 +1,356 @@ +theory Flatten_Iter_Spec + imports + Basic_Assn + "Separation_Logic_Imperative_HOL.Imp_List_Spec" + "HOL-Real_Asymp.Inst_Existentials" +begin + + +text "This locale takes an iterator that refines a list of elements that themselves +can be iterated and defines an iterator over the flattened list of lower level elements" + +locale flatten_iter = + inner_list: imp_list_iterate is_inner_list inner_is_it inner_it_init inner_it_has_next inner_it_next + + outer_list: imp_list_iterate is_outer_list outer_is_it outer_it_init outer_it_has_next outer_it_next + for is_outer_list :: "'l list \ 'm \ assn" + and outer_is_it :: "'l list \ 'm \ 'l list \ 'oit \ assn" + and outer_it_init :: "'m \ ('oit) Heap" + and outer_it_has_next :: "'oit \ bool Heap" + and outer_it_next :: "'oit \ ('l\'oit) Heap" + and is_inner_list :: "'a list \ 'l \ assn" + and inner_is_it :: "'a list \ 'l \ 'a list \ 'iit \ assn" + and inner_it_init :: "'l \ ('iit) Heap" + and inner_it_has_next :: "'iit \ bool Heap" + and inner_it_next :: "'iit \ ('a\'iit) Heap" +begin + + +fun is_flatten_list :: "'a list list \ 'a list \ 'm \ assn" where + "is_flatten_list ls' ls lsi = (\\<^sub>A lsi'. + is_outer_list lsi' lsi * list_assn is_inner_list ls' lsi' * \(ls = concat ls') +)" + +lemma flatten_prec: + "precise (is_flatten_list ls)" + apply (intro preciseI) + apply (auto) + done + +(*type_synonym flatten_it = "'iit \ 'oit"*) +fun is_flatten_it :: "'a list list \ 'a list \ 'm \ 'a list \ ('oit \ 'iit option) \ assn" + where +"is_flatten_it lsi'' ls lsi [] (oit, None) = + (\\<^sub>A lsi'. + list_assn is_inner_list lsi'' lsi' * + \(ls = (concat lsi'')) * + outer_is_it lsi' lsi [] oit +)" | +"is_flatten_it lsi'' ls lsi ls2 (oit, Some iit) = + (\\<^sub>A lsi' ls2' ls1' lsi1 lsi2 lsim ls2m lsm ls1m. + list_assn is_inner_list ls1' lsi1 * + list_assn is_inner_list ls2' lsi2 * + \(ls2m \ [] \ ls2 = ls2m@(concat ls2') \ ls = (concat (ls1'@lsm#ls2')) \ lsi'' = (ls1'@lsm#ls2')) * + outer_is_it lsi' lsi lsi2 oit * + \(lsm = ls1m@ls2m \ lsi'=(lsi1@lsim#lsi2)) * + inner_is_it lsm lsim ls2m iit +) +" | +"is_flatten_it _ _ _ _ _ = false" + +partial_function (heap) flatten_it_adjust:: "'oit \ 'iit \ ('oit \ 'iit option) Heap" where +"flatten_it_adjust oit iit = do { + ihasnext \ inner_it_has_next iit; + if ihasnext then + return (oit, Some iit) + else do { + ohasnext \ outer_it_has_next oit; + if \ohasnext then + return (oit, None) + else do { + (next, oit) \ outer_it_next oit; + nextit \ inner_it_init next; + flatten_it_adjust oit nextit + } + } + } +" + +declare flatten_it_adjust.simps[code] + + +lemma flatten_it_adjust_rule: + " + flatten_it_adjust oit iit + \<^sub>t" +proof (induction ls2 arbitrary: ls1' ls1 ls2' lsim lsm1 lsm2 oit iit) + case Nil + then show ?case + apply(subst flatten_it_adjust.simps) + apply (sep_auto eintros del: exI heap add: inner_list.it_has_next_rule) + apply(inst_existentials "(ls1 @ lsim # [])" ls2' ls1' ls1 "[]::'l list" lsim lsm2 "lsm1@lsm2") + subgoal by auto + subgoal by (sep_auto) + apply (vcg (ss)) + apply (vcg (ss)) + apply (vcg (ss)) + apply (vcg (ss)) + apply (vcg (ss)) + apply (vcg (ss)) + apply (vcg (ss)) + subgoal + apply (vcg (ss)) + apply (sep_auto eintros del: exI) + apply(inst_existentials "(ls1 @ [lsim])" "ls1'@[lsm1]") + subgoal + apply(auto simp add: list_assn_app_one) + using inner_list.quit_iteration + by (smt (z3) assn_aci(9) assn_times_comm ent_true_drop(1) fr_refl) + done + done +next + case (Cons a ls2) + show ?case + apply(subst flatten_it_adjust.simps) + apply (sep_auto eintros del: exI heap add: inner_list.it_has_next_rule) + apply(inst_existentials "(ls1 @ lsim # a # ls2)" ls2' ls1' ls1 "a #ls2" lsim lsm2 "lsm1@lsm2") + subgoal by auto + subgoal by (sep_auto) + apply (vcg (ss)) + apply (vcg (ss)) + apply (vcg (ss)) + apply (vcg (ss)) + apply (vcg (ss)) + apply (vcg (ss)) + apply (vcg (ss)) + subgoal by simp + apply (vcg (ss)) + apply (vcg (ss)) + apply (vcg (ss)) + apply (vcg (ss)) + apply (vcg (ss)) + apply (vcg (ss)) + apply (vcg (ss)) + apply (vcg (ss)) + apply (case_tac ls2') + apply simp_all + apply (sep_auto eintros del: exI heap add: inner_list.it_init_rule) + subgoal for x oit aa list xa + supply R = "Cons.IH"[of "ls1'@[lsm1]" "ls1@[lsim]" list a oit "[]::'a list" aa xa, simplified] + thm R + find_theorems "_ \\<^sub>A _" "<_>_<_>" + supply Q = Hoare_Triple.cons_pre_rule[of +"inner_is_it aa a aa xa * outer_is_it (ls1 @ lsim # a # ls2) lsi ls2 oit * + inner_is_it lsm1 lsim [] iit * + list_assn is_inner_list ls1' ls1 * + list_assn is_inner_list list ls2 * + true" +"list_assn is_inner_list ls1' ls1 * is_inner_list lsm1 lsim * list_assn is_inner_list list ls2 * + outer_is_it (ls1 @ lsim # a # ls2) lsi ls2 oit * + inner_is_it aa a aa + xa * true" +] + thm Q + apply(rule Q) + prefer 2 + subgoal by (sep_auto heap add: R intro: inner_list.quit_iteration) + subgoal using inner_list.quit_iteration + by (smt (z3) assn_aci(10) assn_times_comm ent_refl_true ent_star_mono_true) + done + done +qed + +definition flatten_it_init :: "'m \ _ Heap" + where "flatten_it_init l = do { + oit \ outer_it_init l; + ohasnext \ outer_it_has_next oit; + if ohasnext then do { + (next, oit) \ outer_it_next oit; + nextit \ inner_it_init next; + flatten_it_adjust oit nextit + } else return (oit, None) +}" + +lemma flatten_it_init_rule[sep_heap_rules]: + " flatten_it_init p \<^sub>t" + unfolding flatten_it_init_def + apply simp + apply(rule norm_pre_ex_rule)+ + apply (vcg (ss)) + apply (vcg (ss)) + apply (vcg (ss)) + apply (vcg (ss)) + apply (vcg (ss)) + apply (vcg (ss)) + apply (vcg (ss)) + apply (vcg (ss)) + apply (vcg (ss)) + apply (vcg (ss)) + apply (vcg (ss)) + subgoal for ls' x xa + apply (vcg (ss)) + apply (vcg (ss)) + apply (vcg (ss)) + apply (vcg (ss)) + apply (vcg (ss)) + apply (vcg (ss)) + apply (vcg (ss)) + apply(case_tac ls'; case_tac l') + apply simp+ + apply(rule impI) + thm inner_list.it_init_rule + apply (vcg heap add: inner_list.it_init_rule) + subgoal for _ nxt oit a list aa lista xaa + supply R = flatten_it_adjust_rule[of "[]" "[]" lista list a p oit "[]" aa xaa, simplified] + thm R + apply (sep_auto heap add: R) + done + done + apply (sep_auto) + done + +definition flatten_it_next where + "flatten_it_next \ \(oit,iit). do { + (x, iit) \ inner_it_next (the iit); + (oit, iit) \ flatten_it_adjust oit iit; + return (x, (oit,iit)) + }" + +lemma flatten_it_next_rule: + " l' \ [] \ + + flatten_it_next it + <\(a,it'). is_flatten_it lsi'' l p (tl l') it' * \(a=hd l')>\<^sub>t" + apply(subst flatten_it_next_def) + thm inner_list.it_next_rule + apply (vcg (ss)) + apply (vcg (ss)) + apply(case_tac iit; case_tac l') + apply simp_all + apply(rule norm_pre_ex_rule)+ + subgoal for oit iit a aa list lsi' ls2' ls1' lsi1 lsi2 lsim ls2m lsm ls1m + apply(vcg (ss)) + apply(vcg (ss)) + apply(vcg (ss)) + apply(vcg (ss)) + apply(vcg (ss)) + apply(vcg (ss)) + apply(vcg (ss)) + apply(vcg (ss)) + apply(vcg (ss)) + apply(case_tac ls2m) + apply simp_all + subgoal for _ _ iita lista + supply R = flatten_it_adjust_rule[of ls1' lsi1 ls2' lsi2 lsim p oit "ls1m@[aa]" "lista" iita, simplified] + thm R + apply (sep_auto heap add: R) + done + done + done + +definition flatten_it_has_next where + "flatten_it_has_next \ \(oit, iit). do { + return (iit \ None) +}" + +lemma flatten_it_has_next_rule[sep_heap_rules]: + " + flatten_it_has_next it + <\r. is_flatten_it lsi'' l p l' it * \(r\l'\[])>\<^sub>t" + apply(subst flatten_it_has_next_def) + apply(sep_auto) + apply(case_tac iit, case_tac l') + apply simp_all + apply sep_auto + done + +declare mult.left_assoc[simp add] +lemma flatten_quit_iteration: + "is_flatten_it lsi'' l p l' it \\<^sub>A is_flatten_list lsi'' l p * true" + apply(cases it) + subgoal for oit iit + apply(cases iit; cases l') + proof (goal_cases) + case 1 + then show ?case + apply (sep_auto eintros del: exI) + subgoal for lsi' + apply(inst_existentials lsi') + subgoal by (metis (no_types, lifting) assn_aci(10) assn_times_comm fr_refl outer_list.quit_iteration) + done + done + next + case (2 lsim ll') + then show ?case + by (sep_auto eintros del: exI) + next + case (3 iit) + then show ?case + by (sep_auto eintros del: exI) + next + case (4 iit lsim ll') + then show ?case + apply (sep_auto eintros del: exI) + subgoal for ls2' ls1' lsi1 lsi2 lsima ls2m ls1m + apply(inst_existentials "(lsi1 @ lsima # lsi2)") + apply(rule entails_preI) + apply(sep_auto dest!: mod_starD list_assn_len) + subgoal + apply(simp add: + mult.commute[where ?b="outer_is_it (lsi1 @ lsima # lsi2) p lsi2 oit"] + mult.commute[where ?b="is_outer_list (lsi1 @ lsima # lsi2) p"] + mult.left_assoc )? + apply(rule rem_true) + supply R = ent_star_mono_true[of + "outer_is_it (lsi1 @ lsima # lsi2) p lsi2 oit" + "is_outer_list (lsi1 @ lsima # lsi2) p" + "list_assn is_inner_list ls1' lsi1 * + list_assn is_inner_list ls2' lsi2 * + inner_is_it (ls1m @ ls2m) lsima ls2m iit" + " list_assn is_inner_list ls1' lsi1 * + is_inner_list (ls1m @ ls2m) lsima * + list_assn is_inner_list ls2' lsi2" + ,simplified] + thm R + apply(rule R) + subgoal by (rule outer_list.quit_iteration) + apply(simp add: + mult.commute[where ?b="inner_is_it (ls1m @ ls2m) lsima ls2m iit"] + mult.commute[where ?b="is_inner_list (ls1m @ ls2m) lsima"] + mult.left_assoc) + apply(rule rem_true) + supply R = ent_star_mono_true[of + "inner_is_it (ls1m @ ls2m) lsima ls2m iit" + "is_inner_list (ls1m @ ls2m) lsima" + "list_assn is_inner_list ls1' lsi1 * + list_assn is_inner_list ls2' lsi2" + " list_assn is_inner_list ls1' lsi1 * + list_assn is_inner_list ls2' lsi2" + ,simplified] + thm R + apply(rule R) + subgoal by (rule inner_list.quit_iteration) + subgoal by sep_auto + done + done + done + qed + done +declare mult.left_assoc[simp del] + +interpretation flatten_it: imp_list_iterate "is_flatten_list lsi''" "is_flatten_it lsi''" flatten_it_init flatten_it_has_next flatten_it_next + apply(unfold_locales) + subgoal + by (rule flatten_prec) + subgoal for l p + by (rule flatten_it_init_rule[of lsi'' l p]) + subgoal for l' l p it + by (rule flatten_it_next_rule[of l' lsi'' l p it]) simp + subgoal for l p l' it + by (rule flatten_it_has_next_rule[of lsi'' l p l' it]) + subgoal for l p l' it + by (rule flatten_quit_iteration[of lsi'' l p l' it]) + done +end + +end \ No newline at end of file diff --git a/thys/BTree/Imp_List_Sum.thy b/thys/BTree/Imp_List_Sum.thy new file mode 100644 --- /dev/null +++ b/thys/BTree/Imp_List_Sum.thy @@ -0,0 +1,52 @@ +theory Imp_List_Sum +imports "Separation_Logic_Imperative_HOL.Imp_List_Spec" +begin + +text "A general sum operation can be defined for list iterators +over elements of a monoid" + +locale imp_list_iterate_sum = imp_list_iterate is_list is_it + for is_list :: "('a ::{monoid_add}) list \ 'b \ assn" + and is_it :: "'a list \ 'b \ 'a list \ 'it \ assn" +begin +subsubsection \List-Sum\ + +partial_function (heap) it_sum' :: "'it \ 'a \ 'a Heap" + where [code]: + "it_sum' it s = do { + b \ it_has_next it; + if b then do { + (x,it') \ it_next it; + it_sum' it' (s+x) + } else return s + }" + +lemma it_sum'_rule[sep_heap_rules]: + " + it_sum' it s + <\r. is_list l p * \(r = s + sum_list l')>\<^sub>t" +proof (induct l' arbitrary: it s) + case Nil thus ?case + apply (subst it_sum'.simps) + apply (sep_auto intro: quit_iteration ent_true_drop(1)) + done +next + case (Cons x l') + show ?case + apply (subst it_sum'.simps) + apply (sep_auto heap: Cons.hyps simp add: add.assoc) + done +qed + +definition "it_sum p \ do { + it \ it_init p; + it_sum' it 0}" + +lemma it_sum_rule[sep_heap_rules]: + " it_sum p <\r. is_list l p * \(r=sum_list l)>\<^sub>t" + unfolding it_sum_def + by sep_auto + +end + +end \ No newline at end of file diff --git a/thys/BTree/Imperative_Loops.thy b/thys/BTree/Imperative_Loops.thy --- a/thys/BTree/Imperative_Loops.thy +++ b/thys/BTree/Imperative_Loops.thy @@ -1,129 +1,129 @@ theory Imperative_Loops - imports + imports "Refine_Imperative_HOL.Sepref_HOL_Bindings" "Refine_Imperative_HOL.Pf_Mono_Prover" "Refine_Imperative_HOL.Pf_Add" begin section \Imperative Loops\ text "An auxiliary while rule provided by Peter Lammich." lemma heap_WHILET_rule: assumes "wf R" "P \\<^sub>A I s" "\s. bi s <\r. I s * \(r \ b s)>\<^sub>t" "\s. b s \ f s <\s'. I s' * \((s', s) \ R)>\<^sub>t" "\s. \ b s \ I s \\<^sub>A Q s" shows "

heap_WHILET bi f s \<^sub>t" proof - have " heap_WHILET bi f s <\s'. I s' * \(\ b s')>\<^sub>t" using assms(1) proof (induction arbitrary:) case (less s) show ?case proof (cases "b s") case True then show ?thesis by (subst heap_WHILET_unfold) (sep_auto heap: assms(3,4) less) next case False then show ?thesis by (subst heap_WHILET_unfold) (sep_auto heap: assms(3)) qed qed then show ?thesis apply (rule cons_rule[rotated 2]) apply (intro ent_star_mono assms(2) ent_refl) apply clarsimp apply (intro ent_star_mono assms(5) ent_refl) . qed lemma heap_WHILET_rule': assumes "wf R" "P \\<^sub>A I s si * F" "\si s. bi si <\r. I s si * F * \(r \ b s)>\<^sub>t" "\si s. b s \ f si <\si'. \\<^sub>As'. I s' si' * F * \((s', s) \ R)>\<^sub>t" "\si s. \ b s \ I s si * F \\<^sub>A Q s si" shows "

heap_WHILET bi f si <\si. \\<^sub>As. Q s si>\<^sub>t" proof - have " heap_WHILET bi f si <\si'. \\<^sub>As'. I s' si' * F * \(\ b s')>\<^sub>t" using assms(1) proof (induction arbitrary: si) case (less s) show ?case proof (cases "b s") case True then show ?thesis apply (subst heap_WHILET_unfold) apply (sep_auto heap: assms(3,4) less) done next case False then show ?thesis by (subst heap_WHILET_unfold) (sep_auto heap: assms(3)) qed qed then show ?thesis apply (rule cons_rule[rotated 2]) apply (intro ent_star_mono assms(2) ent_refl) apply clarsimp apply (sep_auto ) apply (erule ent_frame_fwd[OF assms(5)]) apply frame_inference by sep_auto qed (* Added by NM, just a technicality since this rule fits our use case better *) text "I derived my own version, simply because it was a better fit to my use case." corollary heap_WHILET_rule'': assumes "wf R" "P \\<^sub>A I s" "\s. bi s <\r. I s * \(r \ b s)>\<^sub>t" "\s. b s \ f s <\s'. I s' * \((s', s) \ R)>\<^sub>t" "\s. \ b s \ I s \\<^sub>A Q s" shows "

heap_WHILET bi f s \<^sub>t" supply R = heap_WHILET_rule'[of R P "\s si. \(s = si) * I s" s _ true bi b f "\s si.\(s = si) * Q s * true"] thm R using assms ent_true_drop apply(sep_auto heap: R assms) done (* explicit proof: proof - have " heap_WHILET bi f s <\s'. I s' * \(\ b s')>\<^sub>t" using assms(1) proof (induction arbitrary:) case (less s) show ?case proof (cases "b s") case True then show ?thesis by (subst heap_WHILET_unfold) (sep_auto heap: assms(3,4) less) next case False then show ?thesis by (subst heap_WHILET_unfold) (sep_auto heap: assms(3)) qed qed then show ?thesis apply (rule cons_rule[rotated 2]) apply (intro ent_true_drop assms(2) ent_refl) apply clarsimp apply(intro ent_star_mono assms(5) ent_refl) . qed *) end diff --git a/thys/BTree/Inst_Ex_Assn.thy b/thys/BTree/Inst_Ex_Assn.thy new file mode 100644 --- /dev/null +++ b/thys/BTree/Inst_Ex_Assn.thy @@ -0,0 +1,25 @@ +section \Tactic for instantiating existentials\ +theory Inst_Ex_Assn + imports Separation_Logic_Imperative_HOL.Assertions +begin + +thm ent_ex_postI + +text \ + Coinduction proofs in Isabelle often lead to proof obligations with nested conjunctions and + existential quantifiers, e.g. \<^prop>\\x y. P x y \ (\z. Q x y z)\ . + + The following tactic allows instantiating these existentials with a given list of witnesses. + + This tactic was adjusted to work with the assertion specific prop\\\<^sub>A\ +\ + +ML_file \inst_ex_assn.ML\ + +method_setup inst_ex_assn = \ + Scan.lift (Scan.repeat Parse.term) >> + (fn ts => fn ctxt => SIMPLE_METHOD' (Inst_Ex_Assn.tac ctxt + (map (Syntax.read_term ctxt) ts))) +\ + +end \ No newline at end of file diff --git a/thys/BTree/LICENSE b/thys/BTree/LICENSE new file mode 100644 --- /dev/null +++ b/thys/BTree/LICENSE @@ -0,0 +1,9 @@ +Copyright 2021 Niels Mündler + +Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: + +1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. + +2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/thys/BTree/Partially_Filled_Array.thy b/thys/BTree/Partially_Filled_Array.thy --- a/thys/BTree/Partially_Filled_Array.thy +++ b/thys/BTree/Partially_Filled_Array.thy @@ -1,427 +1,443 @@ theory Partially_Filled_Array imports "Refine_Imperative_HOL.IICF_Array_List" Array_SBlit begin section "Partially Filled Arrays" text \An array that is only partially filled. The number of actual elements contained is kept in a second element. This represents a weakened version of the array\_list from IICF.\ type_synonym 'a pfarray = "'a array_list" subsection "Operations on Partly Filled Arrays" definition is_pfa where "is_pfa c l \ \(a,n). \\<^sub>A l'. a \\<^sub>a l' * \(c = length l' \ n \ c \ l = (take n l'))" +abbreviation "len :: 'a pfarray \ nat \ snd" +abbreviation "arr :: 'a pfarray \ 'a array \ fst" lemma is_pfa_prec[safe_constraint_rules]: "precise (is_pfa c)" unfolding is_pfa_def[abs_def] apply(rule preciseI) - apply(simp split: prod.splits) + apply(simp split: prod.splits) using preciseD snga_prec by fastforce definition pfa_init where "pfa_init cap v n \ do { a \ Array.new cap v; return (a,n) }" lemma pfa_init_rule[sep_heap_rules]: "n \ N \ < emp > pfa_init N x n " by (sep_auto simp: pfa_init_def is_pfa_def) definition pfa_empty where "pfa_empty cap \ pfa_init cap default 0" lemma pfa_empty_rule[sep_heap_rules]: "< emp > pfa_empty N " by (sep_auto simp: pfa_empty_def is_pfa_def) definition "pfa_length \ arl_length" lemma pfa_length_rule[sep_heap_rules]: " - + pfa_length a <\r. is_pfa c l a * \(r=length l)>" by (sep_auto simp: pfa_length_def arl_length_def is_pfa_def) definition "pfa_capacity \ \(a,n). Array.len a " lemma pfa_capacity_rule[sep_heap_rules]: " - + pfa_capacity a <\r. is_pfa c l a * \(c=r)>" by (sep_auto simp: pfa_capacity_def arl_length_def is_pfa_def) definition "pfa_is_empty \ arl_is_empty" lemma pfa_is_empty_rule[sep_heap_rules]: " - + pfa_is_empty a <\r. is_pfa c l a * \(r\(l=[]))>" by (sep_auto simp: pfa_is_empty_def arl_is_empty_def is_pfa_def) definition "pfa_append \ \(a,n) x. do { Array.upd n x a; return (a,n+1) }" -lemma pfa_append_rule[sep_heap_rules]: " - n < c \ - < is_pfa c l (a,n) > - pfa_append (a,n) x - <\(a',n'). is_pfa c (l@[x]) (a',n') * \(a' = a \ n' = n+1) >" + +lemma pfa_append_rule[sep_heap_rules]: + "len a < c \ + + pfa_append a x + <\(a',n'). is_pfa c (l@[x]) (a',n') * \(a' = arr a \ n' = (len a)+1) >" by (sep_auto simp: pfa_append_def arl_append_def is_pfa_def take_update_last neq_Nil_conv split: prod.splits nat.split) definition "pfa_last \ arl_last" lemma pfa_last_rule[sep_heap_rules]: " l\[] \ - + pfa_last a <\r. is_pfa c l a * \(r=last l)>" by (sep_auto simp: pfa_last_def arl_last_def is_pfa_def last_take_nth_conv) definition pfa_butlast :: "'a::heap pfarray \ 'a pfarray Heap" where "pfa_butlast \ \(a,n). return (a,n-1) " lemma pfa_butlast_rule[sep_heap_rules]: " - - pfa_butlast (a,n) - <\(a',n'). is_pfa c (butlast l) (a',n') * \(a' = a)>" - by (sep_auto + + pfa_butlast a + <\(a',n'). is_pfa c (butlast l) (a',n') * \(a' = arr a)>" + by (sep_auto split: prod.splits - simp: pfa_butlast_def is_pfa_def butlast_take) + simp: pfa_butlast_def is_pfa_def butlast_take) definition "pfa_get \ arl_get" lemma pfa_get_rule[sep_heap_rules]: " i < length l \ - < is_pfa c l a> + < is_pfa c l a> pfa_get a i <\r. is_pfa c l a * \((l!i) = r)>" by (sep_auto simp: is_pfa_def pfa_get_def arl_get_def split: prod.split) definition "pfa_set \ arl_set" lemma pfa_set_rule[sep_heap_rules]: " i - + pfa_set a i x <\a'. is_pfa c (l[i:=x]) a' * \(a' = a)>" by (sep_auto simp: pfa_set_def arl_set_def is_pfa_def split: prod.split) definition pfa_shrink :: "nat \ 'a::heap pfarray \ 'a pfarray Heap" where "pfa_shrink k \ \(a,n). return (a,k) " lemma pfa_shrink_rule[sep_heap_rules]: " k \ length xs \ - < is_pfa c xs (a,n) > - pfa_shrink k (a,n) - <\(a',n'). is_pfa c (take k xs) (a',n') * \(n' = k \ a'=a) >" - by (sep_auto + < is_pfa c xs a > + pfa_shrink k a + <\(a',n'). is_pfa c (take k xs) (a',n') * \(n' = k \ a'=arr a) >" + by (sep_auto simp: pfa_shrink_def is_pfa_def min.absorb1 split: prod.splits nat.split) definition pfa_shrink_cap :: "nat \ 'a::heap pfarray \ 'a pfarray Heap" where "pfa_shrink_cap k \ \(a,n). do { a' \ array_shrink a k; return (a',min k n) } " lemma pfa_shrink_cap_rule_preserve[sep_heap_rules]: " - \n \ k; k \ c\ \ - < is_pfa c l (a,n) > - pfa_shrink_cap k (a,n) + \len a \ k; k \ c\ \ + < is_pfa c l a > + pfa_shrink_cap k a <\a'. is_pfa k l a' >\<^sub>t" - by (sep_auto + by (sep_auto simp: pfa_shrink_cap_def is_pfa_def min.absorb1 min.absorb2 split: prod.splits nat.split) lemma pfa_shrink_cap_rule: " \k \ c\ \ - < is_pfa c l a > + < is_pfa c l a > pfa_shrink_cap k a - <\a'. is_pfa k (take k l) a' >\<^sub>t" - by (sep_auto + <\a'. is_pfa k (take k l) a' >\<^sub>t" + by (sep_auto simp: pfa_shrink_cap_def is_pfa_def min.absorb1 min.absorb2 split: prod.splits nat.split dest: mod_starD) definition "array_ensure a s x \ do { l\Array.len a; - if l\s then + if l\s then return a else do { a'\Array.new s x; blit a 0 a' 0 l; return a' } }" lemma array_ensure_rule[sep_heap_rules]: shows " - < a\\<^sub>ala > - array_ensure a s x + < a\\<^sub>ala > + array_ensure a s x <\a'. a'\\<^sub>a (la @ replicate (s-length la) x)>\<^sub>t" unfolding array_ensure_def by sep_auto (* Ensure a certain capacity *) definition pfa_ensure :: "'a::{heap,default} pfarray \ nat \ 'a pfarray Heap" where "pfa_ensure \ \(a,n) k. do { a' \ array_ensure a k default; return (a',n) } " lemma pfa_ensure_rule[sep_heap_rules]: " - < is_pfa c l (a,n) > - pfa_ensure (a,n) k - <\(a',n'). is_pfa (max c k) l (a',n') * \(n' = n \ c \ n)>\<^sub>t" - by (sep_auto - simp: pfa_ensure_def is_pfa_def) + < is_pfa c l a > + pfa_ensure a k + <\(a',n'). is_pfa (max c k) l (a',n') * \(n' = len a \ c \ len a)>\<^sub>t" + by (sep_auto + simp: pfa_ensure_def is_pfa_def split!: prod.splits) definition "pfa_copy \ arl_copy" lemma pfa_copy_rule[sep_heap_rules]: "< is_pfa c l a > pfa_copy a - <\r. is_pfa c l a * is_pfa c l r>\<^sub>t" + <\r. is_pfa c l a * is_pfa c l r>\<^sub>t" by (sep_auto simp: pfa_copy_def arl_copy_def is_pfa_def) definition pfa_blit :: "'a::heap pfarray \ nat \ 'a::heap pfarray \ nat \ nat \ unit Heap" where "pfa_blit \ \(src,sn) si (dst,dn) di l. blit src si dst di l" lemma min_nat: "min a (a+b) = (a::nat)" by auto lemma pfa_blit_rule[sep_heap_rules]: - assumes LEN: "si+len \ sn" "di \ dn" "di+len \ dc" + assumes LEN: "si+l \ sn" "di \ dn" "di+l \ dc" shows "< is_pfa sc src (srci,sn) * is_pfa dc dst (dsti,dn) > - pfa_blit (srci,sn) si (dsti,dn) di len + pfa_blit (srci,sn) si (dsti,dn) di l <\_. is_pfa sc src (srci,sn) - * is_pfa dc (take di dst @ take len (drop si src) @ drop (di+len) dst) (dsti,max (di+len) dn) + * is_pfa dc (take di dst @ take l (drop si src) @ drop (di+l) dst) (dsti,max (di+l) dn) >" using LEN apply(sep_auto simp add: min_nat is_pfa_def pfa_blit_def min.commute min.absorb1 heap: blit_rule) apply (simp add: min.absorb1 take_drop) apply (simp add: drop_take max_def) done definition pfa_drop :: "('a::heap) pfarray \ nat \ 'a pfarray \ 'a pfarray Heap" where "pfa_drop \ \(src,sn) si (dst,dn). do { blit src si dst 0 (sn-si); return (dst,(sn-si)) } " -lemma pfa_drop_rule[sep_heap_rules]: +lemma pfa_drop_rule_pair[sep_heap_rules]: assumes LEN: "k \ sn" "(sn-k) \ dc" shows "< is_pfa sc src (srci,sn) * is_pfa dc dst (dsti,dn) > pfa_drop (srci,sn) k (dsti,dn) <\(dsti',dn'). is_pfa sc src (srci,sn) * is_pfa dc (drop k src) (dsti',dn') * \(dsti' = dsti) >" using LEN apply (sep_auto simp add: drop_take is_pfa_def pfa_drop_def dest!: mod_starD heap: pfa_blit_rule) done +lemma pfa_drop_rule[sep_heap_rules]: + assumes LEN: "k \ len srci" "(len srci-k) \ dc" + shows + "< is_pfa sc src srci + * is_pfa dc dst dsti > + pfa_drop srci k dsti + <\(dsti',dn'). is_pfa sc src srci + * is_pfa dc (drop k src) (dsti',dn') + * \(dsti' = arr dsti) + >" + using LEN apply (sep_auto simp add: drop_take is_pfa_def pfa_drop_def dest!: mod_starD heap: pfa_blit_rule split!: prod.splits) + done + definition "pfa_append_grow \ \(a,n) x. do { l \ pfa_capacity (a,n); - a' \ if l = n + a' \ if l = n then array_grow a (l+1) x else Array.upd n x a; return (a',n+1) }" lemma pfa_append_grow_full_rule[sep_heap_rules]: "n = c \ array_grow a (c+1) x <\a'. is_pfa (c+1) (l@[x]) (a',n+1)>\<^sub>t" - apply(sep_auto simp add: is_pfa_def + apply(sep_auto simp add: is_pfa_def heap del: array_grow_rule) apply(vcg heap del: array_grow_rule heap add: array_grow_rule[of l "(Suc (length l))" a x]) apply simp apply(rule ent_ex_postI[where ?x="l@[x]"]) apply sep_auto done lemma pfa_append_grow_less_rule: "n < c \ Array.upd n x a <\a'. is_pfa c (l@[x]) (a',n+1)>\<^sub>t" apply(sep_auto simp add: is_pfa_def take_update_last) done lemma pfa_append_grow_rule[sep_heap_rules]: " - pfa_append_grow (a,n) x + pfa_append_grow (a,n) x <\(a',n'). is_pfa (if c = n then c+1 else c) (l@[x]) (a',n') * \(n'=n+1 \ c \ n)>\<^sub>t" apply(subst pfa_append_grow_def) apply(rule hoare_triple_preI) apply (sep_auto heap add: pfa_append_grow_full_rule pfa_append_grow_less_rule) apply(sep_auto simp add: is_pfa_def) apply(sep_auto simp add: is_pfa_def) done (* This definition has only one access to the array length *) definition "pfa_append_grow' \ \(a,n) x. do { a' \ pfa_ensure (a,n) (n+1); a'' \ pfa_append a' x; return a'' }" lemma pfa_append_grow'_rule[sep_heap_rules]: " - pfa_append_grow' (a,n) x + pfa_append_grow' (a,n) x <\(a',n'). is_pfa (max (n+1) c) (l@[x]) (a',n') * \(n'=n+1 \ c \ n)>\<^sub>t" unfolding pfa_append_grow'_def by (sep_auto simp add: max_def) definition "pfa_insert \ \(a,n) i x. do { a' \ array_shr a i 1; a'' \ Array.upd i x a; return (a'',n+1) }" lemma list_update_last: "length ls = Suc i \ ls[i:=x] = (take i ls)@[x]" by (metis append_eq_conv_conj length_Suc_rev_conv list_update_length) lemma pfa_insert_rule[sep_heap_rules]: "\i \ n; n < c\ \ - pfa_insert (a,n) i x + pfa_insert (a,n) i x <\(a',n'). is_pfa c (take i l@x#drop i l) (a',n') * \(n' = n+1 \ a=a')>" - unfolding pfa_insert_def is_pfa_def + unfolding pfa_insert_def is_pfa_def by (sep_auto simp add: list_update_append1 list_update_last Suc_diff_le drop_take min_def) -definition pfa_insert_grow :: "'a::{heap,default} pfarray \ nat \ 'a \ 'a pfarray Heap" +definition pfa_insert_grow :: "'a::{heap,default} pfarray \ nat \ 'a \ 'a pfarray Heap" where "pfa_insert_grow \ \(a,n) i x. do { a' \ pfa_ensure (a,n) (n+1); a'' \ pfa_insert a' i x; return a'' }" -lemma pfa_insert_grow_rule[sep_heap_rules]: +lemma pfa_insert_grow_rule[sep_heap_rules]: "i \ n \ - pfa_insert_grow (a,n) i x + pfa_insert_grow (a,n) i x <\(a',n'). is_pfa (max c (n+1)) (take i l@x#drop i l) (a',n') * \(n'=n+1 \ c \ n)>\<^sub>t" - unfolding pfa_insert_grow_def + unfolding pfa_insert_grow_def by (sep_auto heap add: pfa_insert_rule[of i n "max c (Suc n)"]) definition pfa_extend where "pfa_extend \ \ (a,n) (b,m). do{ blit b 0 a n m; return (a,n+m) }" -lemma pfa_extend_rule[sep_heap_rules]: +lemma pfa_extend_rule[sep_heap_rules]: "n+m \ c \ - pfa_extend (a,n) (b,m) + pfa_extend (a,n) (b,m) <\(a',n'). is_pfa c (l1@l2) (a',n') * \(a' = a \ n'=n+m) * is_pfa d l2 (b,m)>\<^sub>t" - unfolding pfa_extend_def + unfolding pfa_extend_def by (sep_auto simp add: is_pfa_def min.absorb1 min.absorb2 heap add: blit_rule) definition pfa_extend_grow where "pfa_extend_grow \ \ (a,n) (b,m). do{ a' \ array_ensure a (n+m) default; blit b 0 a' n m; return (a',n+m) }" -lemma pfa_extend_grow_rule[sep_heap_rules]: +lemma pfa_extend_grow_rule[sep_heap_rules]: " - pfa_extend_grow (a,n) (b,m) + pfa_extend_grow (a,n) (b,m) <\(a',n'). is_pfa (max c (n+m)) (l1@l2) (a',n') * \(n'=n+m \ c \ n) * is_pfa d l2 (b,m)>\<^sub>t" - unfolding pfa_extend_grow_def + unfolding pfa_extend_grow_def by (sep_auto simp add: is_pfa_def min.absorb1 min.absorb2 heap add: blit_rule) definition pfa_append_extend_grow where "pfa_append_extend_grow \ \ (a,n) x (b,m). do{ a' \ array_ensure a (n+m+1) default; a'' \ Array.upd n x a'; blit b 0 a'' (n+1) m; return (a'',n+m+1) }" -lemma pfa_append_extend_grow_rule[sep_heap_rules]: +lemma pfa_append_extend_grow_rule[sep_heap_rules]: " - pfa_append_extend_grow (a,n) x (b,m) + pfa_append_extend_grow (a,n) x (b,m) <\(a',n'). is_pfa (max c (n+m+1)) (l1@x#l2) (a',n') * \(n'=n+m+1 \ c \ n) * is_pfa d l2 (b,m)>\<^sub>t" - unfolding pfa_append_extend_grow_def + unfolding pfa_append_extend_grow_def by (sep_auto simp add: list_update_last is_pfa_def min.absorb1 min.absorb2 heap add: blit_rule) definition "pfa_delete \ \(a,n) i. do { array_shl a (i+1) 1; return (a,n-1) }" lemma pfa_delete_rule[sep_heap_rules]: "i < n \ pfa_delete (a,n) i <\(a',n'). is_pfa c (take i l@drop (i+1) l) (a',n') * \(n' = n-1 \ a=a')>" - unfolding pfa_delete_def is_pfa_def + unfolding pfa_delete_def is_pfa_def apply (sep_auto simp add: drop_take min_def) by (metis Suc_diff_Suc diff_zero dual_order.strict_trans2 le_less_Suc_eq zero_le) end \ No newline at end of file diff --git a/thys/BTree/Partially_Filled_Array_Iter.thy b/thys/BTree/Partially_Filled_Array_Iter.thy new file mode 100644 --- /dev/null +++ b/thys/BTree/Partially_Filled_Array_Iter.thy @@ -0,0 +1,72 @@ +theory Partially_Filled_Array_Iter +imports + Partially_Filled_Array + "Separation_Logic_Imperative_HOL.Imp_List_Spec" +begin + + +subsubsection \Iterator\ + +type_synonym 'a pfa_it = "'a pfarray \ nat" +definition "pfa_is_it c ls lsi ls2 + \ (\(lsi',i). is_pfa c ls lsi * \(ls2 = drop i ls \ i \ length ls \ lsi' = lsi))" + +definition pfa_it_init :: "'a pfarray \ ('a pfa_it) Heap" + where "pfa_it_init l = return (l,0)" + +fun pfa_it_next where + "pfa_it_next (p,i) = do { + x \ pfa_get p i; + return (x, (p,Suc i)) + }" + +definition pfa_it_has_next :: "('a::heap) pfa_it \ bool Heap" where + "pfa_it_has_next it \ do { + l \ pfa_length (fst it); + return (snd it \ l) +}" + +lemma pfa_iterate_impl: + "imp_list_iterate (is_pfa k) (pfa_is_it k) pfa_it_init pfa_it_has_next pfa_it_next" + apply unfold_locales + unfolding pfa_it_init_def pfa_is_it_def[abs_def] +proof(goal_cases) + case 1 + then show ?case + by (simp add: is_pfa_prec) +next + case (2 l p) + then show ?case + by sep_auto +next + case (3 l' l p it) + then show ?case + apply (case_tac it, simp) + apply (case_tac l', simp) + apply sep_auto + subgoal by (metis drop_all list.simps(3) not_le_imp_less) + apply (sep_auto) + apply (metis drop_eq_ConsD list.sel(3)) + subgoal by (meson Suc_leI \\list ba b aa a. \it = ((a, b), ba); l' = drop ba l; aa # list = drop ba l; ba \ length l; p = (a, b)\ \ ba < length l\) + subgoal by (metis list.sel(1) nth_via_drop) + subgoal using ent_refl_true by presburger + done +next + case (4 l p l' it) + then show ?case + unfolding pfa_it_has_next_def + apply (case_tac it, simp) + by (sep_auto) +next + case (5 l p l' it) + then show ?case + apply (case_tac it, simp) + by sep_auto +qed + +interpretation pfa_iter: + imp_list_iterate "is_pfa k" "pfa_is_it k" pfa_it_init pfa_it_has_next pfa_it_next + by (rule pfa_iterate_impl) + + +end \ No newline at end of file diff --git a/thys/BTree/README.md b/thys/BTree/README.md --- a/thys/BTree/README.md +++ b/thys/BTree/README.md @@ -1,37 +1,42 @@ # A Verified Imperative Implementation of B-Trees This repository contains all definitions, lemmas and proofs related to the Bachelors Thesis "A Verified Imperative Implementation of B-Trees" -by Niels Mündler. +by Niels Mündler and the paper "A Verified Implementation of B+-trees in Isabelle/HOL" by Niels Mündler and Tobias Nipkow. -For a detailed description of the project, [see the thesis](https://github.com/nielstron/btrees-thesis). +For a detailed description of the B-Tree implementation, [see the thesis](https://github.com/nielstron/btrees-thesis). +For a detailed description of the B+-Tree implementation, see the paper published in ICTAC 2022. ## Overview A functional specification of B-trees, B-tree operations and a height analysis may be found in the files `BTree*.thy` that do not contain `Imp`. An imperative specification of B-trees may be found in `BTree_Imp*.thy`. -This imperative specification makes use of the auxiliary definition + +The same structure applies for B+-trees and the prefix `BPlusTree*.thy`. + +The imperative specification make use of the auxiliary definition of "Partially Filled Arrays" as list refinements, which may be found in `Partially_Filled_Array.thy`. Further an extension of the standard array blit operation in Isabelle, such that it allows error-free array-internal copy operations, may be found in `Array_SBlit.thy`. +Moreover this repository introduces a general "Flattening Iterator", which flattens two iterators on distinct data structures. The remaining files contain auxiliary lemmas and definitions that are due to Dr. Peter Lammich or me. All above mentioned files contain definitions as well as proofs of functional correctness. ## Usage -These theories have been tested with [Isabelle2021](https://isabelle.in.tum.de/website-Isabelle2021/index.html). +These theories have been tested with [Isabelle2021-1](https://isabelle.in.tum.de/website-Isabelle2021/index.html). -The files `BTree*.thy` that do not contain `Imp` only need a regular Isabelle setup. +The files `BTree*.thy` and `BPlusTree*.thy` that do not contain `Imp` only need a regular Isabelle setup. The rest of the theories build upon [Refine_Imperative_HOL](https://www.isa-afp.org/entries/Refine_Imperative_HOL.html), you will need to succesfully set up that project first as described in the [Archive of Formal Proofs](https://www.isa-afp.org/using.html). The script `start_isabelle.sh` uses and if not available compiles a session containing the content of the Refinement Framework which significantly enhances working with the files provided in this project. diff --git a/thys/BTree/ROOT b/thys/BTree/ROOT --- a/thys/BTree/ROOT +++ b/thys/BTree/ROOT @@ -1,20 +1,35 @@ chapter AFP session "BTree" (AFP) = "Refine_Imperative_HOL" + options [timeout = 1200] sessions "HOL-Data_Structures" + "HOL-Real_Asymp" theories BTree BTree_Height BTree_Set BTree_Split + BPlusTree + BPlusTree_Split + BPlusTree_Set + BPlusTree_Range + BPlusTree_SplitCE theories [condition = ISABELLE_OCAMLFIND] Array_SBlit Partially_Filled_Array BTree_Imp BTree_ImpSet BTree_ImpSplit + Flatten_Iter_Spec + Flatten_Iter + BPlusTree_Imp + BPlusTree_ImpSplit + BPlusTree_ImpSet + BPlusTree_Iter_OneWay + BPlusTree_Iter + BPlusTree_ImpRange + BPlusTree_ImpSplitCE document_files "root.tex" "root.bib" diff --git a/thys/BTree/Subst_Mod_Mult_AC.thy b/thys/BTree/Subst_Mod_Mult_AC.thy new file mode 100644 --- /dev/null +++ b/thys/BTree/Subst_Mod_Mult_AC.thy @@ -0,0 +1,162 @@ +theory Subst_Mod_Mult_AC +imports Main +begin + +(* By Manuel Eberl *) + +ML \ + +signature SUBST_MOD_MULT_AC = sig + +val tac : Proof.context -> thm -> int -> tactic + +end + + +structure Subst_Mod_Mult_Ac : SUBST_MOD_MULT_AC = struct + +datatype factor_tree = Base of term | Mult of factor_tree * factor_tree +datatype delete_result = Empty | Deleted of factor_tree | Not_Present + +fun factor_tree (Const (\<^const_name>\Groups.times\, _) $ a $ b) = Mult (factor_tree a, factor_tree b) + | factor_tree t = Base t + +fun flatten_factor_tree (Base t) = [t] + | flatten_factor_tree (Mult (l, r)) = flatten_factor_tree l @ flatten_factor_tree r + + +fun mk_one T = Const (\<^const_name>\Groups.one\, T) +fun mk_mult_const T = Const (\<^const_name>\Groups.times\, T --> T --> T) +fun mk_mult t1 t2 = mk_mult_const (fastype_of t1) $ t1 $ t2 + +fun mk_mult' t1 NONE = t1 + | mk_mult' t1 (SOME t2) = mk_mult t1 t2 + +fun term_of_factor_tree (Base t) = t + | term_of_factor_tree (Mult (l, r)) = mk_mult (term_of_factor_tree l) (term_of_factor_tree r) + +fun delete_factor_tree t tr = + let + fun aux (Base t') = + if Envir.beta_eta_contract t aconv Envir.beta_eta_contract t' then Empty else Not_Present + | aux (Mult (l, r)) = + case aux l of + Empty => Deleted r + | Deleted l' => Deleted (Mult (l', r)) + | Not_Present => ( + case aux r of + Empty => Deleted l + | Deleted r' => Deleted (Mult (l, r')) + | Not_Present => Not_Present) + in + aux tr + end + +fun delete_all_factor_tree [] tr = Deleted tr + | delete_all_factor_tree (t :: ts) tr = + case delete_factor_tree t tr of + Empty => if null ts then Empty else Not_Present + | Not_Present => Not_Present + | Deleted tr' => delete_all_factor_tree ts tr' + +val trans_thm = @{lemma "lhs \ rhs \ a \ lhs \ a \ rhs" by simp} +val lift_thm = @{lemma "lhs \ rhs \ a \ lhs * x \ a \ rhs * x" by simp} + +fun subst_mod_mult_ac ctxt eq_thm ct = + let + val t = Thm.term_of ct + val T = fastype_of t + val (lhs, _) = Logic.dest_equals (Thm.concl_of eq_thm) + fun err () = raise CTERM ("subst_mod_mult_ac", [ct, Thm.dest_equals_lhs (Thm.cconcl_of eq_thm)]) + val _ = if fastype_of lhs <> T then err () else () + val factors_t = factor_tree t + val factors_lhs = factor_tree lhs + val factors_t' = + case delete_all_factor_tree (flatten_factor_tree factors_lhs) factors_t of + Empty => NONE + | Deleted tr => SOME tr + | Not_Present => err () + val is_empty = not (Option.isSome factors_t') + val t' = mk_mult' lhs (Option.map term_of_factor_tree factors_t') + fun tac {context: Proof.context, ...} = + HEADGOAL (Simplifier.simp_tac (put_simpset HOL_ss context addsimps @{thms "mult_ac"})) + val eq_thm1 = Goal.prove ctxt [] [] (Logic.mk_equals (t, t')) tac + val thm = if is_empty then trans_thm OF [eq_thm, eq_thm1] else lift_thm OF [eq_thm, eq_thm1] + in + thm + end + +fun subst_mod_mult_ac_tac_here ctxt eq_thm ct i = + EqSubst.eqsubst_tac ctxt [0] [subst_mod_mult_ac ctxt eq_thm ct] i + handle CTERM _ => no_tac + +fun subst_mod_mult_ac_tac ctxt eq_thm i = + let + val eq_thm = + case Thm.concl_of eq_thm of + Const (\<^const_name>\Pure.eq\, _) $ _ $ _ => eq_thm + | \<^const>\Trueprop\ $ (Const (\<^const_name>\HOL.eq\, _) $ _ $ _) => eq_thm RS @{thm eq_reflection} + | _ => raise THM ("subst_mod_mult_ac_tac", 1, [eq_thm]) + fun tac {context: Proof.context, concl: cterm, ...} = + let + fun tac' ct = + subst_mod_mult_ac_tac_here context eq_thm ct i + ORELSE + (case Thm.term_of ct of + _ $ _ => tac' (Thm.dest_fun ct) ORELSE tac' (Thm.dest_arg ct) + | _ => no_tac) + in + tac' concl + end + in + Subgoal.FOCUS_PARAMS tac ctxt i + end + +val tac = subst_mod_mult_ac_tac + +end + +\ + +method_setup subst_mod_mult_ac = + \Attrib.thm >> (fn eq_thm => fn ctxt => SIMPLE_METHOD' (Subst_Mod_Mult_Ac.tac ctxt eq_thm))\ + + + +(* now a demo *) +locale demo = + fixes a::"'a::{comm_monoid_mult}" + and b::"'a::{comm_monoid_mult}" + and c::"'a::{comm_monoid_mult}" + and d::"'a::{comm_monoid_mult}" + and e::"'a::{comm_monoid_mult}" + and gee + assumes foo: "a*b = c" + and geh: "gee a = true" + and bar: "gee a \ gee b \ a * b = c" +begin + + +(* our method in action *) +lemma "a * b = c" + "b * a = c" + "b * d * a = c * d" + "d * b * a = c * d" + by (subst_mod_mult_ac foo, rule refl)+ + +lemma "gee a \ a * b = c" + by (subst_mod_mult_ac foo, rule refl) + +(* handling of assumptions in the rewrite rule *) +lemma "d * b * a = c * d" + apply (subst_mod_mult_ac bar) + oops + +(* backtracking *) +lemma "f (a * b) (a * b) = rhs" + apply (subst_mod_mult_ac foo) + back + oops + +end +end \ No newline at end of file diff --git a/thys/BTree/document/root.tex b/thys/BTree/document/root.tex --- a/thys/BTree/document/root.tex +++ b/thys/BTree/document/root.tex @@ -1,64 +1,64 @@ \documentclass[11pt,a4paper]{article} \usepackage{isabelle,isabellesym} \usepackage[T1]{fontenc} \usepackage{mathtools} \usepackage{amssymb} \usepackage{stmaryrd} \usepackage[numbers]{natbib} % this should be the last package used \usepackage{pdfsetup} \usepackage{doi} % urls in roman style, theory text in math-similar italics \urlstyle{rm} \isabellestyle{it} \DeclarePairedDelimiter{\norm}{\lVert}{\rVert} \begin{document} \title{A Verified Imperative Implementation of B-Trees} \author{Niels Mündler} \date{} \maketitle \begin{abstract} In this work, we use the interactive theorem prover Isabelle/HOL to verify an imperative implementation of the classical B-tree data structure \cite{DBLP:journals/acta/BayerM72}. -The implementation supports set membership, insertion and deletion queries -with efficient binary search for intra-node navigation. +The implementation supports set membership, insertion, deletion, iteration and range queries with efficient binary search for intra-node navigation. This is accomplished by first specifying the structure abstractly in the functional modeling language HOL and proving functional correctness. Using manual refinement, we derive an imperative implementation in Imperative/HOL. We show the validity of this refinement using the separation logic utilities from the Isabelle Refinement Framework \cite{Refine_Imperative_HOL-AFP}. The code can be exported to the programming languages SML, Scala and OCaml. -We examine the runtime of all operations indirectly by reproducing results -of the logarithmic relationship between height and the number of nodes. -The results are discussed in greater detail in the related Bachelor's Thesis -\cite{BTNielsMuendler}. +This entry contains two developments: +\begin{itemize} + \item \emph{B-Trees} This formalisation is discussed in greater detail in the corresponding Bachelor's Thesis\cite{BTNielsMuendler}. + \item \emph{B$^+$-Trees} This formalisation also supports range queries and is discussed in a paper published at ICTAC 2022. +\end{itemize} \end{abstract} \tableofcontents % sane default for proof documents \parindent 0pt\parskip 0.5ex % generated text of all theories \input{session} % optional bibliography {\raggedright \bibliographystyle{plainnat} \bibliography{root} } \end{document} %%% Local Variables: %%% mode: latex %%% TeX-master: t %%% End: diff --git a/thys/BTree/inst_ex_assn.ML b/thys/BTree/inst_ex_assn.ML new file mode 100644 --- /dev/null +++ b/thys/BTree/inst_ex_assn.ML @@ -0,0 +1,18 @@ +signature INST_EX_ASSN = +sig + val tac : Proof.context -> term list -> int -> tactic +end + +structure Inst_Ex_Assn : INST_EX_ASSN = +struct + +fun tac ctxt [] = TRY o REPEAT_ALL_NEW (assume_tac ctxt) + | tac ctxt (t :: ts) = + (TRY o ( + let + val thm = Drule.infer_instantiate' ctxt [NONE, NONE, SOME (Thm.cterm_of ctxt t)] @{thm Assertions.ent_ex_postI} + in + resolve_tac ctxt [thm] THEN' tac ctxt ts + end)) + +end \ No newline at end of file