Theory Splay_Heap_Analysis

section "Splay Heap"

theory Splay_Heap_Analysis
imports
  Splay_Tree.Splay_Heap
  Amortized_Framework
  Priority_Queue_ops
  Lemmas_log
begin

text ‹Timing functions must be kept in sync with the corresponding functions
on splay heaps.›

fun T_part :: "'a::linorder  'a tree  nat" where
"T_part p Leaf = 1" |
"T_part p (Node l a r) =
  (if a  p then
     case r of
       Leaf  1 |
       Node rl b rr  if b  p then T_part p rr + 1 else T_part p rl + 1
   else case l of
       Leaf  1 |
       Node ll b lr  if b  p then T_part p lr + 1 else T_part p ll + 1)" 

definition T_in :: "'a::linorder  'a tree  nat" where
"T_in x h = T_part x h"

fun T_dm :: "'a::linorder tree  nat" where
"T_dm Leaf = 1" |
"T_dm (Node Leaf _ r) = 1" |
"T_dm (Node (Node ll a lr) b r) = (if ll=Leaf then 1 else T_dm ll + 1)"

abbreviation "φ t == log 2 (size1 t)"

fun Φ :: "'a tree  real" where
"Φ Leaf = 0" |
"Φ (Node l a r) = Φ l + Φ r + φ (Node l a r)"

lemma amor_del_min: "T_dm t + Φ (del_min t) - Φ t  2 * φ t + 1"
proof(induction t rule: T_dm.induct)
  case (3 ll a lr b r)
  let ?t = "Node (Node ll a lr) b r"
  show ?case
  proof cases
    assume [simp]: "ll = Leaf"
    have 1: "log 2 (real (size1 lr) + real (size1 r))
         3 * log 2 (1 + (real (size1 lr) + real (size1 r)))" (is "?l  3 * ?r")
    proof -
      have "?l  ?r" by(simp add: size1_size)
      also have "  3 * ?r" by(simp)
      finally show ?thesis .
    qed
    have 2: "log 2 (1 + real (size1 lr))  0" by simp
    thus ?case apply simp using 1 2 by linarith
  next
    assume ll[simp]: "¬ ll = Leaf"
    let ?l' = "del_min ll"
    let ?s = "Node ll a lr"  let ?t = "Node ?s b r"
    let ?s' = "Node lr b r"  let ?t' = "Node ?l' a ?s'"
    have 0: "φ ?t'  φ ?t" by(simp add: size1_size)
    have 1: "φ ll < φ ?s" by(simp add: size1_size)
    have 2: "log 2 (size1 ll + size1 ?s')  log 2 (size1 ?t)" by(simp add: size1_size)
    have "T_dm ?t + Φ (del_min ?t) - Φ ?t
        = 1 + T_dm ll + Φ (del_min ?t) - Φ ?t" by simp
    also have "  2 + 2 * φ ll + Φ ll - Φ ?l'  + Φ (del_min ?t) - Φ ?t"
      using 3 ll by linarith
    also have " = 2 + 2 * φ ll + φ ?t' + φ ?s' - φ ?t - φ ?s" by(simp)
    also have "  2 + φ ll + φ ?s'" using 0 1 by linarith
    also have " < 2 * φ ?t + 1" using 2 ld_ld_1_less[of "size1 ll" "size1 ?s'"]
      by (simp add: size1_size)
    finally show ?case by simp
  qed
qed auto

lemma zig_zig:
fixes s u r r1' r2' T a b
defines "t == Node s a (Node u b r)" and "t' == Node (Node s a u) b r1'"
assumes "size r1'  size r"
    "T_part p r + Φ r1' + Φ r2' - Φ r  2 * φ r + 1"
shows "T_part p r + 1 + Φ t' + Φ r2' - Φ t  2 * φ t + 1"
proof -
  have 1: "φ r  φ (Node u b r)" by (simp add: size1_size)
  have 2: "log 2 (real (size1 s + size1 u + size1 r1'))  φ t"
    using assms(3) by (simp add: t_def size1_size)
  from ld_ld_1_less[of "size1 s + size1 u" "size1 r"] 
  have "1 + φ r + log 2 (size1 s + size1 u)  2 * log 2 (size1 s + size1 u + size1 r)"
    by(simp add: size1_size)
  thus ?thesis using assms 1 2 by (simp add: algebra_simps)
qed

lemma zig_zag:
fixes s u r r1' r2' a b
defines "t  Node s a (Node r b u)" and "t1' == Node s a r1'" and "t2'  Node u b r2'"
assumes "size r = size r1' + size r2'"
    "T_part p r + Φ r1' + Φ r2' - Φ r  2 * φ r + 1"
shows "T_part p r + 1 + Φ t1' + Φ t2' - Φ t  2 * φ t + 1"
proof -
  have 1: "φ r  φ (Node u b r)" by (simp add: size1_size)
  have 2: "φ r  φ t" by (simp add: t_def size1_size)
  from ld_ld_less2[of "size1 s + size1 r1'" "size1 u + size1 r2'"] 
  have "1 + log 2 (size1 s + size1 r1') + log 2 (size1 u + size1 r2')  2 * φ t"
    by(simp add: assms(4) size1_size t_def ac_simps)
  thus ?thesis using assms 1 2 by (simp add: algebra_simps)
