| author | nipkow | 
| Thu, 16 Nov 2023 14:33:45 +0100 | |
| changeset 78977 | c7db5b4dbace | 
| parent 72990 | db8f94656024 | 
| child 81195 | 8bcb906e73f2 | 
| permissions | -rw-r--r-- | 
| 1476 | 1  | 
(* Title: HOL/Hoare/Examples.thy  | 
2  | 
Author: Norbert Galm  | 
|
| 5646 | 3  | 
Copyright 1998 TUM  | 
| 67410 | 4  | 
*)  | 
| 1335 | 5  | 
|
| 72990 | 6  | 
section \<open>Various examples\<close>  | 
| 13682 | 7  | 
|
| 72990 | 8  | 
theory Examples  | 
9  | 
imports Hoare_Logic Arith2  | 
|
10  | 
begin  | 
|
| 13682 | 11  | 
|
| 72990 | 12  | 
subsection \<open>Arithmetic\<close>  | 
13  | 
||
14  | 
subsubsection \<open>Multiplication by successive addition\<close>  | 
|
| 13682 | 15  | 
|
| 13737 | 16  | 
lemma multiply_by_add: "VARS m s a b  | 
| 67613 | 17  | 
  {a=A \<and> b=B}
 | 
| 13682 | 18  | 
m := 0; s := 0;  | 
| 67613 | 19  | 
WHILE m\<noteq>a  | 
20  | 
  INV {s=m*b \<and> a=A \<and> b=B}
 | 
|
| 13682 | 21  | 
DO s := s+b; m := m+(1::nat) OD  | 
22  | 
  {s = A*B}"
 | 
|
23  | 
by vcg_simp  | 
|
24  | 
||
| 63106 | 25  | 
lemma multiply_by_add_time: "VARS m s a b t  | 
| 67613 | 26  | 
  {a=A \<and> b=B \<and> t=0}
 | 
| 63106 | 27  | 
m := 0; t := t+1; s := 0; t := t+1;  | 
| 67613 | 28  | 
WHILE m\<noteq>a  | 
29  | 
  INV {s=m*b \<and> a=A \<and> b=B \<and> t = 2*m + 2}
 | 
|
| 63106 | 30  | 
DO s := s+b; t := t+1; m := m+(1::nat); t := t+1 OD  | 
31  | 
  {s = A*B \<and> t = 2*A + 2}"
 | 
|
32  | 
by vcg_simp  | 
|
33  | 
||
34  | 
lemma multiply_by_add2: "VARS M N P :: int  | 
|
| 67613 | 35  | 
 {m=M \<and> n=N}
 | 
| 13789 | 36  | 
IF M < 0 THEN M := -M; N := -N ELSE SKIP FI;  | 
37  | 
P := 0;  | 
|
38  | 
WHILE 0 < M  | 
|
| 67613 | 39  | 
 INV {0 \<le> M \<and> (\<exists>p. p = (if m<0 then -m else m) & p*N = m*n & P = (p-M)*N)}
 | 
| 13789 | 40  | 
DO P := P+N; M := M - 1 OD  | 
41  | 
 {P = m*n}"
 | 
|
42  | 
apply vcg_simp  | 
|
| 63106 | 43  | 
apply (auto simp add:int_distrib)  | 
44  | 
done  | 
|
45  | 
||
46  | 
lemma multiply_by_add2_time: "VARS M N P t :: int  | 
|
| 67613 | 47  | 
 {m=M \<and> n=N \<and> t=0}
 | 
| 63106 | 48  | 
IF M < 0 THEN M := -M; t := t+1; N := -N; t := t+1 ELSE SKIP FI;  | 
49  | 
P := 0; t := t+1;  | 
|
50  | 
WHILE 0 < M  | 
|
| 67613 | 51  | 
 INV {0 \<le> M & (\<exists>p. p = (if m<0 then -m else m) & p*N = m*n & P = (p-M)*N & t \<ge> 0 & t \<le> 2*(p-M)+3)}
 | 
