src/HOL/Imperative_HOL/ex/Imperative_Quicksort.thy
author haftmann
Fri Jul 09 16:58:44 2010 +0200 (2010-07-09 ago)
changeset 37758 bf86a65403a8
parent 37750 82e0fe8b07eb
child 37771 1bec64044b5e
permissions -rw-r--r--
pervasive success combinator
bulwahn@36098
     1
(*  Title:      HOL/Imperative_HOL/ex/Imperative_Quicksort.thy
bulwahn@36098
     2
    Author:     Lukas Bulwahn, TU Muenchen
bulwahn@36098
     3
*)
bulwahn@36098
     4
bulwahn@36098
     5
header {* An imperative implementation of Quicksort on arrays *}
haftmann@30689
     6
haftmann@30689
     7
theory Imperative_Quicksort
haftmann@29399
     8
imports "~~/src/HOL/Imperative_HOL/Imperative_HOL" Subarray Multiset Efficient_Nat
bulwahn@27656
     9
begin
bulwahn@27656
    10
bulwahn@27656
    11
text {* We prove QuickSort correct in the Relational Calculus. *}
bulwahn@27656
    12
bulwahn@27656
    13
definition swap :: "nat array \<Rightarrow> nat \<Rightarrow> nat \<Rightarrow> unit Heap"
bulwahn@27656
    14
where
bulwahn@27656
    15
  "swap arr i j = (
bulwahn@27656
    16
     do
bulwahn@27656
    17
       x \<leftarrow> nth arr i;
bulwahn@27656
    18
       y \<leftarrow> nth arr j;
bulwahn@27656
    19
       upd i y arr;
bulwahn@27656
    20
       upd j x arr;
bulwahn@27656
    21
       return ()
bulwahn@27656
    22
     done)"
bulwahn@27656
    23
bulwahn@27656
    24
lemma swap_permutes:
bulwahn@27656
    25
  assumes "crel (swap a i j) h h' rs"
bulwahn@27656
    26
  shows "multiset_of (get_array a h') 
bulwahn@27656
    27
  = multiset_of (get_array a h)"
bulwahn@27656
    28
  using assms
haftmann@28145
    29
  unfolding swap_def
haftmann@37719
    30
  by (auto simp add: Array.length_def multiset_of_swap dest: sym [of _ "h'"] elim!: crelE crel_nth crel_return crel_upd)
bulwahn@27656
    31
bulwahn@27656
    32
function part1 :: "nat array \<Rightarrow> nat \<Rightarrow> nat \<Rightarrow> nat \<Rightarrow> nat Heap"
bulwahn@27656
    33
where
bulwahn@27656
    34
  "part1 a left right p = (
bulwahn@27656
    35
     if (right \<le> left) then return right
bulwahn@27656
    36
     else (do
bulwahn@27656
    37
       v \<leftarrow> nth a left;
bulwahn@27656
    38
       (if (v \<le> p) then (part1 a (left + 1) right p)
bulwahn@27656
    39
                    else (do swap a left right;
bulwahn@27656
    40
  part1 a left (right - 1) p done))
bulwahn@27656
    41
     done))"
bulwahn@27656
    42
by pat_completeness auto
bulwahn@27656
    43
bulwahn@27656
    44
termination
bulwahn@27656
    45
by (relation "measure (\<lambda>(_,l,r,_). r - l )") auto
bulwahn@27656
    46
bulwahn@27656
    47
declare part1.simps[simp del]
bulwahn@27656
    48
bulwahn@27656
    49
lemma part_permutes:
bulwahn@27656
    50
  assumes "crel (part1 a l r p) h h' rs"
bulwahn@27656
    51
  shows "multiset_of (get_array a h') 
bulwahn@27656
    52
  = multiset_of (get_array a h)"
bulwahn@27656
    53
  using assms
bulwahn@27656
    54
