| 78231 |      1 | (* Author: Tobias Nipkow *)
 | 
|  |      2 | 
 | 
|  |      3 | theory Leftist_Heap_List
 | 
|  |      4 | imports
 | 
|  |      5 |   Leftist_Heap
 | 
|  |      6 |   Complex_Main
 | 
|  |      7 | begin
 | 
|  |      8 | 
 | 
|  |      9 | subsection "Converting a list into a leftist heap"
 | 
|  |     10 | 
 | 
|  |     11 | fun merge_adj :: "('a::ord) lheap list \<Rightarrow> 'a lheap list" where
 | 
|  |     12 | "merge_adj [] = []" |
 | 
|  |     13 | "merge_adj [t] = [t]" |
 | 
|  |     14 | "merge_adj (t1 # t2 # ts) = merge t1 t2 # merge_adj ts"
 | 
|  |     15 | 
 | 
|  |     16 | text \<open>For the termination proof of \<open>merge_all\<close> below.\<close>
 | 
|  |     17 | lemma length_merge_adjacent[simp]: "length (merge_adj ts) = (length ts + 1) div 2"
 | 
|  |     18 | by (induction ts rule: merge_adj.induct) auto
 | 
|  |     19 | 
 | 
|  |     20 | fun merge_all :: "('a::ord) lheap list \<Rightarrow> 'a lheap" where
 | 
|  |     21 | "merge_all [] = Leaf" |
 | 
|  |     22 | "merge_all [t] = t" |
 | 
|  |     23 | "merge_all ts = merge_all (merge_adj ts)"
 | 
|  |     24 | 
 | 
|  |     25 | 
 | 
|  |     26 | subsubsection \<open>Functional correctness\<close>
 | 
|  |     27 | 
 | 
|  |     28 | lemma heap_merge_adj: "\<forall>t \<in> set ts. heap t \<Longrightarrow> \<forall>t \<in> set (merge_adj ts). heap t"
 | 
|  |     29 | by(induction ts rule: merge_adj.induct) (auto simp: heap_merge)
 | 
|  |     30 | 
 | 
|  |     31 | lemma ltree_merge_adj: "\<forall>t \<in> set ts. ltree t \<Longrightarrow> \<forall>t \<in> set (merge_adj ts). ltree t"
 | 
|  |     32 | by(induction ts rule: merge_adj.induct) (auto simp: ltree_merge)
 | 
|  |     33 | 
 | 
|  |     34 | lemma heap_merge_all: "\<forall>t \<in> set ts. heap t \<Longrightarrow> heap (merge_all ts)"
 | 
|  |     35 | apply(induction ts rule: merge_all.induct)
 | 
|  |     36 | using [[simp_depth_limit=3]] by (auto simp add: heap_merge_adj)
 | 
|  |     37 | 
 | 
|  |     38 | lemma ltree_merge_all: "\<forall>t \<in> set ts. ltree t \<Longrightarrow> ltree (merge_all ts)"
 | 
|  |     39 | apply(induction ts rule: merge_all.induct)
 | 
|  |     40 | using [[simp_depth_limit=3]] by (auto simp add: ltree_merge_adj)
 | 
|  |     41 | 
 | 
|  |     42 | lemma mset_merge_adj:
 | 
|  |     43 |   "\<Sum>\<^sub># (image_mset mset_tree (mset (merge_adj ts))) =
 | 
|  |     44 |    \<Sum>\<^sub># (image_mset mset_tree (mset ts))"
 | 
|  |     45 | by(induction ts rule: merge_adj.induct) (auto simp: mset_merge)
 | 
|  |     46 | 
 | 
|  |     47 | lemma mset_merge_all:
 | 
|  |     48 |   "mset_tree (merge_all ts) = \<Sum>\<^sub># (mset (map mset_tree ts))"
 | 
|  |     49 | by(induction ts rule: merge_all.induct) (auto simp: mset_merge mset_merge_adj)
 | 