| 63106 | 52  | 
DO P := P+N; t := t+1; M := M - 1; t := t+1 OD  | 
53  | 
 {P = m*n & t \<le> 2*abs m + 3}"
 | 
|
54  | 
apply vcg_simp  | 
|
55  | 
apply (auto simp add:int_distrib)  | 
|
| 13789 | 56  | 
done  | 
| 13682 | 57  | 
|
| 67410 | 58  | 
|
| 72990 | 59  | 
subsubsection \<open>Euclid's algorithm for GCD\<close>  | 
| 13682 | 60  | 
|
| 13737 | 61  | 
lemma Euclid_GCD: "VARS a b  | 
| 13682 | 62  | 
 {0<A & 0<B}
 | 
63  | 
a := A; b := B;  | 
|
| 13857 | 64  | 
WHILE a \<noteq> b  | 
| 13682 | 65  | 
 INV {0<a & 0<b & gcd A B = gcd a b}
 | 
66  | 
DO IF a<b THEN b := b-a ELSE a := a-b FI OD  | 
|
67  | 
 {a = gcd A B}"
 | 
|
68  | 
apply vcg  | 
|
| 67410 | 69  | 
\<comment> \<open>Now prove the verification conditions\<close>  | 
| 13682 | 70  | 
apply auto  | 
71  | 
apply(simp add: gcd_diff_r less_imp_le)  | 
|
| 16796 | 72  | 
apply(simp add: linorder_not_less gcd_diff_l)  | 
| 13682 | 73  | 
apply(erule gcd_nnn)  | 
74  | 
done  | 
|
75  | 
||
| 63106 | 76  | 
lemma Euclid_GCD_time: "VARS a b t  | 
77  | 
 {0<A & 0<B & t=0}
 | 
|
78  | 
a := A; t := t+1; b := B; t := t+1;  | 
|
79  | 
WHILE a \<noteq> b  | 
|
80  | 
 INV {0<a & 0<b & gcd A B = gcd a b & a\<le>A & b\<le>B & t \<le> max A B - max a b + 2}
 | 
|
81  | 
DO IF a<b THEN b := b-a; t := t+1 ELSE a := a-b; t := t+1 FI OD  | 
|
82  | 
 {a = gcd A B & t \<le> max A B + 2}"
 | 
|
83  | 
apply vcg  | 
|
| 67410 | 84  | 
\<comment> \<open>Now prove the verification conditions\<close>  | 
| 63106 | 85  | 
apply auto  | 
86  | 
apply(simp add: gcd_diff_r less_imp_le)  | 
|
87  | 
apply(simp add: linorder_not_less gcd_diff_l)  | 
|
88  | 
apply(erule gcd_nnn)  | 
|
89  | 
done  | 
|
90  | 
||
| 67410 | 91  | 
|
| 72990 | 92  | 
subsubsection \<open>Dijkstra's extension of Euclid's algorithm for simultaneous GCD and SCM\<close>  | 
| 67410 | 93  | 
|
94  | 
text \<open>  | 
|
95  | 
From E.W. Disjkstra. Selected Writings on Computing, p 98 (EWD474),  | 
|
96  | 
where it is given without the invariant. Instead of defining \<open>scm\<close>  | 
|
97  | 
explicitly we have used the theorem \<open>scm x y = x * y / gcd x y\<close> and avoided  | 
|
98  | 
division by mupltiplying with \<open>gcd x y\<close>.  | 
|
99  | 
\<close>  | 
|
| 13682 | 100  | 
|
101  | 
lemmas distribs =  | 
|
102  | 
diff_mult_distrib diff_mult_distrib2 add_mult_distrib add_mult_distrib2  | 
|
103  | 
||
| 13737 | 104  | 
lemma gcd_scm: "VARS a b x y  | 
| 13682 | 105  | 
 {0<A & 0<B & a=A & b=B & x=B & y=A}
 | 
106  | 
WHILE a ~= b  | 
|
107  | 
 INV {0<a & 0<b & gcd A B = gcd a b & 2*A*B = a*x + b*y}
 | 
