Theory Pairing_Heap_Tree_Analysis

(* Author: Hauke Brinkop and Tobias Nipkow *)

section ‹Pairing Heaps›

subsection ‹Binary Tree Representation›

theory Pairing_Heap_Tree_Analysis
imports  
  "HOL-Data_Structures.Define_Time_Function"
  Pairing_Heap.Pairing_Heap_Tree
  Amortized_Framework
  Priority_Queue_ops_merge
  Lemmas_log
begin

text
‹Verification of logarithmic bounds on the amortized complexity of
pairing heaps cite"FredmanSST86" and "Brinkop".›


subsubsection ‹Analysis›

fun len :: "'a tree  nat" where 
  "len Leaf = 0"
| "len (Node _ _ r) = 1 + len r"

fun Φ :: "'a tree  real" where
  "Φ Leaf = 0"
| "Φ (Node l x r) = log 2 (size (Node l x r)) + Φ l + Φ r"

lemma link_size[simp]: "size (link hp) = size hp" 
  by (cases hp rule: link.cases) simp_all

lemma size_pass1: "size (pass1 hp) = size hp" 
  by (induct hp rule: pass1.induct) simp_all

lemma size_pass2: "size (pass2 hp) = size hp" 
  by (induct hp rule: pass2.induct) simp_all

lemma size_merge: 
  "is_root h1  is_root h2  size (merge h1 h2) = size h1 + size h2"
  by (simp split: tree.splits)

lemma ΔΦ_insert: "is_root hp  Φ (insert x hp) - Φ hp  log 2  (size hp + 1)"
  by (simp split: tree.splits)

lemma ΔΦ_merge:
  assumes "h1 = Node hs1 x1 Leaf" "h2 = Node hs2 x2 Leaf" 
  shows "Φ (merge h1 h2) - Φ h1 - Φ h2  log 2 (size h1 + size h2) + 1" 
proof -
  let ?hs = "Node hs1 x1 (Node hs2 x2 Leaf)"
  have "Φ (merge h1 h2) = Φ (link ?hs)" using assms by simp
  also have " = Φ hs1 + Φ hs2 + log 2 (size hs1 + size hs2 + 1) + log 2 (size hs1 + size hs2 + 2)"
    by (simp add: algebra_simps)
  also have " = Φ hs1 + Φ hs2 + log 2 (size hs1 + size hs2 + 1) + log 2 (size h1 + size h2)"
     using assms by simp
  finally have "Φ (merge h1 h2) = " .
  have "Φ (merge h1 h2) - Φ h1 - Φ h2 =
   log 2 (size hs1 + size hs2 + 1) + log 2 (size h1 + size h2)
   - log 2 (size hs1 + 1) - log 2 (size hs2 + 1)"
     using assms by (simp add: algebra_simps)
  also have "  log 2 (size h1 + size h2) + 1"
    using ld_le_2ld[of "size hs1" "size hs2"] assms by (simp add: algebra_simps)
  finally show ?thesis .
qed

fun ub_pass1 :: "'a tree  real" where
  "ub_pass1 (Node _ _ Leaf) = 0"
| "ub_pass1 (Node hs1 _ (Node hs2 _ Leaf)) = 2*log 2 (size hs1 + size hs2 + 2)" 
| "ub_pass1 (Node hs1 _ (Node hs2 _ hs)) = 2*log 2 (size hs1 + size hs2 + size hs + 2) 
    - 2*log 2 (size hs) - 2 + ub_pass1 hs"

lemma ΔΦ_pass1_ub_pass1: "hs  Leaf  Φ (pass1 hs) - Φ hs   ub_pass1 hs"
proof (induction hs rule: ub_pass1.induct)
  case (2 lx x ly y)
  have "log 2  (size lx + size ly + 1) - log 2  (size ly + 1) 
     log 2 (size lx + size ly + 1)" by simp
  also have "  log 2 (size lx + size ly + 2)" by simp
  also have "  2*" by simp
  finally show ?case by (simp add: algebra_simps)