|  |     50 | 
 | 
|  |     51 | fun lheap_list :: "'a::ord list \<Rightarrow> 'a lheap" where
 | 
|  |     52 | "lheap_list xs = merge_all (map (\<lambda>x. Node Leaf (x,1) Leaf) xs)"
 | 
|  |     53 | 
 | 
|  |     54 | lemma mset_lheap_list: "mset_tree (lheap_list xs) = mset xs"
 | 
|  |     55 | by (simp add: mset_merge_all o_def)
 | 
|  |     56 | 
 | 
|  |     57 | lemma ltree_lheap_list: "ltree (lheap_list ts)"
 | 
|  |     58 | by(simp add: ltree_merge_all)
 | 
|  |     59 | 
 | 
|  |     60 | lemma heap_lheap_list: "heap (lheap_list ts)"
 | 
|  |     61 | by(simp add: heap_merge_all)
 | 
|  |     62 | 
 | 
|  |     63 | lemma size_merge: "size(merge t1 t2) = size t1 + size t2"
 | 
|  |     64 | by(induction t1 t2 rule: merge.induct) (auto simp: node_def)
 | 
|  |     65 | 
 | 
|  |     66 | 
 | 
|  |     67 | subsubsection \<open>Running time\<close>
 | 
|  |     68 | 
 | 
|  |     69 | fun T_merge_adj :: "('a::ord) lheap list \<Rightarrow> nat" where
 | 
|  |     70 | "T_merge_adj [] = 0" |
 | 
|  |     71 | "T_merge_adj [t] = 0" |
 | 
|  |     72 | "T_merge_adj (t1 # t2 # ts) = T_merge t1 t2 + T_merge_adj ts"
 | 
|  |     73 | 
 | 
|  |     74 | fun T_merge_all :: "('a::ord) lheap list  \<Rightarrow> nat" where
 | 
|  |     75 | "T_merge_all [] = 0" |
 | 
|  |     76 | "T_merge_all [t] = 0" |
 | 
|  |     77 | "T_merge_all ts = T_merge_adj ts + T_merge_all (merge_adj ts)"
 | 
|  |     78 | 
 | 
|  |     79 | fun T_lheap_list :: "'a::ord list \<Rightarrow> nat" where
 | 
|  |     80 | "T_lheap_list xs = T_merge_all (map (\<lambda>x. Node Leaf (x,1) Leaf) xs)"
 | 
|  |     81 | 
 | 
|  |     82 | abbreviation Tm where
 | 
|  |     83 | "Tm n == 2 * log 2 (n+1) + 1"
 | 
|  |     84 | 
 | 
|  |     85 | lemma T_merge_adj: "\<lbrakk> \<forall>t \<in> set ts. ltree t; \<forall>t \<in> set ts. size t = n \<rbrakk>
 | 
|  |     86 |   \<Longrightarrow> T_merge_adj ts \<le> (length ts div 2) * Tm n"
 | 
|  |     87 | proof(induction ts rule: T_merge_adj.induct)
 | 
|  |     88 |   case 1 thus ?case by simp
 | 
|  |     89 | next
 | 
|  |     90 |   case 2 thus ?case by simp
 | 
|  |     91 | next
 | 
|  |     92 |   case (3 t1 t2) thus ?case using T_merge_log[of t1 t2] by (simp add: algebra_simps size1_size)
 | 
|  |     93 | qed
 | 
|  |     94 | 
 | 
|  |     95 | lemma size_merge_adj:
 | 
|  |     96 |   "\<lbrakk> even(length ts); \<forall>t \<in> set ts. ltree t; \<forall>t \<in> set ts. size t = n \<rbrakk>
 | 
|  |     97 |    \<Longrightarrow> \<forall>t \<in> set (merge_adj ts). size t = 2*n"
 | 
|  |     98 | by(induction ts rule: merge_adj.induct) (auto simp: size_merge)
 | 
