| 
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  | 
  | 
| 
79984
 | 
    69  | 
text \<open>Not defined automatically because we only count the time for @{const merge}.\<close>
 | 
| 
 | 
    70  | 
  | 
| 
78231
 | 
    71  | 
fun T_merge_adj :: "('a::ord) lheap list \<Rightarrow> nat" where
 | 
| 
 | 
    72  | 
"T_merge_adj [] = 0" |
  | 
| 
 | 
    73  | 
"T_merge_adj [t] = 0" |
  | 
| 
 | 
    74  | 
"T_merge_adj (t1 # t2 # ts) = T_merge t1 t2 + T_merge_adj ts"
  | 
| 
 | 
    75  | 
  | 
| 
 | 
    76  | 
fun T_merge_all :: "('a::ord) lheap list  \<Rightarrow> nat" where
 | 
| 
 | 
    77  | 
"T_merge_all [] = 0" |
  | 
| 
 | 
    78  | 
"T_merge_all [t] = 0" |
  | 
| 
 | 
    79  | 
"T_merge_all ts = T_merge_adj ts + T_merge_all (merge_adj ts)"
  | 
| 
 | 
    80  | 
  | 
| 
 | 
    81  | 
fun T_lheap_list :: "'a::ord list \<Rightarrow> nat" where
  | 
| 
 | 
    82  | 
"T_lheap_list xs = T_merge_all (map (\<lambda>x. Node Leaf (x,1) Leaf) xs)"
  | 
| 
 | 
    83  | 
  | 
| 
 | 
    84  | 
abbreviation Tm where
  | 
| 
 | 
    85  | 
"Tm n == 2 * log 2 (n+1) + 1"
  | 
| 
 | 
    86  | 
  | 
| 
 | 
    87  | 
lemma T_merge_adj: "\<lbrakk> \<forall>t \<in> set ts. ltree t; \<forall>t \<in> set ts. size t = n \<rbrakk>
  | 
| 
 | 
    88  | 
  \<Longrightarrow> T_merge_adj ts \<le> (length ts div 2) * Tm n"
  | 
| 
 | 
    89  | 
proof(induction ts rule: T_merge_adj.induct)
  | 
| 
 | 
    90  | 
  case 1 thus ?case by simp
  | 
| 
 | 
    91  | 
next
  | 
| 
 | 
    92  | 
  case 2 thus ?case by simp
  | 
| 
 | 
    93  | 
next
  | 
| 
 | 
    94  | 
  case (3 t1 t2) thus ?case using T_merge_log[of t1 t2] by (simp add: algebra_simps size1_size)
  | 
| 
 | 
    95  | 
qed
  | 
| 
 | 
    96  | 
  | 
| 
 | 
    97  | 
lemma size_merge_adj:
  | 
| 
 | 
    98  | 
  "\<lbrakk> even(length ts); \<forall>t \<in> set ts. ltree t; \<forall>t \<in> set ts. size t = n \<rbrakk>
  | 
| 
 | 
    99  | 
   \<Longrightarrow> \<forall>t \<in> set (merge_adj ts). size t = 2*n"
  | 
| 
 | 
   100  | 
by(induction ts rule: merge_adj.induct) (auto simp: size_merge)
  | 
| 
 | 
   101  | 
  | 
| 
 | 
   102  | 
lemma T_merge_all:
  | 
| 
 | 
   103  | 
 "\<lbrakk> \<forall>t \<in> set ts. ltree t; \<forall>t \<in> set ts. size t = n; length ts = 2^k \<rbrakk>
  | 
| 
 | 
   104  | 
  \<Longrightarrow> T_merge_all ts \<le> (\<Sum>i=1..k. 2^(k-i) * Tm(2 ^ (i-1) * n))"
  | 
| 
 | 
   105  | 
proof (induction ts arbitrary: k n rule: merge_all.induct)
  | 
| 
 | 
   106  | 
  case 1 thus ?case by simp
  | 
| 
 | 
   107  | 
next
  | 
| 
 | 
   108  | 
  case 2 thus ?case by simp
  | 
| 
 | 
   109  | 