next
  case (3 lx x ly y lz z rz)
  let ?ry = "Node lz z rz"
  let ?rx = "Node ly y ?ry"
  let ?h = "Node lx x ?rx"
  let ?t ="log 2 (size lx + size ly + 1) - log 2 (size ly + size ?ry + 1)"
  have "Φ (pass1 ?h) - Φ ?h  ?t + ub_pass1 ?ry" 
    using "3.IH" by (simp add: size_pass1 algebra_simps)
  moreover have "log 2 (size lx + size ly + 1) + 2 * log 2 (size ?ry) + 2
     2 * log 2 (size ?h) + log 2 (size ly + size ?ry + 1)" (is "?l  ?r")
  proof -
    have "?l  2 * log 2 (size lx + size ly + size ?ry + 1) + log 2 (size ?ry)"
      using ld_sum_inequality [of "size lx + size ly + 1" "size ?ry"] by simp
    also have "  2 * log 2 (size lx + size ly + size ?ry + 2) + log 2 (size ?ry)"
      by simp
    also have "  ?r" by simp
    finally show ?thesis .
  qed
  ultimately show ?case by simp
qed simp_all

lemma ΔΦ_pass1: assumes "hs  Leaf"
  shows "Φ (pass1 hs) - Φ hs  2*log 2 (size hs) - len hs + 2"
proof -
  from assms have "ub_pass1 hs  2*log 2 (size hs) - len hs + 2" 
    by (induct hs rule: ub_pass1.induct) (simp_all add: algebra_simps)
  thus ?thesis using ΔΦ_pass1_ub_pass1 [OF assms] order_trans by blast
qed

lemma ΔΦ_pass2: "hs  Leaf  Φ (pass2 hs) - Φ hs  log 2 (size hs)"
proof (induction hs)
  case (Node lx x rx)
  thus ?case 
  proof (cases rx)
    case 1: (Node ly y ry)
    let ?h = "Node lx x rx"
    obtain la a where 2: "pass2 rx = Node la a Leaf" 
      using pass2_struct 1 by force
    hence 3: "size rx = size " using size_pass2 by metis
    have link: "Φ(link(Node lx x (pass2 rx))) - Φ lx - Φ (pass2 rx) =
          log 2 (size lx + size rx + 1) + log 2 (size lx + size rx) - log 2 (size rx)"
      using 2 3 by (simp add: algebra_simps) 
    have "Φ (pass2 ?h) - Φ ?h =
        Φ (link (Node lx x (pass2 rx))) - Φ lx - Φ rx - log 2 (size lx + size rx + 1)"
      by (simp)
    also have " = Φ (pass2 rx) - Φ rx + log 2 (size lx + size rx) - log 2 (size rx)"
      using link by linarith
    also have "  log 2 (size lx + size rx)"
      using Node.IH 1 by simp
    also have "  log 2 (size ?h)" using 1 by simp
    finally show ?thesis .
  qed simp
qed simp

lemma ΔΦ_del_min: assumes "hs  Leaf"
shows "Φ (del_min (Node hs x Leaf)) - Φ (Node hs x Leaf) 
   3*log 2 (size hs) - len hs + 2"
proof -
  let ?h = "Node hs x Leaf"
  let ?ΔΦ1 = "Φ hs - Φ ?h" 
  let ?ΔΦ2 = "Φ(pass2(pass1 hs)) - Φ hs"
  let ?ΔΦ = "Φ (del_min ?h) - Φ ?h"
  have "Φ(pass2(pass1 hs)) - Φ (pass1 hs)  log 2  (size hs)" 
    using ΔΦ_pass2 [of "pass1 hs"] assms by(metis eq_size_0 size_pass1)
  moreover have "Φ (pass1 hs) - Φ hs   2* - len hs + 2" 
    by(rule ΔΦ_pass1[OF assms])
  moreover have "?ΔΦ  ?ΔΦ2" by simp
  ultimately show ?thesis using assms by linarith