|  |     99 | 
 | 
|  |    100 | lemma T_merge_all:
 | 
|  |    101 |  "\<lbrakk> \<forall>t \<in> set ts. ltree t; \<forall>t \<in> set ts. size t = n; length ts = 2^k \<rbrakk>
 | 
|  |    102 |   \<Longrightarrow> T_merge_all ts \<le> (\<Sum>i=1..k. 2^(k-i) * Tm(2 ^ (i-1) * n))"
 | 
|  |    103 | proof (induction ts arbitrary: k n rule: merge_all.induct)
 | 
|  |    104 |   case 1 thus ?case by simp
 | 
|  |    105 | next
 | 
|  |    106 |   case 2 thus ?case by simp
 | 
|  |    107 | next
 | 
|  |    108 |   case (3 t1 t2 ts)
 | 
|  |    109 |   let ?ts = "t1 # t2 # ts"
 | 
|  |    110 |   let ?ts2 = "merge_adj ?ts"
 | 
|  |    111 |   obtain k' where k': "k = Suc k'" using "3.prems"(3)
 | 
|  |    112 |     by (metis length_Cons nat.inject nat_power_eq_Suc_0_iff nat.exhaust)
 | 
|  |    113 |   have 1: "\<forall>x \<in> set(merge_adj ?ts). ltree x"
 | 
|  |    114 |     by(rule ltree_merge_adj[OF "3.prems"(1)])
 | 
|  |    115 |   have "even (length ts)" using "3.prems"(3) even_Suc_Suc_iff by fastforce
 | 
|  |    116 |   from "3.prems"(2) size_merge_adj[OF this] "3.prems"(1)
 | 
|  |    117 |   have 2: "\<forall>x \<in> set(merge_adj ?ts). size x = 2*n" by(auto simp: size_merge)
 | 
|  |    118 |   have 3: "length ?ts2 = 2 ^ k'" using "3.prems"(3) k' by auto
 | 
|  |    119 |   have 4: "length ?ts div 2 = 2 ^ k'"
 | 
|  |    120 |     using "3.prems"(3) k' by(simp add: power_eq_if[of 2 k] split: if_splits)
 | 
|  |    121 |   have "T_merge_all ?ts = T_merge_adj ?ts + T_merge_all ?ts2" by simp
 | 
|  |    122 |   also have "\<dots> \<le> 2^k' * Tm n + T_merge_all ?ts2"
 | 
|  |    123 |     using 4 T_merge_adj[OF "3.prems"(1,2)] by auto
 | 
|  |    124 |   also have "\<dots> \<le> 2^k' * Tm n + (\<Sum>i=1..k'. 2^(k'-i) * Tm(2 ^ (i-1) * (2*n)))"
 | 
|  |    125 |     using "3.IH"[OF 1 2 3] by simp
 | 
|  |    126 |   also have "\<dots> = 2^k' * Tm n + (\<Sum>i=1..k'. 2^(k'-i) * Tm(2 ^ (Suc(i-1)) * n))"
 | 
|  |    127 |     by (simp add: mult_ac cong del: sum.cong)
 | 
|  |    128 |   also have "\<dots> = 2^k' * Tm n + (\<Sum>i=1..k'. 2^(k'-i) * Tm(2 ^ i * n))"
 | 
|  |    129 |      by (simp)
 | 
|  |    130 |   also have "\<dots> = (\<Sum>i=1..k. 2^(k-i) * Tm(2 ^ (i-1) * real n))"
 | 
|  |    131 |     by(simp add: sum.atLeast_Suc_atMost[of "Suc 0" "Suc k'"] sum.atLeast_Suc_atMost_Suc_shift[of _ "Suc 0"] k'
 | 
|  |    132 |         del: sum.cl_ivl_Suc)
 | 
|  |    133 |   finally show ?case .
 | 
|  |    134 | qed
 | 
|  |    135 | 
 | 
