# HG changeset patch # User nipkow # Date 1657867564 -7200 # Node ID 33177228aa694934756669f348e9e1d8f9df4040 # Parent 714528f429228bf7fb55d80bbae3bec6b3892e86 tuned names diff -r 714528f42922 -r 33177228aa69 src/HOL/Data_Structures/Binomial_Heap.thy --- a/src/HOL/Data_Structures/Binomial_Heap.thy Tue Jul 12 10:38:13 2022 +0000 +++ b/src/HOL/Data_Structures/Binomial_Heap.thy Fri Jul 15 08:46:04 2022 +0200 @@ -23,61 +23,61 @@ datatype 'a tree = Node (rank: nat) (root: 'a) (children: "'a tree list") -type_synonym 'a heap = "'a tree list" +type_synonym 'a trees = "'a tree list" subsubsection \Multiset of elements\ fun mset_tree :: "'a::linorder tree \ 'a multiset" where "mset_tree (Node _ a ts) = {#a#} + (\t\#mset ts. mset_tree t)" -definition mset_heap :: "'a::linorder heap \ 'a multiset" where - "mset_heap ts = (\t\#mset ts. mset_tree t)" +definition mset_trees :: "'a::linorder trees \ 'a multiset" where + "mset_trees ts = (\t\#mset ts. mset_tree t)" lemma mset_tree_simp_alt[simp]: - "mset_tree (Node r a ts) = {#a#} + mset_heap ts" - unfolding mset_heap_def by auto + "mset_tree (Node r a ts) = {#a#} + mset_trees ts" + unfolding mset_trees_def by auto declare mset_tree.simps[simp del] lemma mset_tree_nonempty[simp]: "mset_tree t \ {#}" by (cases t) auto -lemma mset_heap_Nil[simp]: - "mset_heap [] = {#}" -by (auto simp: mset_heap_def) +lemma mset_trees_Nil[simp]: + "mset_trees [] = {#}" +by (auto simp: mset_trees_def) -lemma mset_heap_Cons[simp]: "mset_heap (t#ts) = mset_tree t + mset_heap ts" -by (auto simp: mset_heap_def) +lemma mset_trees_Cons[simp]: "mset_trees (t#ts) = mset_tree t + mset_trees ts" +by (auto simp: mset_trees_def) -lemma mset_heap_empty_iff[simp]: "mset_heap ts = {#} \ ts=[]" -by (auto simp: mset_heap_def) +lemma mset_trees_empty_iff[simp]: "mset_trees ts = {#} \ ts=[]" +by (auto simp: mset_trees_def) lemma root_in_mset[simp]: "root t \# mset_tree t" by (cases t) auto -lemma mset_heap_rev_eq[simp]: "mset_heap (rev ts) = mset_heap ts" -by (auto simp: mset_heap_def) +lemma mset_trees_rev_eq[simp]: "mset_trees (rev ts) = mset_trees ts" +by (auto simp: mset_trees_def) subsubsection \Invariants\ text \Binomial tree\ -fun invar_btree :: "'a::linorder tree \ bool" where -"invar_btree (Node r x ts) \ - (\t\set ts. invar_btree t) \ map rank ts = rev [0.. bool" where +"btree (Node r x ts) \ + (\t\set ts. btree t) \ map rank ts = rev [0..Ordering (heap) invariant\ -fun invar_otree :: "'a::linorder tree \ bool" where -"invar_otree (Node _ x ts) \ (\t\set ts. invar_otree t \ x \ root t)" +text \Heap invariant\ +fun heap :: "'a::linorder tree \ bool" where +"heap (Node _ x ts) \ (\t\set ts. heap t \ x \ root t)" -definition "invar_tree t \ invar_btree t \ invar_otree t" +definition "bheap t \ btree t \ heap t" text \Binomial Heap invariant\ -definition "invar ts \ (\t\set ts. invar_tree t) \ (sorted_wrt (<) (map rank ts))" +definition "invar ts \ (\t\set ts. bheap t) \ (sorted_wrt (<) (map rank ts))" text \The children of a node are a valid heap\ lemma invar_children: - "invar_tree (Node r v ts) \ invar (rev ts)" - by (auto simp: invar_tree_def invar_def rev_map[symmetric]) + "bheap (Node r v ts) \ invar (rev ts)" + by (auto simp: bheap_def invar_def rev_map[symmetric]) subsection \Operations and Their Functional Correctness\ @@ -95,11 +95,11 @@ end lemma invar_link: - assumes "invar_tree t\<^sub>1" - assumes "invar_tree t\<^sub>2" + assumes "bheap t\<^sub>1" + assumes "bheap t\<^sub>2" assumes "rank t\<^sub>1 = rank t\<^sub>2" - shows "invar_tree (link t\<^sub>1 t\<^sub>2)" -using assms unfolding invar_tree_def + shows "bheap (link t\<^sub>1 t\<^sub>2)" +using assms unfolding bheap_def by (cases "(t\<^sub>1, t\<^sub>2)" rule: link.cases) auto lemma rank_link[simp]: "rank (link t\<^sub>1 t\<^sub>2) = rank t\<^sub>1 + 1" @@ -110,29 +110,29 @@ subsubsection \\ins_tree\\ -fun ins_tree :: "'a::linorder tree \ 'a heap \ 'a heap" where +fun ins_tree :: "'a::linorder tree \ 'a trees \ 'a trees" where "ins_tree t [] = [t]" | "ins_tree t\<^sub>1 (t\<^sub>2#ts) = (if rank t\<^sub>1 < rank t\<^sub>2 then t\<^sub>1#t\<^sub>2#ts else ins_tree (link t\<^sub>1 t\<^sub>2) ts)" -lemma invar_tree0[simp]: "invar_tree (Node 0 x [])" -unfolding invar_tree_def by auto +lemma bheap0[simp]: "bheap (Node 0 x [])" +unfolding bheap_def by auto lemma invar_Cons[simp]: "invar (t#ts) - \ invar_tree t \ invar ts \ (\t'\set ts. rank t < rank t')" + \ bheap t \ invar ts \ (\t'\set ts. rank t < rank t')" by (auto simp: invar_def) lemma invar_ins_tree: - assumes "invar_tree t" + assumes "bheap t" assumes "invar ts" assumes "\t'\set ts. rank t \ rank t'" shows "invar (ins_tree t ts)" using assms by (induction t ts rule: ins_tree.induct) (auto simp: invar_link less_eq_Suc_le[symmetric]) -lemma mset_heap_ins_tree[simp]: - "mset_heap (ins_tree t ts) = mset_tree t + mset_heap ts" +lemma mset_trees_ins_tree[simp]: + "mset_trees (ins_tree t ts) = mset_tree t + mset_trees ts" by (induction t ts rule: ins_tree.induct) auto lemma ins_tree_rank_bound: @@ -147,13 +147,13 @@ hide_const (open) insert -definition insert :: "'a::linorder \ 'a heap \ 'a heap" where +definition insert :: "'a::linorder \ 'a trees \ 'a trees" where "insert x ts = ins_tree (Node 0 x []) ts" lemma invar_insert[simp]: "invar t \ invar (insert x t)" by (auto intro!: invar_ins_tree simp: insert_def) -lemma mset_heap_insert[simp]: "mset_heap (insert x t) = {#x#} + mset_heap t" +lemma mset_trees_insert[simp]: "mset_trees (insert x t) = {#x#} + mset_trees t" by(auto simp: insert_def) subsubsection \\merge\\ @@ -162,7 +162,7 @@ includes pattern_aliases begin -fun merge :: "'a::linorder heap \ 'a heap \ 'a heap" where +fun merge :: "'a::linorder trees \ 'a trees \ 'a trees" where "merge ts\<^sub>1 [] = ts\<^sub>1" | "merge [] ts\<^sub>2 = ts\<^sub>2" | "merge (t\<^sub>1#ts\<^sub>1 =: h\<^sub>1) (t\<^sub>2#ts\<^sub>2 =: h\<^sub>2) = ( @@ -205,7 +205,7 @@ case (3 t\<^sub>1 ts\<^sub>1 t\<^sub>2 ts\<^sub>2) \ \Invariants of the parts can be shown automatically\ from "3.prems" have [simp]: - "invar_tree t\<^sub>1" "invar_tree t\<^sub>2" + "bheap t\<^sub>1" "bheap t\<^sub>2" (*"invar (merge (t\<^sub>1#ts\<^sub>1) ts\<^sub>2)" "invar (merge ts\<^sub>1 (t\<^sub>2#ts\<^sub>2))" "invar (merge ts\<^sub>1 ts\<^sub>2)"*) @@ -259,50 +259,50 @@ qed auto -lemma mset_heap_merge[simp]: - "mset_heap (merge ts\<^sub>1 ts\<^sub>2) = mset_heap ts\<^sub>1 + mset_heap ts\<^sub>2" +lemma mset_trees_merge[simp]: + "mset_trees (merge ts\<^sub>1 ts\<^sub>2) = mset_trees ts\<^sub>1 + mset_trees ts\<^sub>2" by (induction ts\<^sub>1 ts\<^sub>2 rule: merge.induct) auto subsubsection \\get_min\\ -fun get_min :: "'a::linorder heap \ 'a" where +fun get_min :: "'a::linorder trees \ 'a" where "get_min [t] = root t" | "get_min (t#ts) = min (root t) (get_min ts)" -lemma invar_tree_root_min: - assumes "invar_tree t" +lemma bheap_root_min: + assumes "bheap t" assumes "x \# mset_tree t" shows "root t \ x" -using assms unfolding invar_tree_def -by (induction t arbitrary: x rule: mset_tree.induct) (fastforce simp: mset_heap_def) +using assms unfolding bheap_def +by (induction t arbitrary: x rule: mset_tree.induct) (fastforce simp: mset_trees_def) lemma get_min_mset: assumes "ts\[]" assumes "invar ts" - assumes "x \# mset_heap ts" + assumes "x \# mset_trees ts" shows "get_min ts \ x" using assms apply (induction ts arbitrary: x rule: get_min.induct) apply (auto - simp: invar_tree_root_min min_def intro: order_trans; - meson linear order_trans invar_tree_root_min + simp: bheap_root_min min_def intro: order_trans; + meson linear order_trans bheap_root_min )+ done lemma get_min_member: - "ts\[] \ get_min ts \# mset_heap ts" + "ts\[] \ get_min ts \# mset_trees ts" by (induction ts rule: get_min.induct) (auto simp: min_def) lemma get_min: - assumes "mset_heap ts \ {#}" + assumes "mset_trees ts \ {#}" assumes "invar ts" - shows "get_min ts = Min_mset (mset_heap ts)" + shows "get_min ts = Min_mset (mset_trees ts)" using assms get_min_member get_min_mset by (auto simp: eq_Min_iff) subsubsection \\get_min_rest\\ -fun get_min_rest :: "'a::linorder heap \ 'a tree \ 'a heap" where +fun get_min_rest :: "'a::linorder trees \ 'a tree \ 'a trees" where "get_min_rest [t] = (t,[])" | "get_min_rest (t#ts) = (let (t',ts') = get_min_rest ts in if root t \ root t' then (t,ts) else (t',t#ts'))" @@ -332,9 +332,9 @@ assumes "get_min_rest ts = (t',ts')" assumes "ts\[]" assumes "invar ts" - shows "invar_tree t'" and "invar ts'" + shows "bheap t'" and "invar ts'" proof - - have "invar_tree t' \ invar ts'" + have "bheap t' \ invar ts'" using assms proof (induction ts arbitrary: t' ts' rule: get_min.induct) case (2 t v va) @@ -343,12 +343,12 @@ apply (drule set_get_min_rest; fastforce) done qed auto - thus "invar_tree t'" and "invar ts'" by auto + thus "bheap t'" and "invar ts'" by auto qed subsubsection \\del_min\\ -definition del_min :: "'a::linorder heap \ 'a::linorder heap" where +definition del_min :: "'a::linorder trees \ 'a::linorder trees" where "del_min ts = (case get_min_rest ts of (Node r x ts\<^sub>1, ts\<^sub>2) \ merge (rev ts\<^sub>1) ts\<^sub>2)" @@ -364,15 +364,15 @@ dest: invar_get_min_rest ) -lemma mset_heap_del_min: +lemma mset_trees_del_min: assumes "ts \ []" - shows "mset_heap ts = mset_heap (del_min ts) + {# get_min ts #}" + shows "mset_trees ts = mset_trees (del_min ts) + {# get_min ts #}" using assms unfolding del_min_def apply (clarsimp split: tree.split prod.split) apply (frule (1) get_min_rest_get_min_same_root) apply (frule (1) mset_get_min_rest) -apply (auto simp: mset_heap_def) +apply (auto simp: mset_trees_def) done @@ -381,10 +381,10 @@ text \Last step of functional correctness proof: combine all the above lemmas to show that binomial heaps satisfy the specification of priority queues with merge.\ -interpretation binheap: Priority_Queue_Merge +interpretation bheaps: Priority_Queue_Merge where empty = "[]" and is_empty = "(=) []" and insert = insert and get_min = get_min and del_min = del_min and merge = merge - and invar = invar and mset = mset_heap + and invar = invar and mset = mset_trees proof (unfold_locales, goal_cases) case 1 thus ?case by simp next @@ -393,7 +393,7 @@ case 3 thus ?case by auto next case (4 q) - thus ?case using mset_heap_del_min[of q] get_min[OF _ \invar q\] + thus ?case using mset_trees_del_min[of q] get_min[OF _ \invar q\] by (auto simp: union_single_eq_diff) next case (5 q) thus ?case using get_min[of q] by auto @@ -414,7 +414,7 @@ text \The size of a binomial tree is determined by its rank\ lemma size_mset_btree: - assumes "invar_btree t" + assumes "btree t" shows "size (mset_tree t) = 2^rank t" using assms proof (induction t) @@ -424,7 +424,7 @@ from Node have COMPL: "map rank ts = rev [0..t\ts. size (mset_tree t))" + have "size (mset_trees ts) = (\t\ts. size (mset_tree t))" by (induction ts) auto also have "\ = (\t\ts. 2^rank t)" using IH by (auto cong: map_cong) @@ -440,19 +440,19 @@ qed lemma size_mset_tree: - assumes "invar_tree t" + assumes "bheap t" shows "size (mset_tree t) = 2^rank t" -using assms unfolding invar_tree_def +using assms unfolding bheap_def by (simp add: size_mset_btree) text \The length of a binomial heap is bounded by the number of its elements\ -lemma size_mset_heap: +lemma size_mset_trees: assumes "invar ts" - shows "length ts \ log 2 (size (mset_heap ts) + 1)" + shows "length ts \ log 2 (size (mset_trees ts) + 1)" proof - from \invar ts\ have ASC: "sorted_wrt (<) (map rank ts)" and - TINV: "\t\set ts. invar_tree t" + TINV: "\t\set ts. bheap t" unfolding invar_def by auto have "(2::nat)^length ts = (\i\{0.. = (\t\ts. size (mset_tree t)) + 1" using TINV by (auto cong: map_cong simp: size_mset_tree) - also have "\ = size (mset_heap ts) + 1" - unfolding mset_heap_def by (induction ts) auto - finally have "2^length ts \ size (mset_heap ts) + 1" . + also have "\ = size (mset_trees ts) + 1" + unfolding mset_trees_def by (induction ts) auto + finally have "2^length ts \ size (mset_trees ts) + 1" . then show ?thesis using le_log2_of_power by blast qed @@ -481,14 +481,14 @@ text \This function is non-canonical: we omitted a \+1\ in the \else\-part, to keep the following analysis simpler and more to the point. \ -fun T_ins_tree :: "'a::linorder tree \ 'a heap \ nat" where +fun T_ins_tree :: "'a::linorder tree \ 'a trees \ nat" where "T_ins_tree t [] = 1" | "T_ins_tree t\<^sub>1 (t\<^sub>2 # ts) = ( (if rank t\<^sub>1 < rank t\<^sub>2 then 1 else T_link t\<^sub>1 t\<^sub>2 + T_ins_tree (link t\<^sub>1 t\<^sub>2) ts) )" -definition T_insert :: "'a::linorder \ 'a heap \ nat" where +definition T_insert :: "'a::linorder \ 'a trees \ nat" where "T_insert x ts = T_ins_tree (Node 0 x []) ts + 1" lemma T_ins_tree_simple_bound: "T_ins_tree t ts \ length ts + 1" @@ -498,12 +498,12 @@ lemma T_insert_bound: assumes "invar ts" - shows "T_insert x ts \ log 2 (size (mset_heap ts) + 1) + 2" + shows "T_insert x ts \ log 2 (size (mset_trees ts) + 1) + 2" proof - have "real (T_insert x ts) \ real (length ts) + 2" unfolding T_insert_def using T_ins_tree_simple_bound using of_nat_mono by fastforce - also note size_mset_heap[OF \invar ts\] + also note size_mset_trees[OF \invar ts\] finally show ?thesis by simp qed @@ -513,7 +513,7 @@ includes pattern_aliases begin -fun T_merge :: "'a::linorder heap \ 'a heap \ nat" where +fun T_merge :: "'a::linorder trees \ 'a trees \ nat" where "T_merge ts\<^sub>1 [] = 1" | "T_merge [] ts\<^sub>2 = 1" | "T_merge (t\<^sub>1#ts\<^sub>1 =: h\<^sub>1) (t\<^sub>2#ts\<^sub>2 =: h\<^sub>2) = 1 + ( @@ -532,15 +532,15 @@ by (induction t ts rule: ins_tree.induct) auto lemma T_merge_length: - "length (merge ts\<^sub>1 ts\<^sub>2) + T_merge ts\<^sub>1 ts\<^sub>2 \ 2 * (length ts\<^sub>1 + length ts\<^sub>2) + 1" + "T_merge ts\<^sub>1 ts\<^sub>2 + length (merge ts\<^sub>1 ts\<^sub>2) \ 2 * (length ts\<^sub>1 + length ts\<^sub>2) + 1" by (induction ts\<^sub>1 ts\<^sub>2 rule: T_merge.induct) (auto simp: T_ins_tree_length algebra_simps) text \Finally, we get the desired logarithmic bound\ lemma T_merge_bound: fixes ts\<^sub>1 ts\<^sub>2 - defines "n\<^sub>1 \ size (mset_heap ts\<^sub>1)" - defines "n\<^sub>2 \ size (mset_heap ts\<^sub>2)" + defines "n\<^sub>1 \ size (mset_trees ts\<^sub>1)" + defines "n\<^sub>2 \ size (mset_trees ts\<^sub>2)" assumes "invar ts\<^sub>1" "invar ts\<^sub>2" shows "T_merge ts\<^sub>1 ts\<^sub>2 \ 4*log 2 (n\<^sub>1 + n\<^sub>2 + 1) + 1" proof - @@ -548,8 +548,8 @@ have "T_merge ts\<^sub>1 ts\<^sub>2 \ 2 * real (length ts\<^sub>1) + 2 * real (length ts\<^sub>2) + 1" using T_merge_length[of ts\<^sub>1 ts\<^sub>2] by simp - also note size_mset_heap[OF \invar ts\<^sub>1\] - also note size_mset_heap[OF \invar ts\<^sub>2\] + also note size_mset_trees[OF \invar ts\<^sub>1\] + also note size_mset_trees[OF \invar ts\<^sub>2\] finally have "T_merge ts\<^sub>1 ts\<^sub>2 \ 2 * log 2 (n\<^sub>1 + 1) + 2 * log 2 (n\<^sub>2 + 1) + 1" unfolding n_defs by (simp add: algebra_simps) also have "log 2 (n\<^sub>1 + 1) \ log 2 (n\<^sub>1 + n\<^sub>2 + 1)" @@ -561,7 +561,7 @@ subsubsection \\T_get_min\\ -fun T_get_min :: "'a::linorder heap \ nat" where +fun T_get_min :: "'a::linorder trees \ nat" where "T_get_min [t] = 1" | "T_get_min (t#ts) = 1 + T_get_min ts" @@ -571,16 +571,16 @@ lemma T_get_min_bound: assumes "invar ts" assumes "ts\[]" - shows "T_get_min ts \ log 2 (size (mset_heap ts) + 1)" + shows "T_get_min ts \ log 2 (size (mset_trees ts) + 1)" proof - have 1: "T_get_min ts = length ts" using assms T_get_min_estimate by auto - also note size_mset_heap[OF \invar ts\] + also note size_mset_trees[OF \invar ts\] finally show ?thesis . qed subsubsection \\T_del_min\\ -fun T_get_min_rest :: "'a::linorder heap \ nat" where +fun T_get_min_rest :: "'a::linorder trees \ nat" where "T_get_min_rest [t] = 1" | "T_get_min_rest (t#ts) = 1 + T_get_min_rest ts" @@ -590,10 +590,10 @@ lemma T_get_min_rest_bound: assumes "invar ts" assumes "ts\[]" - shows "T_get_min_rest ts \ log 2 (size (mset_heap ts) + 1)" + shows "T_get_min_rest ts \ log 2 (size (mset_trees ts) + 1)" proof - have 1: "T_get_min_rest ts = length ts" using assms T_get_min_rest_estimate by auto - also note size_mset_heap[OF \invar ts\] + also note size_mset_trees[OF \invar ts\] finally show ?thesis . qed @@ -603,14 +603,14 @@ definition "T_rev xs = length xs + 1" -definition T_del_min :: "'a::linorder heap \ nat" where +definition T_del_min :: "'a::linorder trees \ nat" where "T_del_min ts = T_get_min_rest ts + (case get_min_rest ts of (Node _ x ts\<^sub>1, ts\<^sub>2) \ T_rev ts\<^sub>1 + T_merge (rev ts\<^sub>1) ts\<^sub>2 ) + 1" lemma T_del_min_bound: fixes ts - defines "n \ size (mset_heap ts)" + defines "n \ size (mset_trees ts)" assumes "invar ts" and "ts\[]" shows "T_del_min ts \ 6 * log 2 (n+1) + 3" proof - @@ -621,12 +621,12 @@ using invar_get_min_rest[OF GM \ts\[]\ \invar ts\] invar_children by auto - define n\<^sub>1 where "n\<^sub>1 = size (mset_heap ts\<^sub>1)" - define n\<^sub>2 where "n\<^sub>2 = size (mset_heap ts\<^sub>2)" + define n\<^sub>1 where "n\<^sub>1 = size (mset_trees ts\<^sub>1)" + define n\<^sub>2 where "n\<^sub>2 = size (mset_trees ts\<^sub>2)" have "n\<^sub>1 \ n" "n\<^sub>1 + n\<^sub>2 \ n" unfolding n_def n\<^sub>1_def n\<^sub>2_def using mset_get_min_rest[OF GM \ts\[]\] - by (auto simp: mset_heap_def) + by (auto simp: mset_trees_def) have "T_del_min ts = real (T_get_min_rest ts) + real (T_rev ts\<^sub>1) + real (T_merge (rev ts\<^sub>1) ts\<^sub>2) + 1" unfolding T_del_min_def GM @@ -634,7 +634,7 @@ also have "T_get_min_rest ts \ log 2 (n+1)" using T_get_min_rest_bound[OF \invar ts\ \ts\[]\] unfolding n_def by simp also have "T_rev ts\<^sub>1 \ 1 + log 2 (n\<^sub>1 + 1)" - unfolding T_rev_def n\<^sub>1_def using size_mset_heap[OF I1] by simp + unfolding T_rev_def n\<^sub>1_def using size_mset_trees[OF I1] by simp also have "T_merge (rev ts\<^sub>1) ts\<^sub>2 \ 4*log 2 (n\<^sub>1 + n\<^sub>2 + 1) + 1" unfolding n\<^sub>1_def n\<^sub>2_def using T_merge_bound[OF I1 I2] by (simp add: algebra_simps) finally have "T_del_min ts \ log 2 (n+1) + log 2 (n\<^sub>1 + 1) + 4*log 2 (real (n\<^sub>1 + n\<^sub>2) + 1) + 3"