|
108  | 
DO IF a<b THEN (b := b-a; x := x+y) ELSE (a := a-b; y := y+x) FI OD  | 
|
109  | 
 {a = gcd A B & 2*A*B = a*(x+y)}"
 | 
|
110  | 
apply vcg  | 
|
111  | 
apply simp  | 
|
| 16796 | 112  | 
apply(simp add: distribs gcd_diff_r linorder_not_less gcd_diff_l)  | 
| 13682 | 113  | 
apply(simp add: distribs gcd_nnn)  | 
114  | 
done  | 
|
115  | 
||
| 67410 | 116  | 
|
| 72990 | 117  | 
subsubsection \<open>Power by iterated squaring and multiplication\<close>  | 
| 13682 | 118  | 
|
| 13737 | 119  | 
lemma power_by_mult: "VARS a b c  | 
| 13682 | 120  | 
 {a=A & b=B}
 | 
121  | 
c := (1::nat);  | 
|
122  | 
WHILE b ~= 0  | 
|
123  | 
 INV {A^B = c * a^b}
 | 
|
124  | 
DO WHILE b mod 2 = 0  | 
|
125  | 
     INV {A^B = c * a^b}
 | 
|
126  | 
DO a := a*a; b := b div 2 OD;  | 
|
127  | 
c := c*a; b := b - 1  | 
|
128  | 
OD  | 
|
129  | 
 {c = A^B}"
 | 
|
130  | 
apply vcg_simp  | 
|
131  | 
apply(case_tac "b")  | 
|
| 42154 | 132  | 
apply simp  | 
| 13682 | 133  | 
apply simp  | 
134  | 
done  | 
|
135  | 
||
| 67410 | 136  | 
|
| 72990 | 137  | 
subsubsection \<open>Factorial\<close>  | 
| 13682 | 138  | 
|
| 13737 | 139  | 
lemma factorial: "VARS a b  | 
| 13682 | 140  | 
 {a=A}
 | 
141  | 
b := 1;  | 
|
| 63106 | 142  | 
WHILE a > 0  | 
| 13682 | 143  | 
 INV {fac A = b * fac a}
 | 
144  | 
DO b := b*a; a := a - 1 OD  | 
|
145  | 
 {b = fac A}"
 | 
|
146  | 
apply vcg_simp  | 
|
147  | 
apply(clarsimp split: nat_diff_split)  | 
|
148  | 
done  | 
|
149  | 
||
| 63106 | 150  | 
lemma factorial_time: "VARS a b t  | 
151  | 
 {a=A & t=0}
 | 
|
152  | 
b := 1; t := t+1;  | 
|
153  | 
WHILE a > 0  | 
|
154  | 
 INV {fac A = b * fac a & a \<le> A & t = 2*(A-a)+1}
 | 
|
155  | 
DO b := b*a; t := t+1; a := a - 1; t := t+1 OD  | 
|
156  | 
 {b = fac A & t = 2*A + 1}"
 | 
|
157  | 
apply vcg_simp  | 
|
158  | 
apply(clarsimp split: nat_diff_split)  | 
|
159  | 
done  | 
|
160  | 
||
| 13684 | 161  | 
lemma [simp]: "1 \<le> i \<Longrightarrow> fac (i - Suc 0) * i = fac i"  | 
162  | 
by(induct i, simp_all)  | 
|
163  | 
||
| 63106 | 164  | 
lemma factorial2: "VARS i f  | 
| 13684 | 165  | 
 {True}
 | 
166  | 
i := (1::nat); f := 1;  | 
|
167  | 
 WHILE i <= n INV {f = fac(i - 1) & 1 <= i & i <= n+1}
 | 
|
168  | 
DO f := f*i; i := i+1 OD  | 
|
169  | 
 {f = fac n}"
 | 
|
170  | 
apply vcg_simp  | 
|
171  | 
apply(subgoal_tac "i = Suc n")  | 
|
172  | 
apply simp  | 
|
173  | 
apply arith  | 
|
174  | 
done  | 
|
| 13682 | 175  | 
|
| 63106 | 176  | 
lemma factorial2_time: "VARS i f t  | 
177  | 
 {t=0}
 | 