proof (induct a l r p arbitrary: h h' rs rule:part1.induct)
bulwahn@27656
    55
  case (1 a l r p h h' rs)
bulwahn@27656
    56
  thus ?case
haftmann@28145
    57
    unfolding part1.simps [of a l r p]
bulwahn@27656
    58
    by (elim crelE crel_if crel_return crel_nth) (auto simp add: swap_permutes)
bulwahn@27656
    59
qed
bulwahn@27656
    60
bulwahn@27656
    61
lemma part_returns_index_in_bounds:
bulwahn@27656
    62
  assumes "crel (part1 a l r p) h h' rs"
bulwahn@27656
    63
  assumes "l \<le> r"
bulwahn@27656
    64
  shows "l \<le> rs \<and> rs \<le> r"
bulwahn@27656
    65
using assms
bulwahn@27656
    66
proof (induct a l r p arbitrary: h h' rs rule:part1.induct)
bulwahn@27656
    67
  case (1 a l r p h h' rs)
bulwahn@27656
    68
  note cr = `crel (part1 a l r p) h h' rs`
bulwahn@27656
    69
  show ?case
bulwahn@27656
    70
  proof (cases "r \<le> l")
bulwahn@27656
    71
    case True (* Terminating case *)
bulwahn@27656
    72
    with cr `l \<le> r` show ?thesis
haftmann@28145
    73
      unfolding part1.simps[of a l r p]
bulwahn@27656
    74
      by (elim crelE crel_if crel_return crel_nth) auto
bulwahn@27656
    75
  next
bulwahn@27656
    76
    case False (* recursive case *)
bulwahn@27656
    77
    note rec_condition = this
bulwahn@27656
    78
    let ?v = "get_array a h ! l"
bulwahn@27656
    79
    show ?thesis
bulwahn@27656
    80
    proof (cases "?v \<le> p")
bulwahn@27656
    81
      case True
bulwahn@27656
    82
      with cr False
bulwahn@27656
    83
      have rec1: "crel (part1 a (l + 1) r p) h h' rs"
haftmann@28145
    84
        unfolding part1.simps[of a l r p]
bulwahn@27656
    85
        by (elim crelE crel_nth crel_if crel_return) auto
bulwahn@27656
    86
      from rec_condition have "l + 1 \<le> r" by arith
bulwahn@27656
    87
      from 1(1)[OF rec_condition True rec1 `l + 1 \<le> r`]
bulwahn@27656
    88
      show ?thesis by simp
bulwahn@27656
    89
    next
bulwahn@27656
    90
      case False
bulwahn@27656
    91
      with rec_condition cr
bulwahn@27656
    92
      obtain h1 where swp: "crel (swap a l r) h h1 ()"
bulwahn@27656
    93
        and rec2: "crel (part1 a l (r - 1) p) h1 h' rs"
haftmann@28145
    94
        unfolding part1.simps[of a l r p]
bulwahn@27656
    95
        by (elim crelE crel_nth crel_if crel_return) auto
bulwahn@27656
    96
      from rec_condition have "l \<le> r - 1" by arith
bulwahn@27656
    97
      from 1(2) [OF rec_condition False rec2 `l \<le> r - 1`] show ?thesis by fastsimp
bulwahn@27656
    98
    qed
bulwahn@27656
    99
  qed
bulwahn@27656
   100
qed
bulwahn@27656
   101
bulwahn@27656
   102
lemma part_length_remains:
bulwahn@27656
   103
  assumes "crel (part1 a l r p) h h' rs"
haftmann@37719
   104
  shows "Array.length a h = Array.length a h'"
bulwahn@27656
   105
using assms
bulwahn@27656
   106
proof (induct a l r p arbitrary: h h' rs rule:part1.induct)
bulwahn@27656
   107
  case (1 a l r p h h' rs)
bulwahn@27656
   108
  note cr = `crel (part1 a l r p) h h' rs`
bulwahn@27656
   109
  
bulwahn@27656
   110
  show ?case
bulwahn@27656
   111
  proof (cases "r \<le> l")
bulwahn@27656
   112
    case True (* Terminating case *)
bulwahn@27656
   113
    with cr show ?thesis
haftmann@28145
   114
      unfolding part1.simps[of a l r p]
bulwahn@27656
   115
      by (elim crelE crel_if crel_return crel_nth) auto
bulwahn@27656
   116
  next
bulwahn@27656
   117
    case False (* recursive case *)
bulwahn@27656
   118
    with cr 1 show ?thesis
haftmann@28145
   119
      unfolding part1.simps [of a l r p] swap_def
bulwahn@27656
   120
      by (auto elim!: crelE crel_if crel_nth crel_return crel_upd) fastsimp
bulwahn@27656
   121
  qed
bulwahn@27656
   122
qed
bulwahn@27656
   123
bulwahn@27656
   124
lemma part_outer_remains:
bulwahn@27656
   125
  assumes "crel (part1 a l r p) h h' rs"
bulwahn@27656
   126
  shows "\<forall>i. i < l \<or> r < i \<longrightarrow> get_array (a::nat array) h ! i = get_array a h' ! i"
bulwahn@27656
   127
  using assms
bulwahn@27656
   128
proof (induct a l r p arbitrary: h h' rs rule:part1.induct)
bulwahn@27656
   129
  case (1 a l r p h h' rs)
bulwahn@27656
   130
  note cr = `crel (part1 a l r p) h h' rs`
bulwahn@27656
   131
  
bulwahn@27656
   132
  show ?case
bulwahn@27656
   133
  proof (cases "r \<le> l")
bulwahn@27656
   134
    case True (* Terminating case *)
bulwahn@27656
   135
    with cr show ?thesis
haftmann@28145
   136
      unfolding part1.simps[of a l r p]
bulwahn@27656
   137
      by (elim crelE crel_if crel_return crel_nth) auto
bulwahn@27656
   138
  next
bulwahn@27656
   139
    case False (* recursive case *)
bulwahn@27656
   140
    note rec_condition = this
bulwahn@27656
   141
    let ?v = "get_array a h ! l"
bulwahn@27656
   142
    show ?thesis
bulwahn@27656
   143
    proof (cases "?v \<le> p")
bulwahn@27656
   144
      case True
bulwahn@27656
   145
      with cr False
bulwahn@27656
   146
      have rec1: "crel (part1 a (l + 1) r p) h h' rs"
haftmann@28145
   147
        unfolding part1.simps[of a l r p]
bulwahn@27656
   148
        by (elim crelE crel_nth crel_if crel_return) auto
bulwahn@27656
   149
      from 1(1)[OF rec_condition True rec1]
bulwahn@27656
   150
      show ?thesis by fastsimp
bulwahn@27656
   151
    next
bulwahn@27656
   152
      case False
bulwahn@27656
   153
      with rec_condition cr
bulwahn@27656
   154
      obtain h1 where swp: "crel (swap a l r) h h1 ()"
bulwahn@27656
   155
        and rec2: "crel (part1 a l (r - 1) p) h1 h' rs"
haftmann@28145
   156
        unfolding part1.simps[of a l r p]
bulwahn@27656
   157
        by (elim crelE crel_nth crel_if crel_return) auto
bulwahn@27656
   158
      from swp rec_condition have
haftmann@28013
   159
        "\<forall>i. i < l \<or> r < i \<longrightarrow> get_array a h ! i = get_array a h1 ! i"
wenzelm@32960
   160
        unfolding swap_def
wenzelm@32960
   161
        by (elim crelE crel_nth crel_upd crel_return) auto
bulwahn@27656
   162
      with 1(2) [OF rec_condition False rec2] show ?thesis by fastsimp
bulwahn@27656
   163
    qed
bulwahn@27656
   164
  qed
bulwahn@27656
   165
qed
bulwahn@27656
   166
bulwahn@27656
   167
bulwahn@27656
   168
lemma part_partitions:
bulwahn@27656
   169
  assumes "crel (part1 a l r p) h h' rs"
bulwahn@27656
   170
  shows "(\<forall>i. l \<le> i \<and> i < rs \<longrightarrow> get_array (a::nat array) h' ! i \<le> p)
bulwahn@27656
   171
  \<and> (\<forall>i. rs < i \<and> i \<le> r \<longrightarrow> get_array a h' ! i \<ge> p)"
bulwahn@27656
   172
  using assms
bulwahn@27656
   173
proof (induct a l r p arbitrary: h h' rs rule:part1.induct)
bulwahn@27656
   174
  case (1 a l r p h h' rs)
bulwahn@27656
   175
  note cr = `crel (part1 a l r p) h h' rs`
bulwahn@27656
   176
  
bulwahn@27656
   177
  show ?case
bulwahn@27656
   178
  proof (cases "r \<le> l")
bulwahn@27656
   179
    case True (* Terminating case *)
bulwahn@27656
   180
    with cr have "rs = r"
haftmann@28145
   181
      unfolding part1.simps[of a l r p]
bulwahn@27656
   182
      by (elim crelE crel_if crel_return crel_nth) auto
bulwahn@27656
   183
    with True
bulwahn@27656
   184
    show ?thesis by auto
bulwahn@27656
   185
  next
bulwahn@27656
   186
    case False (* recursive case *)
bulwahn@27656
   187
    note lr = this
bulwahn@27656
   188
    let ?v = "get_array a h ! l"
bulwahn@27656
   189
    show ?thesis
bulwahn@27656
   190
    proof (cases "?v \<le> p")
bulwahn@27656
   191
      case True
bulwahn@27656
   192
      with lr cr
bulwahn@27656
   193
      have rec1: "crel (part1 a (l + 1) r p) h h' rs"
haftmann@28145
   194
        unfolding part1.simps[of a l r p]
bulwahn@27656
   195
        by (elim crelE crel_nth crel_if crel_return) auto
bulwahn@27656
   196
      from True part_outer_remains[OF rec1] have a_l: "get_array a h' ! l \<le> p"
wenzelm@32960
   197
        by fastsimp
bulwahn@27656
   198
      have "\<forall>i. (l \<le> i = (l = i \<or> Suc l \<le> i))" by arith
bulwahn@27656
   199
      with 1(1)[OF False True rec1] a_l show ?thesis
wenzelm@32960
   200
        by auto
bulwahn@27656
   201
    next
bulwahn@27656
   202
      case False
bulwahn@27656
   203
      with lr cr
bulwahn@27656
   204
      obtain h1 where swp: "crel (swap a l r) h h1 ()"
bulwahn@27656
   205
        and rec2: "crel (part1 a l (r - 1) p) h1 h' rs"
haftmann@28145
   206
        unfolding part1.simps[of a l r p]
bulwahn@27656
   207
        by (elim crelE crel_nth crel_if crel_return) auto
bulwahn@27656
   208
      from swp False have "get_array a h1 ! r \<ge> p"
wenzelm@32960
   209
        unfolding swap_def
haftmann@37719
   210
        by (auto simp add: Array.length_def elim!: crelE crel_nth crel_upd crel_return)
bulwahn@27656
   211
      with part_outer_remains [OF rec2] lr have a_r: "get_array a h' ! r \<ge> p"
wenzelm@32960
   212
        by fastsimp
bulwahn@27656
   213
      have "\<forall>i. (i \<le> r = (i = r \<or> i \<le> r - 1))" by arith
bulwahn@27656
   214
      with 1(2)[OF lr False rec2] a_r show ?thesis
wenzelm@32960
   215
        by auto
bulwahn@27656
   216
    qed
bulwahn@27656
   217
  qed
bulwahn@27656
   218
qed
bulwahn@27656
   219
bulwahn@27656
   220
bulwahn@27656
   221
fun partition :: "nat array \<Rightarrow> nat \<Rightarrow> nat \<Rightarrow> nat Heap"
bulwahn@27656
   222
where
bulwahn@27656
   223
  "partition a left right = (do
bulwahn@27656
   224
     pivot \<leftarrow> nth a right;
bulwahn@27656
   225
     middle \<leftarrow> part1 a left (right - 1) pivot;
bulwahn@27656
   226
     v \<leftarrow> nth a middle;
bulwahn@27656
   227
     m \<leftarrow> return (if (v \<le> pivot) then (middle + 1) else middle);
bulwahn@27656
   228
     swap a m right;
bulwahn@27656
   229
     return m
bulwahn@27656
   230
   done)"
bulwahn@27656
   231
bulwahn@27656
   232
declare partition.simps[simp del]
bulwahn@27656
   233
bulwahn@27656
   234
lemma partition_permutes:
bulwahn@27656
   235
  assumes "crel (partition a l r) h h' rs"
bulwahn@27656
   236
  shows "multiset_of (get_array a h') 
bulwahn@27656
   237
  = multiset_of (get_array a h)"
bulwahn@27656
   238
proof -
bulwahn@27656
   239
    from assms part_permutes swap_permutes show ?thesis
haftmann@28145
   240
      unfolding partition.simps
bulwahn@27656
   241
      by (elim crelE crel_return crel_nth crel_if crel_upd) auto
bulwahn@27656
   242
qed
bulwahn@27656
   243
bulwahn@27656
   244
lemma partition_length_remains:
bulwahn@27656
   245
  assumes "crel (partition a l r) h h' rs"
haftmann@37719
   246
  shows "Array.length a h = Array.length a h'"
bulwahn@27656
   247
proof -
bulwahn@27656
   248
  from assms part_length_remains show ?thesis
haftmann@28145
   249
    unfolding partition.simps swap_def
bulwahn@27656
   250
    by (elim crelE crel_return crel_nth crel_if crel_upd) auto
bulwahn@27656
   251
qed
bulwahn@27656
   252
bulwahn@27656
   253
lemma partition_outer_remains:
bulwahn@27656
   254
  assumes "crel (partition a l r) h h' rs"
bulwahn@27656
   255
  assumes "l < r"
bulwahn@27656
   256
  shows "\<forall>i. i < l \<or> r < i \<longrightarrow> get_array (a::nat array) h ! i = get_array a h' ! i"
bulwahn@27656
   257
proof -
bulwahn@27656
   258
  from assms part_outer_remains part_returns_index_in_bounds show ?thesis
haftmann@28145
   259
    unfolding partition.simps swap_def
bulwahn@27656
   260
    by (elim crelE crel_return crel_nth crel_if crel_upd) fastsimp
bulwahn@27656
   261
qed
bulwahn@27656
   262
bulwahn@27656
   263
lemma partition_returns_index_in_bounds:
bulwahn@27656
   264
  assumes crel: "crel (partition a l r) h h' rs"
bulwahn@27656
   265
  assumes "l < r"
bulwahn@27656
   266
  shows "l \<le> rs \<and> rs \<le> r"
bulwahn@27656
   267
proof -
bulwahn@27656
   268
  from crel obtain middle h'' p where part: "crel (part1 a l (r - 1) p) h h'' middle"
bulwahn@27656
   269
    and rs_equals: "rs = (if get_array a h'' ! middle \<le> get_array a h ! r then middle + 1
bulwahn@27656
   270
         else middle)"
haftmann@28145
   271
    unfolding partition.simps
bulwahn@27656
   272
    by (elim crelE crel_return crel_nth crel_if crel_upd) simp
bulwahn@27656
   273
  from `l < r` have "l \<le> r - 1" by arith
bulwahn@27656
   274
  from part_returns_index_in_bounds[OF part this] rs_equals `l < r` show ?thesis by auto
bulwahn@27656
   275
qed
bulwahn@27656
   276
bulwahn@27656
   277
lemma partition_partitions:
bulwahn@27656
   278
  assumes crel: "crel (partition a l r) h h' rs"
bulwahn@27656
   279
  assumes "l < r"
bulwahn@27656
   280
  shows "(\<forall>i. l \<le> i \<and> i < rs \<longrightarrow> get_array (a::nat array) h' ! i \<le> get_array a h' ! rs) \<and>
bulwahn@27656
   281
  (\<forall>i. rs < i \<and> i \<le> r \<longrightarrow> get_array a h' ! rs \<le> get_array a h' ! i)"
bulwahn@27656
   282
proof -
bulwahn@27656
   283
  let ?pivot = "get_array a h ! r" 
bulwahn@27656
   284
  from crel obtain middle h1 where part: "crel (part1 a l (r - 1) ?pivot) h h1 middle"
bulwahn@27656
   285
    and swap: "crel (swap a rs r) h1 h' ()"
bulwahn@27656
   286
    and rs_equals: "rs = (if get_array a h1 ! middle \<le> ?pivot then middle + 1
bulwahn@27656
   287
         else middle)"
haftmann@28145
   288
    unfolding partition.simps
bulwahn@27656
   289
    by (elim crelE crel_return crel_nth crel_if crel_upd) simp
haftmann@37719
   290
  from swap have h'_def: "h' = Array.change a r (get_array a h1 ! rs)
haftmann@37719
   291
    (Array.change a rs (get_array a h1 ! r) h1)"
haftmann@28145
   292
    unfolding swap_def
bulwahn@27656
   293
    by (elim crelE crel_return crel_nth crel_upd) simp
haftmann@37719
   294
  from swap have in_bounds: "r < Array.length a h1 \<and> rs < Array.length a h1"
haftmann@28145
   295
    unfolding swap_def
bulwahn@27656
   296
    by (elim crelE crel_return crel_nth crel_upd) simp
haftmann@37719
   297
  from swap have swap_length_remains: "Array.length a h1 = Array.length a h'"
haftmann@28145
   298
    unfolding swap_def by (elim crelE crel_return crel_nth crel_upd) auto
bulwahn@27656
   299
  from `l < r` have "l \<le> r - 1" by simp 
bulwahn@27656
   300
  note middle_in_bounds = part_returns_index_in_bounds[OF part this]
bulwahn@27656
   301
  from part_outer_remains[OF part] `l < r`
bulwahn@27656
   302
  have "get_array a h ! r = get_array a h1 ! r"
bulwahn@27656
   303
    by fastsimp
bulwahn@27656
   304
  with swap
bulwahn@27656
   305
  have right_remains: "get_array a h ! r = get_array a h' ! rs"
haftmann@28145
   306
    unfolding swap_def
haftmann@37719
   307
    by (auto simp add: Array.length_def elim!: crelE crel_return crel_nth crel_upd) (cases "r = rs", auto)
bulwahn@27656
   308
  from part_partitions [OF part]
bulwahn@27656
   309
  show ?thesis
bulwahn@27656
   310
  proof (cases "get_array a h1 ! middle \<le> ?pivot")
bulwahn@27656
   311
    case True
bulwahn@27656
   312
    with rs_equals have rs_equals: "rs = middle + 1" by simp
bulwahn@27656
   313
    { 
bulwahn@27656
   314
      fix i
bulwahn@27656
   315
      assume i_is_left: "l \<le> i \<and> i < rs"
bulwahn@27656
   316
      with swap_length_remains in_bounds middle_in_bounds rs_equals `l < r`
haftmann@37719
   317
      have i_props: "i < Array.length a h'" "i \<noteq> r" "i \<noteq> rs" by auto
bulwahn@27656
   318
      from i_is_left rs_equals have "l \<le> i \<and> i < middle \<or> i = middle" by arith
bulwahn@27656
   319
      with part_partitions[OF part] right_remains True
bulwahn@27656
   320
      have "get_array a h1 ! i \<le> get_array a h' ! rs" by fastsimp
bulwahn@27656
   321
      with i_props h'_def in_bounds have "get_array a h' ! i \<le> get_array a h' ! rs"
haftmann@37719
   322
        unfolding Array.change_def Array.length_def by simp
bulwahn@27656
   323
    }
bulwahn@27656
   324
    moreover
bulwahn@27656
   325
    {
bulwahn@27656
   326
      fix i
bulwahn@27656
   327
      assume "rs < i \<and> i \<le> r"
bulwahn@27656
   328
bulwahn@27656
   329
      hence "(rs < i \<and> i \<le> r - 1) \<or> (rs < i \<and> i = r)" by arith
bulwahn@27656
   330
      hence "get_array a h' ! rs \<le> get_array a h' ! i"
bulwahn@27656
   331
      proof
wenzelm@32960
   332
        assume i_is: "rs < i \<and> i \<le> r - 1"
wenzelm@32960
   333
        with swap_length_remains in_bounds middle_in_bounds rs_equals
haftmann@37719
   334
        have i_props: "i < Array.length a h'" "i \<noteq> r" "i \<noteq> rs" by auto
wenzelm@32960
   335
        from part_partitions[OF part] rs_equals right_remains i_is
wenzelm@32960
   336
        have "get_array a h' ! rs \<le> get_array a h1 ! i"
wenzelm@32960
   337
          by fastsimp
wenzelm@32960
   338
        with i_props h'_def show ?thesis by fastsimp
bulwahn@27656
   339
      next
wenzelm@32960
   340
        assume i_is: "rs < i \<and> i = r"
wenzelm@32960
   341
        with rs_equals have "Suc middle \<noteq> r" by arith
wenzelm@32960
   342
        with middle_in_bounds `l < r` have "Suc middle \<le> r - 1" by arith
wenzelm@32960
   343
        with part_partitions[OF part] right_remains 
wenzelm@32960
   344
        have "get_array a h' ! rs \<le> get_array a h1 ! (Suc middle)"
wenzelm@32960
   345
          by fastsimp
wenzelm@32960
   346
        with i_is True rs_equals right_remains h'_def
wenzelm@32960
   347
        show ?thesis using in_bounds
haftmann@37719
   348
          unfolding Array.change_def Array.length_def
wenzelm@32960
   349
          by auto
bulwahn@27656
   350
      qed
bulwahn@27656
   351
    }
bulwahn@27656
   352
    ultimately show ?thesis by auto
bulwahn@27656
   353
  next
bulwahn@27656
   354
    case False
bulwahn@27656
   355
    with rs_equals have rs_equals: "middle = rs" by simp
bulwahn@27656
   356
    { 
bulwahn@27656
   357
      fix i
bulwahn@27656
   358
      assume i_is_left: "l \<le> i \<and> i < rs"
bulwahn@27656
   359
      with swap_length_remains in_bounds middle_in_bounds rs_equals
haftmann@37719
   360
      have i_props: "i < Array.length a h'" "i \<noteq> r" "i \<noteq> rs" by auto
bulwahn@27656
   361
      from part_partitions[OF part] rs_equals right_remains i_is_left
bulwahn@27656
   362
      have "get_array a h1 ! i \<le> get_array a h' ! rs" by fastsimp
bulwahn@27656
   363
      with i_props h'_def have "get_array a h' ! i \<le> get_array a h' ! rs"
haftmann@37719
   364
        unfolding Array.change_def by simp
bulwahn@27656
   365
    }
bulwahn@27656
   366
    moreover
bulwahn@27656
   367
    {
bulwahn@27656
   368
      fix i
bulwahn@27656
   369
      assume "rs < i \<and> i \<le> r"
bulwahn@27656
   370
      hence "(rs < i \<and> i \<le> r - 1) \<or> i = r" by arith
bulwahn@27656
   371
      hence "get_array a h' ! rs \<le> get_array a h' ! i"
bulwahn@27656
   372
      proof
wenzelm@32960
   373
        assume i_is: "rs < i \<and> i \<le> r - 1"
wenzelm@32960
   374
        with swap_length_remains in_bounds middle_in_bounds rs_equals
haftmann@37719
   375
        have i_props: "i < Array.length a h'" "i \<noteq> r" "i \<noteq> rs" by auto
wenzelm@32960
   376
        from part_partitions[OF part] rs_equals right_remains i_is
wenzelm@32960
   377
        have "get_array a h' ! rs \<le> get_array a h1 ! i"
wenzelm@32960
   378
          by fastsimp
wenzelm@32960
   379
        with i_props h'_def show ?thesis by fastsimp
bulwahn@27656
   380
      next
wenzelm@32960
   381
        assume i_is: "i = r"
wenzelm@32960
   382
        from i_is False rs_equals right_remains h'_def
wenzelm@32960
   383
        show ?thesis using in_bounds
haftmann@37719
   384
          unfolding Array.change_def Array.length_def
wenzelm@32960
   385
          by auto
bulwahn@27656
   386
      qed
bulwahn@27656
   387
    }
bulwahn@27656
   388
    ultimately
bulwahn@27656
   389
    show ?thesis by auto
bulwahn@27656
   390
  qed
bulwahn@27656
   391
qed
bulwahn@27656
   392
bulwahn@27656
   393
bulwahn@27656
   394
function quicksort :: "nat array \<Rightarrow> nat \<Rightarrow> nat \<Rightarrow> unit Heap"
bulwahn@27656
   395
where
bulwahn@27656
   396
  "quicksort arr left right =
bulwahn@27656
   397
     (if (right > left)  then
bulwahn@27656
   398
        do
bulwahn@27656
   399
          pivotNewIndex \<leftarrow> partition arr left right;
bulwahn@27656
   400
          pivotNewIndex \<leftarrow> assert (\<lambda>x. left \<le> x \<and> x \<le> right) pivotNewIndex;
bulwahn@27656
   401
          quicksort arr left (pivotNewIndex - 1);
bulwahn@27656
   402
          quicksort arr (pivotNewIndex + 1) right
bulwahn@27656
   403
        done
bulwahn@27656
   404
     else return ())"
bulwahn@27656
   405
by pat_completeness auto
bulwahn@27656
   406
bulwahn@27656
   407
(* For termination, we must show that the pivotNewIndex is between left and right *) 
bulwahn@27656
   408
termination
bulwahn@27656
   409
by (relation "measure (\<lambda>(a, l, r). (r - l))") auto
bulwahn@27656
   410
bulwahn@27656
   411
declare quicksort.simps[simp del]
bulwahn@27656
   412
bulwahn@27656
   413
bulwahn@27656
   414
lemma quicksort_permutes:
bulwahn@27656
   415
  assumes "crel (quicksort a l r) h h' rs"
bulwahn@27656
   416
  shows "multiset_of (get_array a h') 
bulwahn@27656
   417
  = multiset_of (get_array a h)"
bulwahn@27656
   418
  using assms
bulwahn@27656
   419
proof (induct a l r arbitrary: h h' rs rule: quicksort.induct)
bulwahn@27656
   420
  case (1 a l r h h' rs)
bulwahn@27656
   421
  with partition_permutes show ?case
haftmann@28145
   422
    unfolding quicksort.simps [of a l r]
bulwahn@27656
   423
    by (elim crel_if crelE crel_assert crel_return) auto
bulwahn@27656
   424
qed
bulwahn@27656
   425
bulwahn@27656
   426
lemma length_remains:
bulwahn@27656
   427
  assumes "crel (quicksort a l r) h h' rs"
haftmann@37719
   428
  shows "Array.length a h = Array.length a h'"
bulwahn@27656
   429
using assms
bulwahn@27656
   430
proof (induct a l r arbitrary: h h' rs rule: quicksort.induct)
bulwahn@27656
   431
  case (1 a l r h h' rs)
bulwahn@27656
   432
  with partition_length_remains show ?case
haftmann@28145
   433
    unfolding quicksort.simps [of a l r]
bulwahn@27656
   434
    by (elim crel_if crelE crel_assert crel_return) auto
bulwahn@27656
   435
qed
bulwahn@27656
   436
bulwahn@27656
   437
lemma quicksort_outer_remains:
bulwahn@27656
   438
  assumes "crel (quicksort a l r) h h' rs"
bulwahn@27656
   439
   shows "\<forall>i. i < l \<or> r < i \<longrightarrow> get_array (a::nat array) h ! i = get_array a h' ! i"
bulwahn@27656
   440
  using assms
bulwahn@27656
   441
proof (induct a l r arbitrary: h h' rs rule: quicksort.induct)
bulwahn@27656
   442
  case (1 a l r h h' rs)
bulwahn@27656
   443
  note cr = `crel (quicksort a l r) h h' rs`
bulwahn@27656
   444
  thus ?case
bulwahn@27656
   445
  proof (cases "r > l")
bulwahn@27656
   446
    case False
bulwahn@27656
   447
    with cr have "h' = h"
bulwahn@27656
   448
      unfolding quicksort.simps [of a l r]
bulwahn@27656
   449
      by (elim crel_if crel_return) auto
bulwahn@27656
   450
    thus ?thesis by simp
bulwahn@27656
   451
  next
bulwahn@27656
   452
  case True
bulwahn@27656
   453
   { 
bulwahn@27656
   454
      fix h1 h2 p ret1 ret2 i
bulwahn@27656
   455
      assume part: "crel (partition a l r) h h1 p"
bulwahn@27656
   456
      assume qs1: "crel (quicksort a l (p - 1)) h1 h2 ret1"
bulwahn@27656
   457
      assume qs2: "crel (quicksort a (p + 1) r) h2 h' ret2"
bulwahn@27656
   458
      assume pivot: "l \<le> p \<and> p \<le> r"
bulwahn@27656
   459
      assume i_outer: "i < l \<or> r < i"
bulwahn@27656
   460
      from  partition_outer_remains [OF part True] i_outer
bulwahn@27656
   461
      have "get_array a h !i = get_array a h1 ! i" by fastsimp
bulwahn@27656
   462
      moreover
bulwahn@27656
   463
      with 1(1) [OF True pivot qs1] pivot i_outer
bulwahn@27656
   464
      have "get_array a h1 ! i = get_array a h2 ! i" by auto
bulwahn@27656
   465
      moreover
bulwahn@27656
   466
      with qs2 1(2) [of p h2 h' ret2] True pivot i_outer
bulwahn@27656
   467
      have "get_array a h2 ! i = get_array a h' ! i" by auto
bulwahn@27656
   468
      ultimately have "get_array a h ! i= get_array a h' ! i" by simp
bulwahn@27656
   469
    }
bulwahn@27656
   470
    with cr show ?thesis
haftmann@28145
   471
      unfolding quicksort.simps [of a l r]
bulwahn@27656
   472
      by (elim crel_if crelE crel_assert crel_return) auto
bulwahn@27656
   473
  qed
bulwahn@27656
   474
qed
bulwahn@27656
   475
bulwahn@27656
   476
lemma quicksort_is_skip:
bulwahn@27656
   477
  assumes "crel (quicksort a l r) h h' rs"
bulwahn@27656
   478
  shows "r \<le> l \<longrightarrow> h = h'"
bulwahn@27656
   479
  using assms
haftmann@28145
   480
  unfolding quicksort.simps [of a l r]
bulwahn@27656
   481
  by (elim crel_if crel_return) auto
bulwahn@27656
   482
 
bulwahn@27656
   483
lemma quicksort_sorts:
bulwahn@27656
   484
  assumes "crel (quicksort a l r) h h' rs"
haftmann@37719
   485
  assumes l_r_length: "l < Array.length a h" "r < Array.length a h" 
bulwahn@27656
   486
  shows "sorted (subarray l (r + 1) a h')"
bulwahn@27656
   487
  using assms
bulwahn@27656
   488
proof (induct a l r arbitrary: h h' rs rule: quicksort.induct)
bulwahn@27656
   489
  case (1 a l r h h' rs)
bulwahn@27656
   490
  note cr = `crel (quicksort a l r) h h' rs`
bulwahn@27656
   491
  thus ?case
bulwahn@27656
   492
  proof (cases "r > l")
bulwahn@27656
   493
    case False
bulwahn@27656
   494
    hence "l \<ge> r + 1 \<or> l = r" by arith 
bulwahn@27656
   495
    with length_remains[OF cr] 1(5) show ?thesis
bulwahn@27656
   496
      by (auto simp add: subarray_Nil subarray_single)
bulwahn@27656
   497
  next
bulwahn@27656
   498
    case True
bulwahn@27656
   499
    { 
bulwahn@27656
   500
      fix h1 h2 p
bulwahn@27656
   501
      assume part: "crel (partition a l r) h h1 p"
bulwahn@27656
   502
      assume qs1: "crel (quicksort a l (p - 1)) h1 h2 ()"
bulwahn@27656
   503
      assume qs2: "crel (quicksort a (p + 1) r) h2 h' ()"
bulwahn@27656
   504
      from partition_returns_index_in_bounds [OF part True]
bulwahn@27656
   505
      have pivot: "l\<le> p \<and> p \<le> r" .
bulwahn@27656
   506
     note length_remains = length_remains[OF qs2] length_remains[OF qs1] partition_length_remains[OF part]
bulwahn@27656
   507
      from quicksort_outer_remains [OF qs2] quicksort_outer_remains [OF qs1] pivot quicksort_is_skip[OF qs1]
bulwahn@27656
   508
      have pivot_unchanged: "get_array a h1 ! p = get_array a h' ! p" by (cases p, auto)
haftmann@28013
   509
        (*-- First of all, by induction hypothesis both sublists are sorted. *)
bulwahn@27656
   510
      from 1(1)[OF True pivot qs1] length_remains pivot 1(5) 
bulwahn@27656
   511
      have IH1: "sorted (subarray l p a h2)"  by (cases p, auto simp add: subarray_Nil)
bulwahn@27656
   512
      from quicksort_outer_remains [OF qs2] length_remains
bulwahn@27656
   513
      have left_subarray_remains: "subarray l p a h2 = subarray l p a h'"
wenzelm@32960
   514
        by (simp add: subarray_eq_samelength_iff)
bulwahn@27656
   515
      with IH1 have IH1': "sorted (subarray l p a h')" by simp
bulwahn@27656
   516
      from 1(2)[OF True pivot qs2] pivot 1(5) length_remains
bulwahn@27656
   517
      have IH2: "sorted (subarray (p + 1) (r + 1) a h')"
haftmann@28013
   518
        by (cases "Suc p \<le> r", auto simp add: subarray_Nil)
haftmann@28013
   519
           (* -- Secondly, both sublists remain partitioned. *)
bulwahn@27656
   520
      from partition_partitions[OF part True]
bulwahn@27656
   521
      have part_conds1: "\<forall>j. j \<in> set (subarray l p a h1) \<longrightarrow> j \<le> get_array a h1 ! p "
haftmann@28013
   522
        and part_conds2: "\<forall>j. j \<in> set (subarray (p + 1) (r + 1) a h1) \<longrightarrow> get_array a h1 ! p \<le> j"
haftmann@28013
   523
        by (auto simp add: all_in_set_subarray_conv)
bulwahn@27656
   524
      from quicksort_outer_remains [OF qs1] quicksort_permutes [OF qs1] True
haftmann@28013
   525
        length_remains 1(5) pivot multiset_of_sublist [of l p "get_array a h1" "get_array a h2"]
bulwahn@27656
   526
      have multiset_partconds1: "multiset_of (subarray l p a h2) = multiset_of (subarray l p a h1)"
haftmann@37719
   527
        unfolding Array.length_def subarray_def by (cases p, auto)
bulwahn@27656
   528
      with left_subarray_remains part_conds1 pivot_unchanged
bulwahn@27656
   529
      have part_conds2': "\<forall>j. j \<in> set (subarray l p a h') \<longrightarrow> j \<le> get_array a h' ! p"
haftmann@28013
   530
        by (simp, subst set_of_multiset_of[symmetric], simp)
haftmann@28013
   531
          (* -- These steps are the analogous for the right sublist \<dots> *)
bulwahn@27656
   532
      from quicksort_outer_remains [OF qs1] length_remains
bulwahn@27656
   533
      have right_subarray_remains: "subarray (p + 1) (r + 1) a h1 = subarray (p + 1) (r + 1) a h2"
wenzelm@32960
   534
        by (auto simp add: subarray_eq_samelength_iff)
bulwahn@27656
   535
      from quicksort_outer_remains [OF qs2] quicksort_permutes [OF qs2] True
haftmann@28013
   536
        length_remains 1(5) pivot multiset_of_sublist [of "p + 1" "r + 1" "get_array a h2" "get_array a h'"]
bulwahn@27656
   537
      have multiset_partconds2: "multiset_of (subarray (p + 1) (r + 1) a h') = multiset_of (subarray (p + 1) (r + 1) a h2)"
haftmann@37719
   538
        unfolding Array.length_def subarray_def by auto
bulwahn@27656
   539
      with right_subarray_remains part_conds2 pivot_unchanged
bulwahn@27656
   540
      have part_conds1': "\<forall>j. j \<in> set (subarray (p + 1) (r + 1) a h') \<longrightarrow> get_array a h' ! p \<le> j"
haftmann@28013
   541
        by (simp, subst set_of_multiset_of[symmetric], simp)
haftmann@28013
   542
          (* -- Thirdly and finally, we show that the array is sorted
haftmann@28013
   543
          following from the facts above. *)
bulwahn@27656
   544
      from True pivot 1(5) length_remains have "subarray l (r + 1) a h' = subarray l p a h' @ [get_array a h' ! p] @ subarray (p + 1) (r + 1) a h'"
wenzelm@32960
   545
        by (simp add: subarray_nth_array_Cons, cases "l < p") (auto simp add: subarray_append subarray_Nil)
bulwahn@27656
   546
      with IH1' IH2 part_conds1' part_conds2' pivot have ?thesis
wenzelm@32960
   547
        unfolding subarray_def
wenzelm@32960
   548
        apply (auto simp add: sorted_append sorted_Cons all_in_set_sublist'_conv)
wenzelm@32960
   549
        by (auto simp add: set_sublist' dest: le_trans [of _ "get_array a h' ! p"])
bulwahn@27656
   550
    }
bulwahn@27656
   551
    with True cr show ?thesis
haftmann@28145
   552
      unfolding quicksort.simps [of a l r]
bulwahn@27656
   553
      by (elim crel_if crel_return crelE crel_assert) auto
bulwahn@27656
   554
  qed
bulwahn@27656
   555
qed
bulwahn@27656
   556
bulwahn@27656
   557
bulwahn@27656
   558
lemma quicksort_is_sort:
haftmann@37719
   559
  assumes crel: "crel (quicksort a 0 (Array.length a h - 1)) h h' rs"
bulwahn@27656
   560
  shows "get_array a h' = sort (get_array a h)"
bulwahn@27656
   561
proof (cases "get_array a h = []")
bulwahn@27656
   562
  case True
bulwahn@27656
   563
  with quicksort_is_skip[OF crel] show ?thesis
haftmann@37719
   564
  unfolding Array.length_def by simp
bulwahn@27656
   565
next
bulwahn@27656
   566
  case False
bulwahn@27656
   567
  from quicksort_sorts [OF crel] False have "sorted (sublist' 0 (List.length (get_array a h)) (get_array a h'))"
haftmann@37719
   568
    unfolding Array.length_def subarray_def by auto
bulwahn@27656
   569
  with length_remains[OF crel] have "sorted (get_array a h')"
haftmann@37719
   570
    unfolding Array.length_def by simp
bulwahn@27656
   571
  with quicksort_permutes [OF crel] properties_for_sort show ?thesis by fastsimp
bulwahn@27656
   572
qed
bulwahn@27656
   573
bulwahn@27656
   574
subsection {* No Errors in quicksort *}
bulwahn@27656
   575
text {* We have proved that quicksort sorts (if no exceptions occur).
bulwahn@27656
   576
We will now show that exceptions do not occur. *}
bulwahn@27656
   577
haftmann@37758
   578
lemma success_part1I: 
haftmann@37719
   579
  assumes "l < Array.length a h" "r < Array.length a h"
haftmann@37758
   580
  shows "success (part1 a l r p) h"
bulwahn@27656
   581
  using assms
bulwahn@27656
   582
proof (induct a l r p arbitrary: h rule: part1.induct)
bulwahn@27656
   583
  case (1 a l r p)
bulwahn@27656
   584
  thus ?case
haftmann@28145
   585
    unfolding part1.simps [of a l r] swap_def
haftmann@37758
   586
    by (auto simp add: execute_simps intro!: success_intros elim!: crelE crel_upd crel_nth crel_return)
bulwahn@27656
   587
qed
bulwahn@27656
   588
haftmann@37758
   589
lemma success_ifI: (*FIXME move*)
haftmann@37758
   590
  assumes "c \<Longrightarrow> success t h" "\<not> c \<Longrightarrow> success e h"
haftmann@37758
   591
  shows "success (if c then t else e) h"
haftmann@37758
   592
  using assms
haftmann@37758
   593
  unfolding success_def
haftmann@37758
   594
  by auto
haftmann@37758
   595
haftmann@37758
   596
lemma success_bindI' [success_intros]: (*FIXME move*)
haftmann@37758
   597
  assumes "success f h"
haftmann@37758
   598
  assumes "\<And>h' r. crel f h h' r \<Longrightarrow> success (g r) h'"
haftmann@37758
   599
  shows "success (f \<guillemotright>= g) h"
haftmann@37758
   600
  using assms by (auto intro!: successI elim!: successE simp add: bind_def crel_def success_def) blast
haftmann@37758
   601
haftmann@37758
   602
lemma success_partitionI:
haftmann@37719
   603
  assumes "l < r" "l < Array.length a h" "r < Array.length a h"
haftmann@37758
   604
  shows "success (partition a l r) h"
haftmann@37758
   605
using assms unfolding partition.simps swap_def
haftmann@37758
   606
apply (auto intro!: success_bindI' success_ifI success_returnI success_nthI success_updI success_part1I elim!: crelE crel_upd crel_nth crel_return simp add:)
bulwahn@27656
   607
apply (frule part_length_remains)
bulwahn@27656
   608
apply (frule part_returns_index_in_bounds)
bulwahn@27656
   609
apply auto
bulwahn@27656
   610
apply (frule part_length_remains)
bulwahn@27656
   611
apply (frule part_returns_index_in_bounds)
bulwahn@27656
   612
apply auto
bulwahn@27656
   613
apply (frule part_length_remains)
bulwahn@27656
   614
apply auto
bulwahn@27656
   615
done
bulwahn@27656
   616
haftmann@37758
   617
lemma success_quicksortI:
haftmann@37719
   618
  assumes "l < Array.length a h" "r < Array.length a h"
haftmann@37758
   619
  shows "success (quicksort a l r) h"
bulwahn@27656
   620
using assms
bulwahn@27656
   621
proof (induct a l r arbitrary: h rule: quicksort.induct)
bulwahn@27656
   622
  case (1 a l ri h)
bulwahn@27656
   623
  thus ?case
haftmann@28145
   624
    unfolding quicksort.simps [of a l ri]
haftmann@37758
   625
    apply (auto intro!: success_ifI success_bindI' success_returnI success_nthI success_updI success_assertI success_partitionI)
bulwahn@27656
   626
    apply (frule partition_returns_index_in_bounds)
bulwahn@27656
   627
    apply auto
bulwahn@27656
   628
    apply (frule partition_returns_index_in_bounds)
bulwahn@27656
   629
    apply auto
bulwahn@27656
   630
    apply (auto elim!: crel_assert dest!: partition_length_remains length_remains)
bulwahn@27656
   631
    apply (subgoal_tac "Suc r \<le> ri \<or> r = ri") 
bulwahn@27656
   632
    apply (erule disjE)
bulwahn@27656
   633
    apply auto
haftmann@28145
   634
    unfolding quicksort.simps [of a "Suc ri" ri]
haftmann@37758
   635
    apply (auto intro!: success_ifI success_returnI)
bulwahn@27656
   636
    done
bulwahn@27656
   637
qed
bulwahn@27656
   638
haftmann@27674
   639
haftmann@27674
   640
subsection {* Example *}
haftmann@27674
   641
haftmann@27674
   642
definition "qsort a = do
haftmann@37719
   643
    k \<leftarrow> len a;
haftmann@27674
   644
    quicksort a 0 (k - 1);
haftmann@27674
   645
    return a
haftmann@27674
   646
  done"
haftmann@27674
   647
haftmann@35041
   648
code_reserved SML upto
haftmann@35041
   649
haftmann@27674
   650
ML {* @{code qsort} (Array.fromList [42, 2, 3, 5, 0, 1705, 8, 3, 15]) () *}
haftmann@27674
   651
haftmann@37750
   652
export_code qsort in SML_imp module_name QSort file -
haftmann@29793
   653
export_code qsort in OCaml module_name QSort file -
haftmann@31887
   654
export_code qsort in OCaml_imp module_name QSort file -
haftmann@29793
   655
export_code qsort in Haskell module_name QSort file -
haftmann@27674
   656
bulwahn@27656
   657
end