Theory Quicksort

(*
    Author:      Norbert Schirmer
    Maintainer:  Norbert Schirmer, norbert.schirmer at web de

Copyright (C) 2006-2008 Norbert Schirmer
*)

section "Example: Quicksort on Heap Lists"

theory Quicksort
imports "../Vcg" "../HeapList" "HOL-Library.Multiset"
begin

record globals_heap =
  next_' :: "ref  ref"
  cont_' :: "ref  nat"

record 'g vars = "'g state" +
  p_'    :: "ref"
  q_'    :: "ref"
  le_'   :: "ref"
  gt_'   :: "ref"
  hd_'   :: "ref"
  tl_'   :: "ref"

procedures
  append(p,q|p) =
    "IF ´p=Null THEN ´p :== ´q ELSE ´p→´next :== CALL append(´p→´next,´q) FI"

  append_spec:
   "∀σ Ps Qs.
     Γ⊢ ⦃σ. List ´p ´next Ps ∧  List ´q ´next Qs ∧ set Ps ∩ set Qs = {}⦄
           ´p :== PROC append(´p,´q)
         ⦃List ´p ´next (Ps@Qs) ∧ (∀x. x∉set Ps ⟶ ´next x = σnext x)⦄"

  append_modifies:
   "∀σ. Γ⊢ {σ} ´p :== PROC append(´p,´q){t. t may_only_modify_globals σ in [next]}"


lemma (in append_impl) append_modifies:
  shows
   "σ. Γ {σ} ´p :== PROC append(´p,´q){t. t may_only_modify_globals σ in [next]}"
  apply (hoare_rule HoarePartial.ProcRec1)
  apply (vcg spec=modifies)
  done


lemma (in append_impl) append_spec:
  shows "σ Ps Qs. Γ
            σ. List ´p ´next Ps   List ´q ´next Qs  set Ps  set Qs = {}
                ´p :== PROC append(´p,´q)
            List ´p ´next (Ps@Qs)  (x. xset Ps  ´next x = σnext x)"
  apply (hoare_rule HoarePartial.ProcRec1)
  apply vcg
  apply fastforce
  done

primrec sorted:: "('a  'a  bool)  'a list   bool"
where
"sorted le [] = True" |
"sorted le (x#xs) = ((yset xs. le x y)  sorted le xs)"

lemma sorted_append[simp]:
 "sorted le (xs@ys) = (sorted le xs  sorted le ys 
                       (x  set xs. y  set ys. le x y))"
by (induct xs, auto)

procedures quickSort(p|p) =
 "IF ´p=Null THEN SKIP
  ELSE ´tl :== ´p→´next;;
       ´le :== Null;;
       ´gt :== Null;;
       WHILE ´tl≠Null DO
         ´hd :== ´tl;;
         ´tl :== ´tl→´next;;
         IF ´hd→´cont ≤ ´p→´cont
         THEN ´hd→´next :== ´le;;
              ´le :== ´hd
         ELSE ´hd→´next :== ´gt;;
              ´gt :== ´hd
         FI
       OD;;
       ´le :== CALL quickSort(´le);;
       ´gt :== CALL quickSort(´gt);;
       ´p→´next :== ´gt;;
       ´le :== CALL append(´le,´p);;
       ´p :== ´le
  FI"

  quickSort_spec:
  "∀σ Ps. Γ⊢ ⦃σ. List ´p ´next Ps⦄ ´p :== PROC quickSort(´p)
       ⦃(∃sortedPs. List ´p ´next sortedPs ∧
        sorted (≤) (map σcont sortedPs) ∧
        mset Ps = mset sortedPs) ∧
        (∀x. x∉set Ps ⟶ ´next x = σnext x)⦄"

  quickSort_modifies:
  "∀σ. Γ⊢ {σ} ´p :== PROC quickSort(´p) {t. t may_only_modify_globals σ in [next]}"