|
178  | 
i := (1::nat); t := t+1; f := 1; t := t+1;  | 
|
179  | 
 WHILE i \<le> n INV {f = fac(i - 1) & 1 \<le> i & i \<le> n+1 & t = 2*(i-1)+2}
 | 
|
180  | 
DO f := f*i; t := t+1; i := i+1; t := t+1 OD  | 
|
181  | 
 {f = fac n & t = 2*n+2}"
 | 
|
182  | 
apply vcg_simp  | 
|
183  | 
apply auto  | 
|
184  | 
apply(subgoal_tac "i = Suc n")  | 
|
185  | 
apply simp  | 
|
186  | 
apply arith  | 
|
187  | 
done  | 
|
188  | 
||
| 13682 | 189  | 
|
| 72990 | 190  | 
subsubsection \<open>Square root\<close>  | 
| 67410 | 191  | 
|
192  | 
\<comment> \<open>the easy way:\<close>  | 
|
| 13682 | 193  | 
|
| 13737 | 194  | 
lemma sqrt: "VARS r x  | 
| 13682 | 195  | 
 {True}
 | 
| 63106 | 196  | 
r := (0::nat);  | 
197  | 
WHILE (r+1)*(r+1) <= X  | 
|
198  | 
 INV {r*r \<le> X}
 | 
|
| 13682 | 199  | 
DO r := r+1 OD  | 
200  | 
 {r*r <= X & X < (r+1)*(r+1)}"
 | 
|
201  | 
apply vcg_simp  | 
|
202  | 
done  | 
|
203  | 
||
| 63106 | 204  | 
lemma sqrt_time: "VARS r t  | 
205  | 
 {t=0}
 | 
|
206  | 
r := (0::nat); t := t+1;  | 
|
207  | 
WHILE (r+1)*(r+1) <= X  | 
|
208  | 
 INV {r*r \<le> X & t = r+1}
 | 
|
209  | 
DO r := r+1; t := t+1 OD  | 
|
210  | 
 {r*r <= X & X < (r+1)*(r+1) & (t-1)*(t-1) \<le> X}"
 | 
|
211  | 
apply vcg_simp  | 
|
212  | 
done  | 
|
213  | 
||
| 67410 | 214  | 
\<comment> \<open>without multiplication\<close>  | 
| 63106 | 215  | 
lemma sqrt_without_multiplication: "VARS u w r  | 
216  | 
 {x=X}
 | 
|
217  | 
u := 1; w := 1; r := (0::nat);  | 
|
218  | 
WHILE w <= X  | 
|
219  | 
 INV {u = r+r+1 & w = (r+1)*(r+1) & r*r <= X}
 | 
|
| 13682 | 220  | 
DO r := r + 1; w := w + u + 2; u := u + 2 OD  | 
221  | 
 {r*r <= X & X < (r+1)*(r+1)}"
 | 
|
222  | 
apply vcg_simp  | 
|
223  | 
done  | 
|
224  | 
||
225  | 
||
| 72990 | 226  | 
subsection \<open>Lists\<close>  | 
| 13682 | 227  | 
|
| 13737 | 228  | 
lemma imperative_reverse: "VARS y x  | 
| 13682 | 229  | 
 {x=X}
 | 
230  | 
y:=[];  | 
|
231  | 
WHILE x ~= []  | 
|
232  | 
 INV {rev(x)@y = rev(X)}
 | 