|  |    136 | lemma summation: "(\<Sum>i=1..k. 2^(k-i) * ((2::real)*i+1)) = 5*2^k - (2::real)*k - 5"
 | 
|  |    137 | proof (induction k)
 | 
|  |    138 |   case 0 thus ?case by simp
 | 
|  |    139 | next
 | 
|  |    140 |   case (Suc k)
 | 
|  |    141 |   have "(\<Sum>i=1..Suc k. 2^(Suc k - i) * ((2::real)*i+1))
 | 
|  |    142 |     = (\<Sum>i=1..k. 2^(k+1-i) * ((2::real)*i+1)) + 2*k+3"
 | 
|  |    143 |     by(simp)
 | 
|  |    144 |   also have "\<dots> = (\<Sum>i=1..k. (2::real)*(2^(k-i) * ((2::real)*i+1))) + 2*k+3"
 | 
|  |    145 |     by (simp add: Suc_diff_le mult.assoc)
 | 
|  |    146 |   also have "\<dots> = 2*(\<Sum>i=1..k. 2^(k-i) * ((2::real)*i+1)) + 2*k+3"
 | 
|  |    147 |     by(simp add: sum_distrib_left)
 | 
|  |    148 |   also have "\<dots> = (2::real)*(5*2^k - (2::real)*k - 5) + 2*k+3"
 | 
|  |    149 |     using Suc.IH by simp
 | 
|  |    150 |   also have "\<dots> = 5*2^(Suc k) - (2::real)*(Suc k) - 5"
 | 
|  |    151 |     by simp
 | 
|  |    152 |   finally show ?case .
 | 
|  |    153 | qed
 | 
|  |    154 | 
 | 
|  |    155 | lemma T_lheap_list: assumes "length xs = 2 ^ k"
 | 
|  |    156 | shows "T_lheap_list xs \<le> 5 * length xs"
 | 
|  |    157 | proof -
 | 
|  |    158 |   let ?ts = "map (\<lambda>x. Node Leaf (x,1) Leaf) xs"
 | 
|  |    159 |   have "T_lheap_list xs = T_merge_all ?ts" by simp
 | 
|  |    160 |   also have "\<dots> \<le> (\<Sum>i = 1..k. 2^(k-i) * (2 * log 2 (2^(i-1) + 1) + 1))"
 | 
|  |    161 |     using T_merge_all[of ?ts 1 k] assms by (simp)
 | 
|  |    162 |   also have "\<dots> \<le> (\<Sum>i = 1..k. 2^(k-i) * (2 * log 2 (2*2^(i-1)) + 1))"
 | 
|  |    163 |     apply(rule sum_mono)
 | 
|  |    164 |     using zero_le_power[of "2::real"] by (simp add: add_pos_nonneg)
 | 
|  |    165 |   also have "\<dots> = (\<Sum>i = 1..k. 2^(k-i) * (2 * log 2 (2^(1+(i-1))) + 1))"
 | 
|  |    166 |     by (simp del: Suc_pred)
 | 
|  |    167 |   also have "\<dots> = (\<Sum>i = 1..k. 2^(k-i) * (2 * log 2 (2^i) + 1))"
 | 
|  |    168 |     by (simp)
 | 
|  |    169 |   also have "\<dots> = (\<Sum>i = 1..k. 2^(k-i) * ((2::real)*i+1))"
 | 
|  |    170 |     by (simp add:log_nat_power algebra_simps)
 | 
|  |    171 |   also have "\<dots> = 5*(2::real)^k - (2::real)*k - 5"
 | 
|  |    172 |     using summation by (simp)
 | 
|  |    173 |   also have "\<dots> \<le> 5*(2::real)^k"
 | 
|  |    174 |     by linarith
 | 
|  |    175 |   finally show ?thesis
 | 
|  |    176 |     using assms of_nat_le_iff by fastforce
 | 
|  |    177 | qed
 | 
|  |    178 | 
 | 
|  |    179 | end |