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";
|