src/HOL/Hoare/Examples.ML
author wenzelm
Sat, 06 Oct 2001 00:02:46 +0200
changeset 11704 3c50a2cd6f00
parent 11701 3d51fbf81c17
child 12486 0ed8bdd883e0
permissions -rw-r--r--
* sane numerals (stage 2): plain "num" syntax (removed "#");
oheimb@9393
     1
(*  Title:      HOL/Hoare/Examples.ML
nipkow@1335
     2
    ID:         $Id$
nipkow@5646
     3
    Author:     Norbert Galm & Tobias Nipkow
nipkow@5646
     4
    Copyright   1998 TUM
nipkow@1335
     5
*)
nipkow@1335
     6
nipkow@5646
     7
(*** ARITHMETIC ***)
nipkow@1335
     8
nipkow@6802
     9
(** multiplication by successive addition **)
nipkow@1335
    10
oheimb@9147
    11
Goal "|- VARS m s a b. \
oheimb@9147
    12
\  {a=A & b=B} \
oheimb@9147
    13
\  m := 0; s := 0; \
nipkow@5646
    14
\  WHILE m~=a \
oheimb@9147
    15
\  INV {s=m*b & a=A & b=B} \  
wenzelm@11701
    16
\  DO s := s+b; m := m+(1::nat) OD \
oheimb@9147
    17
\  {s = A*B}"; 
paulson@6162
    18
by (hoare_tac (Asm_full_simp_tac) 1);
nipkow@1335
    19
qed "multiply_by_add";
nipkow@1335
    20
nipkow@6802
    21
