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 x1 ts1 =: t1) (Node r' x2 ts2 =: t2) = (if x1≤x2 then Node (r+1) x1 (t2#ts1) else Node (r+1) x2 (t1#ts2))"
end
lemma invar_link: assumes"bheap t1" assumes"bheap t2" assumes"rank t1 = rank t2" shows"bheap (link t1 t2)" using assms unfolding bheap_def by (cases "(t1, t2)" 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 ts1" assumes"invar ts2" shows"invar (merge ts1 ts2)" using assms proof (induction ts1 ts2 rule: merge.induct) case (3 t1 ts1 t2 ts2) ―‹Invariants of the parts can be shown automatically› from"3.prems"have [simp]: "bheap t1""bheap t2" (*"invar (merge (t\<^sub>1#ts\<^sub>1) ts\<^sub>2)" "invar(mergets\<^sub>1(t\<^sub>2#ts\<^sub>2))"
"invar (merge ts\<^sub>1 ts\<^sub>2)"*) by auto
―‹These are the three cases of the @{const merge} function›
consider (LT) "rank t1 < rank t2"
| (GT) "rank t1 > rank t2"
| (EQ) "rank t1 = rank t2" using antisym_conv3 by blast thenshow ?caseproof cases case LT ―‹@{const merge} takes the first tree from the left heap› thenhave"merge (t1 # ts1) (t2 # ts2) = t1 # merge ts1 (t2 # ts2)"by simp alsohave"invar …"proof (simp, intro conjI) ―‹Invariant follows from induction hypothesis› show"invar (merge ts1 (t2 # ts2))" using LT "3.IH""3.prems"by simp
―‹It remains to show that ‹t1› has smallest rank.› show"∀t'∈set (merge ts1 (t2 # ts2)). rank t1 < 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 (t1 # ts1) (t2 # ts2) = ins_tree (link t1 t2) (merge ts1 ts2)"by simp alsohave"invar …"proof (intro invar_ins_tree invar_link) ―‹Invariant of merged remaining heaps follows by IH› show"invar (merge ts1 ts2)" 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 ts1 ts2). rank (link t1 t2) ≤ rank t'" proof - ―‹Which is, again, done with the help of @{thm [source] merge_rank_bound}› have"rank (link t1 t2) = Suc (rank t2)"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 ts1 ts2) = mset_forest ts1 + mset_forest ts2" by (induction ts1 ts2 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
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) case1thus ?caseby simp next case2thus ?caseby auto next case3thus ?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 case6thus ?caseby (auto simp add: invar_def) next case7thus ?caseby simp next case8thus ?caseby simp next case9thus ?caseby simp next case10thus ?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..<r]"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..<r}. 2^i)" 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..<length ts}. 2^i) + 1" by (simp add: sum_power2) alsohave"… = (∑i←[0..<length ts]. 2^i) + 1" (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>, apparentlybecauseofthe\<open>let\<close>clausesintroducedbypattern_aliases;shouldbeinvestigated.
*)
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.