|
233  | 
DO y := (hd x # y); x := tl x OD  | 
|
234  | 
 {y=rev(X)}"
 | 
|
235  | 
apply vcg_simp  | 
|
236  | 
apply(simp add: neq_Nil_conv)  | 
|
237  | 
apply auto  | 
|
238  | 
done  | 
|
239  | 
||
| 63106 | 240  | 
lemma imperative_reverse_time: "VARS y x t  | 
241  | 
 {x=X & t=0}
 | 
|
242  | 
y:=[]; t := t+1;  | 
|
243  | 
WHILE x ~= []  | 
|
244  | 
 INV {rev(x)@y = rev(X) & t = 2*(length y) + 1}
 | 
|
245  | 
DO y := (hd x # y); t := t+1; x := tl x; t := t+1 OD  | 
|
246  | 
 {y=rev(X) & t = 2*length X + 1}"
 | 
|
247  | 
apply vcg_simp  | 
|
248  | 
apply(simp add: neq_Nil_conv)  | 
|
249  | 
apply auto  | 
|
250  | 
done  | 
|
251  | 
||
| 13737 | 252  | 
lemma imperative_append: "VARS x y  | 
| 13682 | 253  | 
 {x=X & y=Y}
 | 
254  | 
x := rev(x);  | 
|
255  | 
WHILE x~=[]  | 
|
256  | 
 INV {rev(x)@y = X@Y}
 | 
|
257  | 
DO y := (hd x # y);  | 
|
258  | 
x := tl x  | 
|
259  | 
OD  | 
|
260  | 
 {y = X@Y}"
 | 
|
261  | 
apply vcg_simp  | 
|
262  | 
apply(simp add: neq_Nil_conv)  | 
|
263  | 
apply auto  | 
|
264  | 
done  | 
|
265  | 
||
| 63106 | 266  | 
lemma imperative_append_time_no_rev: "VARS x y t  | 
267  | 
 {x=X & y=Y}
 | 
|
268  | 
x := rev(x); t := 0;  | 
|
269  | 
WHILE x~=[]  | 
|
270  | 
 INV {rev(x)@y = X@Y & length x \<le> length X & t = 2 * (length X - length x)}
 | 
|
271  | 
DO y := (hd x # y); t := t+1;  | 
|
272  | 
x := tl x; t := t+1  | 
|
273  | 
OD  | 
|
274  | 
 {y = X@Y & t = 2 * length X}"
 | 
|
275  | 
apply vcg_simp  | 
|
276  | 
apply(simp add: neq_Nil_conv)  | 
|
277  | 
apply auto  | 
|
278  | 
done  | 
|
279  | 
||
| 13682 | 280  | 
|
| 72990 | 281  | 
subsection \<open>Arrays\<close>  | 
| 13682 | 282  | 
|
| 72990 | 283  | 
subsubsection \<open>Search for a key\<close>  | 
| 67410 | 284  | 
|
| 13737 | 285  | 
lemma zero_search: "VARS A i  | 
| 13682 | 286  | 
 {True}
 | 
287  | 
i := 0;  | 
|
| 67613 | 288  | 
WHILE i < length A & A!i \<noteq> key  | 
289  | 
 INV {\<forall>j. j<i --> A!j \<noteq> key}
 | 
|
| 13682 | 290  | 
DO i := i+1 OD  | 
291  | 
 {(i < length A --> A!i = key) &
 | 
|
| 67613 | 292  | 
(i = length A --> (\<forall>j. j < length A \<longrightarrow> A!j \<noteq> key))}"  | 
| 13682 | 293  | 
apply vcg_simp  | 
294  | 
apply(blast elim!: less_SucE)  | 
|
295  | 
done  | 
|
296  | 
||
| 63106 | 297  | 
lemma zero_search_time: "VARS A i t  | 
298  | 
 {t=0}
 | 
|
299  | 
i := 0; t := t+1;  | 
|
| 67613 | 300  | 
WHILE i < length A \<and> A!i \<noteq> key  | 
301  | 
 INV {(\<forall>j. j<i \<longrightarrow> A!j \<noteq> key) \<and> i \<le> length A \<and> t = i+1}
 | 
|
| 63106 | 302  | 
DO i := i+1; t := t+1 OD  | 
| 67613 | 303  | 
 {(i < length A \<longrightarrow> A!i = key) \<and>
 | 
304  | 
(i = length A \<longrightarrow> (\<forall>j. j < length A --> A!j \<noteq> key)) \<and> t \<le> length A + 1}"  | 
|
| 63106 | 305  | 
apply vcg_simp  | 
306  | 
apply(blast elim!: less_SucE)  | 
|
307  | 
done  | 
|
308  | 
||
| 67410 | 309  | 
text \<open>  | 
310  | 
The \<open>partition\<close> procedure for quicksort.  | 
|
311  | 
\<^item> \<open>A\<close> is the array to be sorted (modelled as a list).  | 
|
312  | 
\<^item> Elements of \<open>A\<close> must be of class order to infer at the end  | 
|
313  | 
that the elements between u and l are equal to pivot.  | 
|
| 13682 | 314  | 
|
| 67410 | 315  | 
Ambiguity warnings of parser are due to \<open>:=\<close> being used  | 
316  | 
both for assignment and list update.  | 
|
317  | 
\<close>  | 
|
| 13682 | 318  | 
lemma lem: "m - Suc 0 < n ==> m < Suc n"  | 
319  | 
by arith  | 
|
320  | 
||
321  | 
||
322  | 
lemma Partition:  | 
|
| 67613 | 323  | 
"[| leq == \<lambda>A i. \<forall>k. k<i \<longrightarrow> A!k \<le> pivot;  | 
324  | 
geq == \<lambda>A i. \<forall>k. i<k \<and> k<length A \<longrightarrow> pivot \<le> A!k |] ==>  | 
|
| 13737 | 325  | 
VARS A u l  | 
| 13682 | 326  | 
 {0 < length(A::('a::order)list)}
 | 
327  | 
l := 0; u := length A - Suc 0;  | 
|
| 67613 | 328  | 
WHILE l \<le> u  | 
329  | 
  INV {leq A l \<and> geq A u \<and> u<length A \<and> l\<le>length A}
 | 
|
330  | 
DO WHILE l < length A \<and> A!l \<le> pivot  | 
|
331  | 
     INV {leq A l & geq A u \<and> u<length A \<and> l\<le>length A}
 | 
|
| 13682 | 332  | 
DO l := l+1 OD;  | 
| 67613 | 333  | 
WHILE 0 < u & pivot \<le> A!u  | 
334  | 
     INV {leq A l & geq A u  \<and> u<length A \<and> l\<le>length A}
 | 
|
| 13682 | 335  | 
DO u := u - 1 OD;  | 
| 67613 | 336  | 
IF l \<le> u THEN A := A[l := A!u, u := A!l] ELSE SKIP FI  | 
| 13682 | 337  | 
OD  | 
| 67613 | 338  | 
 {leq A u & (\<forall>k. u<k \<and> k<l --> A!k = pivot) \<and> geq A l}"
 | 
| 67410 | 339  | 
\<comment> \<open>expand and delete abbreviations first\<close>  | 
| 58860 | 340  | 
apply (simp)  | 
| 13682 | 341  | 
apply (erule thin_rl)+  | 
342  | 
apply vcg_simp  | 
|
| 
16733
 
236dfafbeb63
linear arithmetic now takes "&" in assumptions apart.
 
nipkow 
parents: 
16417 
diff
changeset
 | 
343  | 
apply (force simp: neq_Nil_conv)  | 
| 
 
236dfafbeb63
linear arithmetic now takes "&" in assumptions apart.
 
nipkow 
parents: 
16417 
diff
changeset
 | 
344  | 
apply (blast elim!: less_SucE intro: Suc_leI)  | 
| 
 
236dfafbeb63
linear arithmetic now takes "&" in assumptions apart.
 
nipkow 
parents: 
16417 
diff
changeset
 | 
345  | 
apply (blast elim!: less_SucE intro: less_imp_diff_less dest: lem)  | 
| 
 
236dfafbeb63
linear arithmetic now takes "&" in assumptions apart.
 
nipkow 
parents: 
16417 
diff
changeset
 | 
346  | 
apply (force simp: nth_list_update)  | 
| 13682 | 347  | 
done  | 
348  | 
||
| 62390 | 349  | 
end  |