next
  | 
| 
 | 
   110  | 
  case (3 t1 t2 ts)
  | 
| 
 | 
   111  | 
  let ?ts = "t1 # t2 # ts"
  | 
| 
 | 
   112  | 
  let ?ts2 = "merge_adj ?ts"
  | 
| 
 | 
   113  | 
  obtain k' where k': "k = Suc k'" using "3.prems"(3)
  | 
| 
 | 
   114  | 
    by (metis length_Cons nat.inject nat_power_eq_Suc_0_iff nat.exhaust)
  | 
| 
 | 
   115  | 
  have 1: "\<forall>x \<in> set(merge_adj ?ts). ltree x"
  | 
| 
 | 
   116  | 
    by(rule ltree_merge_adj[OF "3.prems"(1)])
  | 
| 
 | 
   117  | 
  have "even (length ts)" using "3.prems"(3) even_Suc_Suc_iff by fastforce
  | 
| 
 | 
   118  | 
  from "3.prems"(2) size_merge_adj[OF this] "3.prems"(1)
  | 
| 
 | 
   119  | 
  have 2: "\<forall>x \<in> set(merge_adj ?ts). size x = 2*n" by(auto simp: size_merge)
  | 
| 
 | 
   120  | 
  have 3: "length ?ts2 = 2 ^ k'" using "3.prems"(3) k' by auto
  | 
| 
 | 
   121  | 
  have 4: "length ?ts div 2 = 2 ^ k'"
  | 
| 
 | 
   122  | 
    using "3.prems"(3) k' by(simp add: power_eq_if[of 2 k] split: if_splits)
  | 
| 
 | 
   123  | 
  have "T_merge_all ?ts = T_merge_adj ?ts + T_merge_all ?ts2" by simp
  | 
| 
 | 
   124  | 
  also have "\<dots> \<le> 2^k' * Tm n + T_merge_all ?ts2"
  | 
| 
 | 
   125  | 
    using 4 T_merge_adj[OF "3.prems"(1,2)] by auto
  | 
| 
 | 
   126  | 
  also have "\<dots> \<le> 2^k' * Tm n + (\<Sum>i=1..k'. 2^(k'-i) * Tm(2 ^ (i-1) * (2*n)))"
  | 
| 
 | 
   127  | 
    using "3.IH"[OF 1 2 3] by simp
  | 
| 
 | 
   128  | 
  also have "\<dots> = 2^k' * Tm n + (\<Sum>i=1..k'. 2^(k'-i) * Tm(2 ^ (Suc(i-1)) * n))"
  | 
| 
 | 
   129  | 
    by (simp add: mult_ac cong del: sum.cong)
  | 
| 
 | 
   130  | 
  also have "\<dots> = 2^k' * Tm n + (\<Sum>i=1..k'. 2^(k'-i) * Tm(2 ^ i * n))"
  | 
| 
 | 
   131  | 
     by (simp)
  | 
| 
 | 
   132  | 
  also have "\<dots> = (\<Sum>i=1..k. 2^(k-i) * Tm(2 ^ (i-1) * real n))"
  | 
| 
 | 
   133  | 
    by(simp add: sum.atLeast_Suc_atMost[of "Suc 0" "Suc k'"] sum.atLeast_Suc_atMost_Suc_shift[of _ "Suc 0"] k'
  | 
| 
 | 
   134  | 
        del: sum.cl_ivl_Suc)
  | 
| 
 | 
   135  | 
  finally show ?case .
  | 
| 
 | 
   136  | 
qed
  | 
| 
 | 
   137  | 
  | 
| 
 | 
   138  | 
lemma summation: "(\<Sum>i=1..k. 2^(k-i) * ((2::real)*i+1)) = 5*2^k - (2::real)*k - 5"
  | 
| 
 | 
   139  | 
proof (induction k)
  | 
| 
 | 
   140  | 
  case 0 thus ?case by simp
  | 
| 
 | 
   141  | 
next
  | 
| 
 | 
   142  | 
  case (Suc k)
  | 
