(* Author: Peter Lammich Tobias Nipkow (tuning) *)
section‹Binomial Priority Queue›
theory Binomial_Heap imports "HOL-Library.Pattern_Aliases"
Complex_Main
Priority_Queue_Specs "HOL-Library.Time_Functions" begin
text‹ We formalize the presentation from Okasaki's book. We show the functional correctness and complexity of all operations. The presentation is engineered for simplicity, and most proofs are straightforward and automatic. ›
subsection‹Binomial Tree and Forest Types›
datatype 'a tree = Node (rank: nat) (root: 'a) (children: "'a tree list")
type_synonym 'a forest = "'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)"
text‹A binomial forest is often called a binomial heap, but this overloads the latter term.›
text‹The children of a binomial heap node are a valid forest:› lemma invar_children: "bheap (Node r v ts) ==> invar (rev ts)" by (auto simp: bheap_def invar_def rev_map[symmetric])
subsection‹Operations and Their Functional Correctness›
subsubsection ‹‹link›\›
context includes pattern_aliases begin
fun link :: "('a::linorder) tree ==> 'a tree ==> 'a tree"where "link (Node r x🪙1 ts🪙1 =: t🪙1) (Node r' x🪙2 ts🪙2 =: t🪙2) = (if x🪙1≤x🪙2 then Node (r+1) x🪙1 (t🪙2#ts🪙1) else Node (r+1) x🪙2 (t🪙1#ts🪙2))"
end
lemma invar_link: assumes"bheap t🪙1" assumes"bheap t🪙2" assumes"rank t🪙1 = rank t🪙2" shows"bheap (link t🪙1 t🪙2)" using assms unfolding bheap_def by (cases "(t🪙1, t🪙2)" rule: link.cases) auto
text‹Longer, more explicit proof of @{thm [source] invar_merge}, to illustrate the application of the @{thm [source] merge_rank_bound} lemma.› lemma assumes"invar ts🪙1" assumes"invar ts🪙2" shows"invar (merge ts🪙1 ts🪙2)" using assms proof (induction ts🪙1 ts🪙2 rule: merge.induct) case (3 t🪙1 ts🪙1 t🪙2 ts🪙2) 🍋‹Invariants of the parts can be shown automatically› from"3.prems"have [simp]: "bheap t🪙1""bheap t🪙2" (*"invar (merge (t\<^sub>1#ts\<^sub>1) ts\<^sub>2)" "invar (merge ts🪙1 (t🪙2#ts🪙2))" "invar (merge ts\<^sub>1 ts\<^sub>2)"*) by auto
🍋‹These are the three cases of the @{const merge} function›
consider (LT) "rank t🪙1 < rank t🪙2"
| (GT) "rank t🪙1 > rank t🪙2"
| (EQ) "rank t🪙1 = rank t🪙2" using antisym_conv3 by blast thenshow ?caseproof cases case LT 🍋‹@{const merge} takes the first tree from the left heap› thenhave"merge (t🪙1 # ts🪙1) (t🪙2 # ts🪙2) = t🪙1 # merge ts🪙1 (t🪙2 # ts🪙2)"by simp alsohave"invar …"proof (simp, intro conjI) 🍋‹Invariant follows from induction hypothesis› show"invar (merge ts🪙1 (t🪙2 # ts🪙2))" using LT "3.IH""3.prems"by simp
🍋‹It remains to show that ‹t🪙1›has smallest rank.› show"∀t'∈set (merge ts🪙1 (t🪙2 # ts🪙2)). rank t🪙1 < rank t'" 🍋‹Which is done by auxiliary lemma @{thm [source] merge_rank_bound}› using LT "3.prems"by (force elim!: merge_rank_bound) qed finallyshow ?thesis . next 🍋‹@{const merge} takes the first tree from the right heap› case GT 🍋‹The proof is anaologous to the ‹LT›case› thenshow ?thesis using"3.prems""3.IH"by (force elim!: merge_rank_bound) next case [simp]: EQ 🍋‹@{const merge} links both first forest, and inserts them into the merged remaining heaps› have"merge (t🪙1 # ts🪙1) (t🪙2 # ts🪙2) = ins_tree (link t🪙1 t🪙2) (merge ts🪙1 ts🪙2)"by simp alsohave"invar …"proof (intro invar_ins_tree invar_link) 🍋‹Invariant of merged remaining heaps follows by IH› show"invar (merge ts🪙1 ts🪙2)" using EQ "3.prems""3.IH"by auto
🍋‹For insertion, we have to show that the rank of the linked tree is ‹≤›the ranks in the merged remaining heaps› show"∀t'∈set (merge ts🪙1 ts🪙2). rank (link t🪙1 t🪙2) ≤ rank t'" proof - 🍋‹Which is, again, done with the help of @{thm [source] merge_rank_bound}› have"rank (link t🪙1 t🪙2) = Suc (rank t🪙2)"by simp thus ?thesis using"3.prems"by (auto simp: Suc_le_eq elim!: merge_rank_bound) qed qed simp_all finallyshow ?thesis . qed qed auto
lemma mset_forest_merge[simp]: "mset_forest (merge ts🪙1 ts🪙2) = mset_forest ts🪙1 + mset_forest ts🪙2" by (induction ts🪙1 ts🪙2 rule: merge.induct) auto
fun get_min_rest :: "'a::linorder forest ==> 'a tree × 'a forest"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'))"
subsubsection ‹Instantiating the Priority Queue Locale›
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 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_forest proof (unfold_locales, goal_cases) case 1 thus ?caseby simp next case 2 thus ?caseby auto next case 3 thus ?caseby auto next case (4 q) thus ?caseusing mset_forest_del_min[of q] get_min[OF _ ‹invar q›] by (auto simp: union_single_eq_diff) next case (5 q) thus ?caseusing get_min[of q] by auto next case 6 thus ?caseby (auto simp add: invar_def) next case 7 thus ?caseby simp next case 8 thus ?caseby simp next case 9 thus ?caseby simp next case 10 thus ?caseby simp qed
subsection‹Complexity›
text‹The size of a binomial tree is determined by its rank› lemma size_mset_btree: assumes"btree t" shows"size (mset_tree t) = 2^rank t" using assms proof (induction t) case (Node r v ts) hence IH: "size (mset_tree t) = 2^rank t"if"t ∈ set ts"for t using that by auto
from Node have COMPL: "map rank ts = rev [0..by auto
have"size (mset_forest ts) = (∑t←ts. size (mset_tree t))" by (induction ts) auto alsohave"… = (∑t←ts. 2^rank t)"using IH by (auto cong: map_cong) alsohave"… = (∑r←map rank ts. 2^r)" by (induction ts) auto alsohave"… = (∑i∈{0.. unfolding COMPL by (auto simp: rev_map[symmetric] interv_sum_list_conv_sum_set_nat) alsohave"… = 2^r - 1" by (induction r) auto finallyshow ?case by (simp) qed
lemma size_mset_tree: assumes"bheap t" shows"size (mset_tree t) = 2^rank t" 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_forest: assumes"invar ts" shows"length ts ≤ log 2 (size (mset_forest ts) + 1)" proof - from‹invar ts›have
ASC: "sorted_wrt (<) (map rank ts)"and
TINV: "∀t∈set ts. bheap t" unfolding invar_def by auto
have"(2::nat)^length ts = (∑i∈{0.. by (simp add: sum_power2) alsohave"… = (∑i←[0.. (is"_ = ?S + 1") by (simp add: interv_sum_list_conv_sum_set_nat) alsohave"?S ≤ (∑t←ts. 2^rank t)" (is"_ ≤ ?T") using sorted_wrt_less_idx[OF ASC] by(simp add: sum_list_mono2) alsohave"?T + 1 ≤ (∑t←ts. size (mset_tree t)) + 1"using TINV by (auto cong: map_cong simp: size_mset_tree) alsohave"… = size (mset_forest ts) + 1" unfolding mset_forest_def by (induction ts) auto finallyhave"2^length ts ≤ size (mset_forest ts) + 1"by simp thenshow ?thesis using le_log2_of_power by blast qed
lemma T_rank[simp]: "T_rank t = 0" by(cases t, auto)
time_fun ins_tree
time_fun insert
lemma T_ins_tree_simple_bound: "T_ins_tree t ts ≤ length ts + 1" by (induction t ts rule: T_ins_tree.induct) auto
subsubsection ‹‹T_insert›\›
lemma T_insert_bound: assumes"invar ts" shows"T_insert x ts ≤ log 2 (size (mset_forest ts) + 1) + 1" proof - have"real (T_insert x ts) ≤ real (length ts) + 1" unfolding T_insert.simps using T_ins_tree_simple_bound by (metis of_nat_1 of_nat_add of_nat_mono) alsonote size_mset_forest[OF ‹invar ts›] finallyshow ?thesis by simp qed
subsubsection ‹‹T_merge›\›
time_fun merge
(* Warning: \<open>T_merge.induct\<close> is less convenient than the equivalent \<open>merge.induct\<close>, apparently because of the ‹let›clauses introduced by pattern_aliases; should be investigated. *)
text‹A crucial idea is to estimate the time in correlation with the result length, as each carry reduces the length of the result.›
lemma T_ins_tree_length: "T_ins_tree t ts + length (ins_tree t ts) = 2 + length ts" by (induction t ts rule: ins_tree.induct) auto
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.