(** Euclid's algorithm for GCD **)
nipkow@1335
    22
nipkow@5646
    23
Goal "|- VARS a b. \
oheimb@9147
    24
\ {0<A & 0<B} \
oheimb@9147
    25
\ a := A; b := B; \
nipkow@5646
    26
\ WHILE  a~=b  \
nipkow@5646
    27
\ INV {0<a & 0<b & gcd A B = gcd a b} \
nipkow@5646
    28
\ DO IF a<b THEN b := b-a ELSE a := a-b FI OD \
nipkow@1335
    29
\ {a = gcd A B}";
nipkow@5646
    30
by (hoare_tac (K all_tac) 1);
paulson@3372
    31
(*Now prove the verification conditions*)
oheimb@9147
    32
by   Auto_tac;
oheimb@9147
    33
by    (etac gcd_nnn 4);
oheimb@9147
    34
by   (asm_full_simp_tac (simpset() addsimps [not_less_iff_le, gcd_diff_l]) 3);
oheimb@9147
    35
by  (force_tac (claset(),
nipkow@5646
    36
               simpset() addsimps [not_less_iff_le, le_eq_less_or_eq]) 2);
nipkow@5646
    37
by (asm_simp_tac (simpset() addsimps [gcd_diff_r,less_imp_le]) 1);
nipkow@1335
    38
qed "Euclid_GCD";
nipkow@1335
    39
nipkow@10123
    40
(** Dijkstra's extension of Euclid's algorithm for simultaneous GCD and SCM **)
nipkow@10123
    41
(* From E.W. Disjkstra. Selected Writings on Computing, p 98 (EWD474),
nipkow@10123
    42
   where it is given without the invariant. Instead of defining scm
nipkow@10123
    43
   explicitly we have used the theorem scm x y = x*y/gcd x y and avoided
nipkow@10123
    44
   division by mupltiplying with gcd x y.
nipkow@10123
    45
*)
nipkow@10123
    46
nipkow@10123
    47
val distribs =
nipkow@10123
    48
  [diff_mult_distrib,diff_mult_distrib2,add_mult_distrib,add_mult_distrib2];
nipkow@10123
    49
nipkow@10123
    50
Goal "|- VARS a b x y. \
nipkow@10123
    51
\ {0<A & 0<B & a=A & b=B & x=B & y=A} \
nipkow@10123
    52
\ WHILE  a ~= b  \
wenzelm@11704
    53
\ INV {0<a & 0<b & gcd A B = gcd a b & 2*A*B = a*x + b*y} \
nipkow@10123
    54
\ DO IF a<b THEN (b := b-a; x := x+y) ELSE (a := a-b; y := y+x) FI OD \
wenzelm@11704
    55
\ {a = gcd A B & 2*A*B = a*(x+y)}";
nipkow@10123
    56
by (hoare_tac (K all_tac) 1);
nipkow@10123
    57
by(Asm_simp_tac 1);
nipkow@10123
    58
by(asm_simp_tac (simpset() addsimps
nipkow@10123
    59
    (distribs @ [gcd_diff_r,not_less_iff_le, gcd_diff_l])) 1);
nipkow@10123
    60
by(arith_tac 1);
nipkow@10123
    61
by(asm_full_simp_tac (simpset() addsimps (distribs @ [gcd_nnn])) 1);
nipkow@10123
    62
qed "gcd_scm";
nipkow@10123
    63
nipkow@6802
    64
(** Power by iterated squaring and multiplication **)
nipkow@1335
    65
nipkow@5646
    66
Goal "|- VARS a b c. \
nipkow@5646
    67
\ {a=A & b=B} \
wenzelm@11701
    68
\ c := (1::nat); \
nipkow@5646
    69
\ WHILE b ~= 0 \
nipkow@5646
    70
\ INV {A^B = c * a^b} \
wenzelm@11704
    71
\ DO  WHILE b mod 2 = 0 \
nipkow@5646
    72
\     INV {A^B = c * a^b} \
wenzelm@11704
    73
\     DO  a := a*a; b := b div 2 OD; \
wenzelm@11701
    74
\     c := c*a; b := b - 1 \
nipkow@5646
    75
\ OD \
nipkow@4359
    76
\ {c = A^B}";
paulson@6162
    77
by (hoare_tac (Asm_full_simp_tac) 1);
wenzelm@8442
    78
by (case_tac "b" 1);
oheimb@9147
    79
by  (asm_full_simp_tac (simpset() addsimps [mod_less]) 1);
paulson@8791
    80
by (Asm_simp_tac 1);
nipkow@1335
    81
qed "power_by_mult";
nipkow@1335
    82
nipkow@6802
    83
(** Factorial **)
nipkow@6802
    84
nipkow@5646
    85
Goal "|- VARS a b. \
nipkow@5646
    86
\ {a=A} \
nipkow@5646
    87
\ b := 1; \
nipkow@5646
    88
\ WHILE a ~= 0 \
nipkow@5646
    89
\ INV {fac A = b * fac a} \
wenzelm@11701
    90
\ DO b := b*a; a := a - 1 OD \
nipkow@1335
    91
\ {b = fac A}";
paulson@10700
    92
by (hoare_tac (asm_full_simp_tac (simpset() addsplits [nat_diff_split])) 1);
paulson@10700
    93
by Auto_tac;  
oheimb@9147
    94
qed "factorial";
nipkow@1335
    95
nipkow@6802
    96
(** Square root **)
nipkow@6802
    97
nipkow@6816
    98
(* the easy way: *)
nipkow@6802
    99
oheimb@9147
   100
Goal "|- VARS r x. \
oheimb@9147
   101
\ {True} \
wenzelm@11701
   102
\ x := X; r := (0::nat); \
nipkow@6802
   103
\ WHILE (r+1)*(r+1) <= x \
oheimb@9147
   104
\ INV {r*r <= x & x=X} \
nipkow@6802
   105
\ DO r := r+1 OD \
oheimb@9147
   106
\ {r*r <= X & X < (r+1)*(r+1)}";
oheimb@9147
   107
by (hoare_tac (SELECT_GOAL Auto_tac) 1);
nipkow@6802
   108
qed "sqrt";
nipkow@6802
   109
nipkow@6802
   110
(* without multiplication *)
nipkow@6802
   111
oheimb@9147
   112
Goal "|- VARS u w r x. \
oheimb@9147
   113
\ {True} \
wenzelm@11701
   114
\ x := X; u := 1; w := 1; r := (0::nat); \
nipkow@6802
   115
\ WHILE w <= x \
oheimb@9147
   116
\ INV {u = r+r+1 & w = (r+1)*(r+1) & r*r <= x & x=X} \
wenzelm@11704
   117
\ DO r := r + 1; w := w + u + 2; u := u + 2 OD \
oheimb@9147
   118
\ {r*r <= X & X < (r+1)*(r+1)}";
oheimb@9147
   119
by (hoare_tac (SELECT_GOAL Auto_tac) 1);
nipkow@6802
   120
qed "sqrt_without_multiplication";
nipkow@6802
   121
nipkow@6802
   122
nipkow@5646
   123
(*** LISTS ***)
nipkow@5646
   124
nipkow@5646
   125
Goal "|- VARS y x. \
nipkow@5646
   126
\ {x=X} \
nipkow@5646
   127
\ y:=[]; \
nipkow@5646
   128
\ WHILE x ~= [] \
nipkow@5646
   129
\ INV {rev(x)@y = rev(X)} \
nipkow@5646
   130
\ DO y := (hd x # y); x := tl x OD \
nipkow@5646
   131
\ {y=rev(X)}";
nipkow@5646
   132
by (hoare_tac Asm_full_simp_tac 1);
oheimb@9147
   133
by  (asm_full_simp_tac (simpset() addsimps [neq_Nil_conv]) 1);
oheimb@9147
   134
by  Auto_tac;
nipkow@5646
   135
qed "imperative_reverse";
nipkow@5646
   136
nipkow@5646
   137
Goal
nipkow@5646
   138
"|- VARS x y. \
nipkow@5646
   139
\ {x=X & y=Y} \
nipkow@5646
   140
\ x := rev(x); \
nipkow@5646
   141
\ WHILE x~=[] \
nipkow@5646
   142
\ INV {rev(x)@y = X@Y} \
nipkow@5646
   143
\ DO y := (hd x # y); \
nipkow@5646
   144
\    x := tl x \
nipkow@5646
   145
\ OD \
nipkow@5646
   146
\ {y = X@Y}";
nipkow@5646
   147
by (hoare_tac Asm_full_simp_tac 1);
oheimb@9147
   148
by  (asm_full_simp_tac (simpset() addsimps [neq_Nil_conv]) 1);
oheimb@9147
   149
by  Auto_tac;
nipkow@5646
   150
qed "imperative_append";
nipkow@5646
   151
nipkow@5646
   152
nipkow@5646
   153
(*** ARRAYS ***)
nipkow@5646
   154
nipkow@5646
   155
(* Search for 0 *)
nipkow@5646
   156
Goal
nipkow@5646
   157
"|- VARS A i. \
nipkow@5646
   158
\ {True} \
nipkow@5646
   159
\ i := 0; \
nipkow@5646
   160
\ WHILE i < length A & A!i ~= 0 \
nipkow@5646
   161
\ INV {!j. j<i --> A!j ~= 0} \
nipkow@5646
   162
\ DO i := i+1 OD \
nipkow@5646
   163
\ {(i < length A --> A!i = 0) & \
nipkow@5646
   164
\  (i = length A --> (!j. j < length A --> A!j ~= 0))}";
nipkow@5646
   165
by (hoare_tac Asm_full_simp_tac 1);
paulson@6162
   166
by (blast_tac (claset() addSEs [less_SucE]) 1);
nipkow@5646
   167
qed "zero_search";
nipkow@5646
   168
nipkow@5646
   169
(* 
nipkow@5646
   170
The `partition' procedure for quicksort.
nipkow@5646
   171
`A' is the array to be sorted (modelled as a list).
nipkow@5646
   172
Elements of A must be of class order to infer at the end
nipkow@5646
   173
that the elements between u and l are equal to pivot.
nipkow@5646
   174
nipkow@5646
   175
Ambiguity warnings of parser are due to := being used
nipkow@5646
   176
both for assignment and list update.
nipkow@5646
   177
*)
wenzelm@11701
   178
Goal "m - Suc 0 < n ==> m < Suc n";
paulson@10962
   179
by (arith_tac 1);
paulson@10962
   180
qed "lemma";
paulson@10962
   181
nipkow@5646
   182
Goal
nipkow@5646
   183
"[| leq == %A i. !k. k<i --> A!k <= pivot; \
nipkow@5646
   184
\   geq == %A i. !k. i<k & k<length A --> pivot <= A!k |] ==> \
nipkow@5646
   185
\ |- VARS A u l.\
nipkow@5646
   186
\ {0 < length(A::('a::order)list)} \
wenzelm@11701
   187
\ l := 0; u := length A - Suc 0; \
nipkow@5646
   188
\ WHILE l <= u \
nipkow@5646
   189
\  INV {leq A l & geq A u & u<length A & l<=length A} \
nipkow@5646
   190
\  DO WHILE l < length A & A!l <= pivot \
nipkow@5646
   191
\      INV {leq A l & geq A u & u<length A & l<=length A} \
nipkow@5646
   192
\      DO l := l+1 OD; \
nipkow@5646
   193
\     WHILE 0 < u & pivot <= A!u \
nipkow@5646
   194
\      INV {leq A l & geq A u  & u<length A & l<=length A} \
wenzelm@11701
   195
\      DO u := u - 1 OD; \
nipkow@5646
   196
\     IF l <= u THEN A := A[l := A!u, u := A!l] ELSE SKIP FI \
nipkow@5646
   197
\  OD \
nipkow@5646
   198
\ {leq A u & (!k. u<k & k<l --> A!k = pivot) & geq A l}";
nipkow@5646
   199
(* expand and delete abbreviations first *)
paulson@6162
   200
by (asm_simp_tac HOL_basic_ss 1);
oheimb@9147
   201
by (REPEAT (etac thin_rl 1));
nipkow@5646
   202
by (hoare_tac Asm_full_simp_tac 1);
paulson@10700
   203
    by (force_tac (claset(), simpset() addsimps [neq_Nil_conv]) 1);
paulson@6162
   204
   by (blast_tac (claset() addSEs [less_SucE] addIs [Suc_leI]) 1);
paulson@10962
   205
  by (blast_tac (claset() addSEs [less_SucE] 
paulson@10962
   206
                          addIs [less_imp_diff_less] addDs [lemma]) 1);
paulson@10700
   207
 by (force_tac (claset(), simpset() addsimps [nth_list_update]) 1);
paulson@10700
   208
by (auto_tac (claset() addIs [order_antisym], simpset()));
nipkow@5646
   209
qed "Partition";