qed

lemma pass1_len: "len (pass1 h)  len h"
by (induct h rule: pass1.induct) simp_all


subsubsection ‹Putting it all together (boiler plate)›

fun exec :: "'a :: linorder op  'a tree list  'a tree" where
"exec Empty [] = Leaf" | 
"exec Del_min [h] = del_min h" |
"exec (Insert x) [h] = insert x h" |
"exec Merge [h1,h2] = merge h1 h2"

time_fun link

lemma T_link_0[simp]: "T_link h = 0"
by (cases h rule: T_link.cases) auto

time_fun pass1

time_fun pass2

time_fun del_min

time_fun merge

lemma T_merge_0[simp]: "T_merge h1 h2 = 0"
by (cases "(h1,h2)" rule: T_merge.cases) auto

time_fun insert

fun cost :: "'a :: linorder op  'a tree list  nat" where
  "cost Empty [] = 0"
| "cost Del_min [hp] = T_del_min hp"
| "cost (Insert a) [hp] = T_insert a hp"
| "cost Merge [h1,h2] = T_merge h1 h2"

fun U :: "'a :: linorder op  'a tree list  real" where
  "U Empty [] = 0"
| "U (Insert a) [h] = log 2 (size h + 1)"
| "U Del_min [h] = 3*log 2 (size h + 1) + 4"
| "U Merge [h1,h2] = log 2 (size h1 + size h2 + 1) + 1"

interpretation Amortized
where arity = arity and exec = exec and cost = cost and inv = is_root 
and Φ = Φ and U = U
proof (standard, goal_cases)
  case (1 _ f) thus ?case using is_root_insert is_root_del_min is_root_merge
    by (cases f) (auto simp: numeral_eq_Suc)
next
  case (2 s) show ?case by (induct s) simp_all
next
  case (3 ss f) show ?case 
  proof (cases f)
    case Empty with 3 show ?thesis by(auto)
  next
    case (Insert x)
    then obtain h where "ss = [h]" "is_root h" using 3 by auto
    thus ?thesis using Insert ΔΦ_insert 3 by auto
  next
    case [simp]: (Del_min)
    then obtain h where [simp]: "ss = [h]" using 3 by auto
    show ?thesis
    proof (cases h)
      case [simp]: (Node lx x rx)
      have "T_pass2 (pass1 lx) + T_pass1 lx  len lx + 2"
        by (induct lx rule: pass1.induct) simp_all
      hence "cost f ss  " by simp 
      moreover have "Φ (del_min h) - Φ h  3*log 2 (size h + 1) - len lx + 2"
      proof (cases lx)
        case [simp]: (Node ly y ry) 
        have "Φ (del_min h) - Φ h  3*log 2 (size lx) - len lx + 2"
          using  ΔΦ_del_min[of "lx" "x"] 3 by simp
        also have "  3*log 2 (size h + 1) - len lx + 2" by fastforce
        finally show ?thesis by blast
      qed (insert 3, simp)
      ultimately show ?thesis by auto
    qed simp
  next
    case [simp]: Merge
    then obtain h1 h2 where [simp]: "ss = [h1,h2]" and 1: "is_root h1" "is_root h2"
      using 3 by (auto simp: numeral_eq_Suc)
    show ?thesis
    proof (cases h1)
      case Leaf thus ?thesis by (cases h2) auto
    next
      case h1: Node
      show ?thesis
      proof (cases h2)
        case Leaf thus ?thesis using h1 by simp
      next
        case h2: Node
        have "Φ (merge h1 h2) - Φ h1 - Φ h2  log 2 (real (size h1 + size h2)) + 1"
          apply(rule ΔΦ_merge) using h1 h2 1 by auto
        also have "  log 2 (size h1 + size h2 + 1) + 1" by (simp add: h1)
        finally show ?thesis by(simp add: algebra_simps)
      qed
    qed
  qed
qed

end