Theory Splay_Heap

section "Splay Heap"

theory Splay_Heap
imports
  "HOL-Library.Tree_Multiset"
begin

text‹Splay heaps were invented by Okasaki~cite"Okasaki". They represent
priority queues by splay trees, not by heaps!›

fun get_min :: "('a::linorder) tree  'a" where
"get_min(Node l m r) = (if l = Leaf then m else get_min l)"

fun partition :: "'a::linorder  'a tree  'a tree * 'a tree" where
"partition p Leaf = (Leaf,Leaf)" |
"partition p (Node al a ar) =
  (if a  p then
     case ar of
       Leaf  (Node al a ar, Leaf) |
       Node bl b br 
         if b  p
         then let (pl,pr) = partition p br in (Node (Node al a bl) b pl, pr)
         else let (pl,pr) = partition p bl in (Node al a pl, Node pr b br)
   else case al of
       Leaf  (Leaf, Node al a ar) |
       Node bl b br 
         if b  p
         then let (pl,pr) = partition p br in (Node bl b pl, Node pr a ar)
         else let (pl,pr) = partition p bl in (pl, Node pr b (Node br a ar)))" 

definition insert :: "'a::linorder  'a tree  'a tree" where
"insert x h = (let (l,r) = partition x h in Node l x r)"

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


lemma get_min_in:
  "h  Leaf  get_min h  set_tree h"
by(induction h) auto

lemma get_min_min:
  " bst_wrt (≤) h; h  Leaf   x  set_tree h. get_min h  x"
proof(induction h)
  case (Node l x r) thus ?case using get_min_in[of l] get_min_in[of r]
    by auto (blast intro: order_trans)
qed simp

lemma size_partition: "partition p t = (l',r')  size t = size l' + size r'"
by (induction p t arbitrary: l' r' rule: partition.induct)
   (auto split: if_splits tree.splits prod.splits)

lemma mset_partition: " bst_wrt (≤) t; partition p t = (l',r') 
  mset_tree t = mset_tree l' + mset_tree r'"
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 auto
    next
      case (Node rl b rr)
      show ?thesis
      proof cases
        assume "b  p"
        thus ?thesis using Node a  p "2.prems" "2.IH"(1)[OF _ Node]
          by (auto simp: ac_simps split: prod.splits)
      next
        assume "¬ b  p"
        thus ?thesis using Node a  p "2.prems" "2.IH"(2)[OF _ Node]
          by (auto simp: ac_simps split: prod.splits)
      qed
    qed
  next
    assume "¬ a  p"
    show ?thesis
    proof (cases l)
      case Leaf thus ?thesis using ¬ a  p "2.prems" by auto
    next
      case (Node ll b lr)
      show ?thesis
      proof cases
        assume "b  p"
        thus ?thesis using Node ¬ a  p "2.prems" "2.IH"(3)[OF _ Node]
          by (auto simp: ac_simps split: prod.splits)
      next
        assume "¬ b  p"
        thus ?thesis using Node ¬ a  p "2.prems" "2.IH"(4)[OF _ Node]
          by (auto simp: ac_simps split: prod.splits)
      qed
    qed
  qed
qed

lemma set_partition: " bst_wrt (≤) t; partition p t = (l',r') 
  set_tree t = set_tree l'  set_tree r'"
by (metis mset_partition set_mset_tree set_mset_union)

lemma bst_partition:
  "partition p t = (l',r')  bst_wrt (≤) t  bst_wrt (≤) (Node l' p r')"
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 (Node rl b rr)
      show ?thesis
      proof cases
        assume "b  p"
        thus ?thesis
          using Node a  p "2.prems" "2.IH"(1)[OF _ Node] set_partition[of rr]
          by (fastforce split: prod.splits)
      next
        assume "¬ b  p"
        thus ?thesis
          using Node a  p "2.prems" "2.IH"(2)[OF _ Node] set_partition[of rl]
          by (fastforce split: prod.splits)
      qed
    qed
  next
    assume "¬ a  p"
    show ?thesis
    proof (cases l)
      case Leaf thus ?thesis using ¬ a  p "2.prems" by fastforce
    next
      case (Node ll b lr)
      show ?thesis
      proof cases
        assume "b  p"
        thus ?thesis
          using Node ¬ a  p "2.prems" "2.IH"(3)[OF _ Node] set_partition[of lr]
          by (fastforce split: prod.splits)
      next
        assume "¬ b  p"
        thus ?thesis
          using Node ¬ a  p "2.prems" "2.IH"(4)[OF _ Node] set_partition[of ll]
          by (fastforce split: prod.splits)
      qed
    qed
  qed
qed

lemma size_del_min[simp]: "size(del_min t) = size t - 1"
by(induction t rule: del_min.induct) (auto simp: neq_Leaf_iff)

lemma mset_del_min: "mset_tree (del_min h) = mset_tree h - {# get_min h #}"
proof(induction h rule: del_min.induct)
  case (3 ll)
  show ?case
  proof cases
    assume "ll = Leaf" thus ?thesis using 3 by (simp add: ac_simps)
  next
    assume "ll  Leaf"
    hence "get_min ll ∈# mset_tree ll"
      by (simp add: get_min_in)
    then obtain A where "mset_tree ll = add_mset (get_min ll) A"
      by (blast dest: multi_member_split)
    then show ?thesis using 3 by auto
  qed
qed auto

lemma bst_del_min: "bst_wrt (≤) t  bst_wrt (≤) (del_min t)"
apply(induction t rule: del_min.induct)
  apply simp
 apply simp
apply auto
by (metis Multiset.diff_subset_eq_self subsetD set_mset_mono set_mset_tree mset_del_min)

end