lemma (in quickSort_impl) quickSort_modifies:
  shows
  "σ. Γ {σ} ´p :== PROC quickSort(´p) {t. t may_only_modify_globals σ in [next]}"
apply (hoare_rule HoarePartial.ProcRec1)
apply (vcg spec=modifies)
done

lemma (in quickSort_impl) quickSort_spec:
shows
  "σ Ps. Γ σ. List ´p ´next Ps
                  ´p :== PROC quickSort(´p)
                (sortedPs. List ´p ´next sortedPs 
                 sorted (≤) (map σcont sortedPs) 
                 mset Ps = mset sortedPs) 
                 (x. xset Ps  ´next x = σnext x)"
apply (hoare_rule HoarePartial.ProcRec1)
apply (hoare_rule anno =
 "IF ´p=Null THEN SKIP
  ELSE ´tl :== ´p´next;;
       ´le :== Null;;
       ´gt :== Null;;
       WHILE ´tlNull
       INV  (les grs tls. List ´le ´next les  List ´gt ´next grs 
               List ´tl ´next tls 
               mset Ps = mset (´p#tls@les@grs) 
               distinct(´p#tls@les@grs) 
               (xset les. x´cont  ´p´cont) 
               (xset grs. ´p´cont < x´cont)) 
               ´p=σp 
               ´cont=σcont 
               List σp σnext Ps 
               (x. xset Ps  ´next x = σnext x)
       DO
         ´hd :== ´tl;;
         ´tl :== ´tl´next;;
         IF ´hd´cont  ´p´cont
         THEN ´hd´next :== ´le;;
              ´le :== ´hd
         ELSE ´hd´next :== ´gt;;
              ´gt :== ´hd
         FI
       OD;;
       ´le :== CALL quickSort(´le);;
       ´gt :== CALL quickSort(´gt);;
       ´p´next :== ´gt;;
       ´le :== CALL append(´le,´p);;
       ´p :== ´le
  FI" in HoarePartial.annotateI)
  apply vcg
    apply fastforce
   apply clarsimp
   apply (rule conjI)
    apply clarify
    apply (rule conjI)
     apply (rule_tac x="tl#les" in exI)
     apply simp
     apply (rule_tac x="grs" in exI)
     apply simp
     apply (rule_tac x="ps" in exI)
     apply simp
    apply (metis insertCI set_mset_add_mset_insert set_mset_mset)
   apply clarify
   apply (rule conjI)
    apply (rule_tac x="les" in exI)
    apply simp
    apply (rule_tac x="tl#grs" in exI)
    apply simp
    apply (rule_tac x="ps" in exI)
    apply simp
   apply (metis insertCI set_mset_add_mset_insert set_mset_mset)
  apply clarsimp
  apply (rule_tac ?x=grs in exI)
  apply (rule conjI)
  apply (erule heap_eq_ListI1)
   apply clarify
   apply (erule_tac x=x in allE) back
   apply blast
  apply clarsimp
  apply (rule_tac x="sortedPs" in exI)
  apply (rule conjI)
   apply (erule heap_eq_ListI1)
   apply (clarsimp)
   apply (erule_tac x=x in allE) back back
   apply (metis IntI empty_iff set_mset_mset)
  apply (rule_tac x="p#sortedPsa" in exI)
  apply (rule conjI)
   apply (metis List_cons List_updateI Null_notin_List fun_upd_same insert_iff set_mset_add_mset_insert set_mset_mset)
  apply (rule conjI)
   apply (metis disjoint_iff mset_eq_setD set_ConsD)
  apply clarsimp
  apply (rule conjI)
   apply (metis less_or_eq_imp_le mset_eq_setD)
  apply (rule conjI)
   apply (metis leD less_le_trans mset_eq_setD nat_le_linear)
  apply clarsimp
  apply (erule_tac x=x in allE)+
  apply (metis Un_iff insert_iff list.set(2) mset.simps(2) mset_append set_append set_mset_mset)
  done

end