| 
 | 
   143  | 
  have "(\<Sum>i=1..Suc k. 2^(Suc k - i) * ((2::real)*i+1))
  | 
| 
 | 
   144  | 
    = (\<Sum>i=1..k. 2^(k+1-i) * ((2::real)*i+1)) + 2*k+3"
  | 
| 
 | 
   145  | 
    by(simp)
  | 
| 
 | 
   146  | 
  also have "\<dots> = (\<Sum>i=1..k. (2::real)*(2^(k-i) * ((2::real)*i+1))) + 2*k+3"
  | 
| 
 | 
   147  | 
    by (simp add: Suc_diff_le mult.assoc)
  | 
| 
 | 
   148  | 
  also have "\<dots> = 2*(\<Sum>i=1..k. 2^(k-i) * ((2::real)*i+1)) + 2*k+3"
  | 
| 
 | 
   149  | 
    by(simp add: sum_distrib_left)
  | 
| 
 | 
   150  | 
  also have "\<dots> = (2::real)*(5*2^k - (2::real)*k - 5) + 2*k+3"
  | 
| 
 | 
   151  | 
    using Suc.IH by simp
  | 
| 
 | 
   152  | 
  also have "\<dots> = 5*2^(Suc k) - (2::real)*(Suc k) - 5"
  | 
| 
 | 
   153  | 
    by simp
  | 
| 
 | 
   154  | 
  finally show ?case .
  | 
| 
 | 
   155  | 
qed
  | 
| 
 | 
   156  | 
  | 
| 
 | 
   157  | 
lemma T_lheap_list: assumes "length xs = 2 ^ k"
  | 
| 
 | 
   158  | 
shows "T_lheap_list xs \<le> 5 * length xs"
  | 
| 
 | 
   159  | 
proof -
  | 
| 
 | 
   160  | 
  let ?ts = "map (\<lambda>x. Node Leaf (x,1) Leaf) xs"
  | 
| 
 | 
   161  | 
  have "T_lheap_list xs = T_merge_all ?ts" by simp
  | 
| 
 | 
   162  | 
  also have "\<dots> \<le> (\<Sum>i = 1..k. 2^(k-i) * (2 * log 2 (2^(i-1) + 1) + 1))"
  | 
| 
 | 
   163  | 
    using T_merge_all[of ?ts 1 k] assms by (simp)
  | 
| 
 | 
   164  | 
  also have "\<dots> \<le> (\<Sum>i = 1..k. 2^(k-i) * (2 * log 2 (2*2^(i-1)) + 1))"
  | 
| 
 | 
   165  | 
    apply(rule sum_mono)
  | 
| 
 | 
   166  | 
    using zero_le_power[of "2::real"] by (simp add: add_pos_nonneg)
  | 
| 
 | 
   167  | 
  also have "\<dots> = (\<Sum>i = 1..k. 2^(k-i) * (2 * log 2 (2^(1+(i-1))) + 1))"
  | 
| 
 | 
   168  | 
    by (simp del: Suc_pred)
  | 
| 
 | 
   169  | 
  also have "\<dots> = (\<Sum>i = 1..k. 2^(k-i) * (2 * log 2 (2^i) + 1))"
  | 
| 
 | 
   170  | 
    by (simp)
  | 
| 
 | 
   171  | 
  also have "\<dots> = (\<Sum>i = 1..k. 2^(k-i) * ((2::real)*i+1))"
  | 
| 
 | 
   172  | 
    by (simp add:log_nat_power algebra_simps)
  | 
| 
 | 
   173  | 
  also have "\<dots> = 5*(2::real)^k - (2::real)*k - 5"
  | 
| 
 | 
   174  | 
    using summation by (simp)
  | 
| 
 | 
   175  | 
  also have "\<dots> \<le> 5*(2::real)^k"
  | 
| 
 | 
   176  | 
    by linarith
  | 
| 
 | 
   177  | 
  finally show ?thesis
  | 
| 
 | 
   178  | 
    using assms of_nat_le_iff by fastforce
  | 
| 
 | 
   179  | 
qed
  | 
| 
 | 
   180  | 
  | 
| 
 | 
   181  | 
end  |