qed

lemma amor_partition: "bst_wrt (≤) t  partition p t = (l',r')
   T_part p t + Φ l' + Φ r' - Φ t  2 * log 2 (size1 t) + 1"
proof(induction p t arbitrary: l' r' rule: partition.induct)
  case 1 thus ?case by simp
next
  case (2 p l a r)
  show ?case
  proof cases
    assume "a  p"
    show ?thesis
    proof (cases r)
      case Leaf thus ?thesis using a  p "2.prems" by fastforce
    next
      case [simp]: (Node rl b rr)
      let ?t = "Node l a r"
      show ?thesis
      proof cases
        assume "b  p"
        with a  p "2.prems" obtain rrl
          where 0: "partition p rr = (rrl, r')" "l' = Node (Node l a rl) b rrl"
          by (auto split: tree.splits prod.splits)
        have "size rrl  size rr"
          using size_partition[OF 0(1)] by (simp add: size1_size)
        with 0 a  p b  p "2.prems"(1) "2.IH"(1)[OF _ Node , of rrl r']
          zig_zig[where s=l and u=rl and r=rr and r1'=rrl and r2'=r' and p=p, of a b]
        show ?thesis by (simp add: algebra_simps)
      next
        assume "¬ b  p"
        with a  p "2.prems" obtain rll rlr 
          where 0: "partition p rl = (rll, rlr)" "l' = Node l a rll" "r' = Node rlr b rr"
          by (auto split: tree.splits prod.splits)
        from 0 a  p ¬ b  p "2.prems"(1) "2.IH"(2)[OF _ Node, of rll rlr]
          size_partition[OF 0(1)]
          zig_zag[where s=l and u=rr and r=rl and r1'=rll and r2'=rlr and p=p, of a b]
        show ?thesis by (simp add: algebra_simps)
      qed
    qed
  next
    assume "¬ a  p"
    show ?thesis
    proof (cases l)
      case Leaf thus ?thesis using ¬ a  p "2.prems" by fastforce
    next
      case [simp]: (Node ll b lr)
      let ?t = "Node l a r"
      show ?thesis
      proof cases
        assume "b  p"
        with ¬ a  p "2.prems" obtain lrl lrr 
          where 0: "partition p lr = (lrl, lrr)" "l' = Node ll b lrl" "r' = Node lrr a r"
          by (auto split: tree.splits prod.splits)
        from 0 ¬ a  p b  p "2.prems"(1) "2.IH"(3)[OF _ Node, of lrl lrr]
          size_partition[OF 0(1)]
          zig_zag[where s=r and u=ll and r=lr and r1'=lrr and r2'=lrl and p=p, of a b]
        show ?thesis by (auto simp: algebra_simps)
      next
        assume "¬ b  p"
        with ¬ a  p "2.prems" obtain llr
          where 0: "partition p ll = (l',llr)" "r' = Node llr b (Node lr a r)"
          by (auto split: tree.splits prod.splits)
        have "size llr  size ll"
          using size_partition[OF 0(1)] by (simp add: size1_size)
        with 0 ¬ a  p ¬ b  p "2.prems"(1) "2.IH"(4)[OF _ Node, of l' llr]
          zig_zig[where s=r and u=lr and r=ll and r1'=llr and r2'=l' and p=p, of a b]
        show ?thesis by (auto simp: algebra_simps)
      qed
    qed
  qed
qed

fun exec :: "'a::linorder op  'a tree list  'a tree" where
"exec Empty [] = Leaf" |
"exec (Insert a) [t] = insert a t" |
"exec Del_min [t] = del_min t"

fun cost :: "'a::linorder op  'a tree list  nat" where
"cost Empty [] = 1" |
"cost (Insert a) [t] = T_in a t" |
"cost Del_min [t] = T_dm t"

fun U where
"U Empty [] = 1" |
"U (Insert _) [t] = 3 * log 2 (size1 t + 1) + 1" |
"U Del_min [t] = 2 * φ t + 1"

interpretation Amortized
where arity = arity and exec = exec and inv = "bst_wrt (≤)"
and cost = cost and Φ = Φ and U = U
proof (standard, goal_cases)
  case (1 _ f) thus ?case
    by(cases f)
       (auto simp: insert_def bst_del_min dest!: bst_partition split: prod.splits)
next
  case (2 h) thus ?case by(induction h) (auto simp: size1_size)
next
  case (3 s f)
  show ?case
  proof (cases f)
    case Empty with 3 show ?thesis by(auto)
  next
    case Del_min with 3 show ?thesis by(auto simp: amor_del_min)
  next
    case [simp]: (Insert x)
    then obtain t where [simp]: "s = [t]" "bst_wrt (≤) t" using 3 by auto
    { fix l r assume 1: "partition x t = (l,r)"
      have "log 2 (1 + size t) < log 2 (2 + size t)" by simp
      with 1 amor_partition[OF bst_wrt (≤) t 1] size_partition[OF 1] have ?thesis
        by(simp add: T_in_def insert_def algebra_simps size1_size
             del: log_less_cancel_iff) }
    thus ?thesis by(simp add: insert_def split: prod.split)
  qed
qed

end