| author | wenzelm | 
| Wed, 17 May 2006 22:34:44 +0200 | |
| changeset 19676 | 187234ec6050 | 
| parent 16731 | 124b4782944f | 
| child 19736 | d8d0f8f51d69 | 
| permissions | -rw-r--r-- | 
| 11024 | 1  | 
(* Title: HOL/ex/Primrec.thy  | 
| 3335 | 2  | 
ID: $Id$  | 
3  | 
Author: Lawrence C Paulson, Cambridge University Computer Laboratory  | 
|
4  | 
Copyright 1997 University of Cambridge  | 
|
5  | 
||
| 11024 | 6  | 
Primitive Recursive Functions. Demonstrates recursive definitions,  | 
7  | 
the TFL package.  | 
|
| 3335 | 8  | 
*)  | 
9  | 
||
| 11024 | 10  | 
header {* Primitive Recursive Functions *}
 | 
11  | 
||
| 16417 | 12  | 
theory Primrec imports Main begin  | 
| 11024 | 13  | 
|
14  | 
text {*
 | 
|
15  | 
Proof adopted from  | 
|
16  | 
||
17  | 
Nora Szasz, A Machine Checked Proof that Ackermann's Function is not  | 
|
18  | 
Primitive Recursive, In: Huet \& Plotkin, eds., Logical Environments  | 
|
19  | 
(CUP, 1993), 317-338.  | 
|
20  | 
||
21  | 
See also E. Mendelson, Introduction to Mathematical Logic. (Van  | 
|
22  | 
Nostrand, 1964), page 250, exercise 11.  | 
|
23  | 
\medskip  | 
|
24  | 
*}  | 
|
25  | 
||
26  | 
consts ack :: "nat * nat => nat"  | 
|
27  | 
recdef ack "less_than <*lex*> less_than"  | 
|
28  | 
"ack (0, n) = Suc n"  | 
|
29  | 
"ack (Suc m, 0) = ack (m, 1)"  | 
|
30  | 
"ack (Suc m, Suc n) = ack (m, ack (Suc m, n))"  | 
|
31  | 
||
32  | 
consts list_add :: "nat list => nat"  | 
|
33  | 
primrec  | 
|
34  | 
"list_add [] = 0"  | 
|
35  | 
"list_add (m # ms) = m + list_add ms"  | 
|
36  | 
||
37  | 
consts zeroHd :: "nat list => nat"  | 
|
38  | 
primrec  | 
|
39  | 
"zeroHd [] = 0"  | 
|
40  | 
"zeroHd (m # ms) = m"  | 
|
41  | 
||
42  | 
||
43  | 
text {* The set of primitive recursive functions of type @{typ "nat list => nat"}. *}
 | 
|
44  | 
||
45  | 
constdefs  | 
|
46  | 
SC :: "nat list => nat"  | 
|
47  | 
"SC l == Suc (zeroHd l)"  | 
|
| 3335 | 48  | 
|
| 19676 | 49  | 
CONSTANT :: "nat => nat list => nat"  | 
50  | 
"CONSTANT k l == k"  | 
|
| 11024 | 51  | 
|
52  | 
PROJ :: "nat => nat list => nat"  | 
|
53  | 
"PROJ i l == zeroHd (drop i l)"  | 
|
54  | 
||
55  | 
COMP :: "(nat list => nat) => (nat list => nat) list => nat list => nat"  | 
|
56  | 
"COMP g fs l == g (map (\<lambda>f. f l) fs)"  | 
|
57  | 
||
58  | 
PREC :: "(nat list => nat) => (nat list => nat) => nat list => nat"  | 
|
59  | 
"PREC f g l ==  | 
|
60  | 
case l of  | 
|
61  | 
[] => 0  | 
|
62  | 
| x # l' => nat_rec (f l') (\<lambda>y r. g (r # y # l')) x"  | 
|
63  | 
  -- {* Note that @{term g} is applied first to @{term "PREC f g y"} and then to @{term y}! *}
 | 
|
64  | 
||
65  | 
consts PRIMREC :: "(nat list => nat) set"  | 
|
66  | 
inductive PRIMREC  | 
|
67  | 
intros  | 
|
68  | 
SC: "SC \<in> PRIMREC"  | 
|
| 19676 | 69  | 
CONSTANT: "CONSTANT k \<in> PRIMREC"  | 
| 11024 | 70  | 
PROJ: "PROJ i \<in> PRIMREC"  | 
71  | 
COMP: "g \<in> PRIMREC ==> fs \<in> lists PRIMREC ==> COMP g fs \<in> PRIMREC"  | 
|
72  | 
PREC: "f \<in> PRIMREC ==> g \<in> PRIMREC ==> PREC f g \<in> PRIMREC"  | 
|
73  | 
||
74  | 
||
75  | 
text {* Useful special cases of evaluation *}
 | 
|
76  | 
||
77  | 
lemma SC [simp]: "SC (x # l) = Suc x"  | 
|
78  | 
apply (simp add: SC_def)  | 
|
79  | 
done  | 
|
80  | 
||
| 19676 | 81  | 
lemma CONSTANT [simp]: "CONSTANT k l = k"  | 
82  | 
apply (simp add: CONSTANT_def)  | 
|
| 11024 | 83  | 
done  | 
84  | 
||
85  | 
lemma PROJ_0 [simp]: "PROJ 0 (x # l) = x"  | 
|
86  | 
apply (simp add: PROJ_def)  | 
|
87  | 
done  | 
|
88  | 
||
89  | 
lemma COMP_1 [simp]: "COMP g [f] l = g [f l]"  | 
|
90  | 
apply (simp add: COMP_def)  | 
|
91  | 
done  | 
|
| 3335 | 92  | 
|
| 11024 | 93  | 
lemma PREC_0 [simp]: "PREC f g (0 # l) = f l"  | 
94  | 
apply (simp add: PREC_def)  | 
|
95  | 
done  | 
|
96  | 
||
97  | 
lemma PREC_Suc [simp]: "PREC f g (Suc x # l) = g (PREC f g (x # l) # x # l)"  | 
|
98  | 
apply (simp add: PREC_def)  | 
|
99  | 
done  | 
|
100  | 
||
101  | 
||
102  | 
text {* PROPERTY A 4 *}
 | 
|
103  | 
||
104  | 
lemma less_ack2 [iff]: "j < ack (i, j)"  | 
|
105  | 
apply (induct i j rule: ack.induct)  | 
|
106  | 
apply simp_all  | 
|
107  | 
done  | 
|
108  | 
||
109  | 
||
110  | 
text {* PROPERTY A 5-, the single-step lemma *}
 | 
|
111  | 
||
112  | 
lemma ack_less_ack_Suc2 [iff]: "ack(i, j) < ack (i, Suc j)"  | 
|
113  | 
apply (induct i j rule: ack.induct)  | 
|
114  | 
apply simp_all  | 
|
115  | 
done  | 
|
116  | 
||
117  | 
||
118  | 
text {* PROPERTY A 5, monotonicity for @{text "<"} *}
 | 
|
119  | 
||
120  | 
lemma ack_less_mono2: "j < k ==> ack (i, j) < ack (i, k)"  | 
|
121  | 
apply (induct i k rule: ack.induct)  | 
|
122  | 
apply simp_all  | 
|
123  | 
apply (blast elim!: less_SucE intro: less_trans)  | 
|
124  | 
done  | 
|
125  | 
||
126  | 
||
127  | 
text {* PROPERTY A 5', monotonicity for @{text \<le>} *}
 | 
|
128  | 
||
129  | 
lemma ack_le_mono2: "j \<le> k ==> ack (i, j) \<le> ack (i, k)"  | 
|
130  | 
apply (simp add: order_le_less)  | 
|
131  | 
apply (blast intro: ack_less_mono2)  | 
|
132  | 
done  | 
|
| 3335 | 133  | 
|
| 11024 | 134  | 
|
135  | 
text {* PROPERTY A 6 *}
 | 
|
136  | 
||
137  | 
lemma ack2_le_ack1 [iff]: "ack (i, Suc j) \<le> ack (Suc i, j)"  | 
|
138  | 
apply (induct j)  | 
|
139  | 
apply simp_all  | 
|
140  | 
apply (blast intro: ack_le_mono2 less_ack2 [THEN Suc_leI] le_trans)  | 
|
141  | 
done  | 
|
142  | 
||
143  | 
||
144  | 
text {* PROPERTY A 7-, the single-step lemma *}
 | 
|
145  | 
||
146  | 
lemma ack_less_ack_Suc1 [iff]: "ack (i, j) < ack (Suc i, j)"  | 
|
147  | 
apply (blast intro: ack_less_mono2 less_le_trans)  | 
|
148  | 
done  | 
|
149  | 
||
150  | 
||
| 19676 | 151  | 
text {* PROPERTY A 4'? Extra lemma needed for @{term CONSTANT} case, constant functions *}
 | 
| 11024 | 152  | 
|
153  | 
lemma less_ack1 [iff]: "i < ack (i, j)"  | 
|
154  | 
apply (induct i)  | 
|
155  | 
apply simp_all  | 
|
156  | 
apply (blast intro: Suc_leI le_less_trans)  | 
|
157  | 
done  | 
|
158  | 
||
159  | 
||
160  | 
text {* PROPERTY A 8 *}
 | 
|
161  | 
||
| 
11704
 
3c50a2cd6f00
* sane numerals (stage 2): plain "num" syntax (removed "#");
 
wenzelm 
parents: 
11701 
diff
changeset
 | 
162  | 
lemma ack_1 [simp]: "ack (Suc 0, j) = j + 2"  | 
| 11024 | 163  | 
apply (induct j)  | 
164  | 
apply simp_all  | 
|
165  | 
done  | 
|
166  | 
||
167  | 
||
| 
11701
 
3d51fbf81c17
sane numerals (stage 1): added generic 1, removed 1' and 2 on nat,
 
wenzelm 
parents: 
11464 
diff
changeset
 | 
168  | 
text {* PROPERTY A 9.  The unary @{text 1} and @{text 2} in @{term
 | 
| 11024 | 169  | 
ack} is essential for the rewriting. *}  | 
170  | 
||
| 
11704
 
3c50a2cd6f00
* sane numerals (stage 2): plain "num" syntax (removed "#");
 
wenzelm 
parents: 
11701 
diff
changeset
 | 
171  | 
lemma ack_2 [simp]: "ack (Suc (Suc 0), j) = 2 * j + 3"  | 
| 11024 | 172  | 
apply (induct j)  | 
173  | 
apply simp_all  | 
|
174  | 
done  | 
|
| 3335 | 175  | 
|
176  | 
||
| 11024 | 177  | 
text {* PROPERTY A 7, monotonicity for @{text "<"} [not clear why
 | 
178  | 
  @{thm [source] ack_1} is now needed first!] *}
 | 
|
179  | 
||
180  | 
lemma ack_less_mono1_aux: "ack (i, k) < ack (Suc (i +i'), k)"  | 
|
181  | 
apply (induct i k rule: ack.induct)  | 
|
182  | 
apply simp_all  | 
|
183  | 
prefer 2  | 
|
184  | 
apply (blast intro: less_trans ack_less_mono2)  | 
|
185  | 
apply (induct_tac i' n rule: ack.induct)  | 
|
186  | 
apply simp_all  | 
|
187  | 
apply (blast intro: Suc_leI [THEN le_less_trans] ack_less_mono2)  | 
|
188  | 
done  | 
|
189  | 
||
190  | 
lemma ack_less_mono1: "i < j ==> ack (i, k) < ack (j, k)"  | 
|
191  | 
apply (drule less_imp_Suc_add)  | 
|
192  | 
apply (blast intro!: ack_less_mono1_aux)  | 
|
193  | 
done  | 
|
194  | 
||
195  | 
||
196  | 
text {* PROPERTY A 7', monotonicity for @{text "\<le>"} *}
 | 
|
197  | 
||
198  | 
lemma ack_le_mono1: "i \<le> j ==> ack (i, k) \<le> ack (j, k)"  | 
|
199  | 
apply (simp add: order_le_less)  | 
|
200  | 
apply (blast intro: ack_less_mono1)  | 
|
201  | 
done  | 
|
202  | 
||
203  | 
||
204  | 
text {* PROPERTY A 10 *}
 | 
|
205  | 
||
| 
11704
 
3c50a2cd6f00
* sane numerals (stage 2): plain "num" syntax (removed "#");
 
wenzelm 
parents: 
11701 
diff
changeset
 | 
206  | 
lemma ack_nest_bound: "ack(i1, ack (i2, j)) < ack (2 + (i1 + i2), j)"  | 
| 11024 | 207  | 
apply (simp add: numerals)  | 
208  | 
apply (rule ack2_le_ack1 [THEN [2] less_le_trans])  | 
|
209  | 
apply simp  | 
|
210  | 
apply (rule le_add1 [THEN ack_le_mono1, THEN le_less_trans])  | 
|
211  | 
apply (rule ack_less_mono1 [THEN ack_less_mono2])  | 
|
212  | 
apply (simp add: le_imp_less_Suc le_add2)  | 
|
213  | 
done  | 
|
214  | 
||
| 3335 | 215  | 
|
| 11024 | 216  | 
text {* PROPERTY A 11 *}
 | 
| 3335 | 217  | 
|
| 
11704
 
3c50a2cd6f00
* sane numerals (stage 2): plain "num" syntax (removed "#");
 
wenzelm 
parents: 
11701 
diff
changeset
 | 
218  | 
lemma ack_add_bound: "ack (i1, j) + ack (i2, j) < ack (4 + (i1 + i2), j)"  | 
| 
11701
 
3d51fbf81c17
sane numerals (stage 1): added generic 1, removed 1' and 2 on nat,
 
wenzelm 
parents: 
11464 
diff
changeset
 | 
219  | 
apply (rule_tac j = "ack (Suc (Suc 0), ack (i1 + i2, j))" in less_trans)  | 
| 11024 | 220  | 
prefer 2  | 
221  | 
apply (rule ack_nest_bound [THEN less_le_trans])  | 
|
222  | 
apply (simp add: Suc3_eq_add_3)  | 
|
223  | 
apply simp  | 
|
224  | 
apply (cut_tac i = i1 and m1 = i2 and k = j in le_add1 [THEN ack_le_mono1])  | 
|
225  | 
apply (cut_tac i = "i2" and m1 = i1 and k = j in le_add2 [THEN ack_le_mono1])  | 
|
226  | 
apply auto  | 
|
227  | 
done  | 
|
228  | 
||
229  | 
||
230  | 
text {* PROPERTY A 12.  Article uses existential quantifier but the ALF proof
 | 
|
231  | 
  used @{text "k + 4"}.  Quantified version must be nested @{text
 | 
|
232  | 
"\<exists>k'. \<forall>i j. ..."} *}  | 
|
| 3335 | 233  | 
|
| 
11704
 
3c50a2cd6f00
* sane numerals (stage 2): plain "num" syntax (removed "#");
 
wenzelm 
parents: 
11701 
diff
changeset
 | 
234  | 
lemma ack_add_bound2: "i < ack (k, j) ==> i + j < ack (4 + k, j)"  | 
| 11024 | 235  | 
apply (rule_tac j = "ack (k, j) + ack (0, j)" in less_trans)  | 
236  | 
prefer 2  | 
|
237  | 
apply (rule ack_add_bound [THEN less_le_trans])  | 
|
238  | 
apply simp  | 
|
239  | 
apply (rule add_less_mono less_ack2 | assumption)+  | 
|
240  | 
done  | 
|
241  | 
||
242  | 
||
243  | 
||
244  | 
text {* Inductive definition of the @{term PR} functions *}
 | 
|
| 3335 | 245  | 
|
| 11024 | 246  | 
text {* MAIN RESULT *}
 | 
247  | 
||
248  | 
lemma SC_case: "SC l < ack (1, list_add l)"  | 
|
249  | 
apply (unfold SC_def)  | 
|
250  | 
apply (induct l)  | 
|
251  | 
apply (simp_all add: le_add1 le_imp_less_Suc)  | 
|
252  | 
done  | 
|
253  | 
||
| 19676 | 254  | 
lemma CONSTANT_case: "CONSTANT k l < ack (k, list_add l)"  | 
| 11024 | 255  | 
apply simp  | 
256  | 
done  | 
|
| 3335 | 257  | 
|
| 11024 | 258  | 
lemma PROJ_case [rule_format]: "\<forall>i. PROJ i l < ack (0, list_add l)"  | 
259  | 
apply (simp add: PROJ_def)  | 
|
260  | 
apply (induct l)  | 
|
261  | 
apply simp_all  | 
|
262  | 
apply (rule allI)  | 
|
263  | 
apply (case_tac i)  | 
|
264  | 
apply (simp (no_asm_simp) add: le_add1 le_imp_less_Suc)  | 
|
265  | 
apply (simp (no_asm_simp))  | 
|
266  | 
apply (blast intro: less_le_trans intro!: le_add2)  | 
|
267  | 
done  | 
|
268  | 
||
269  | 
||
270  | 
text {* @{term COMP} case *}
 | 
|
| 3335 | 271  | 
|
| 11024 | 272  | 
lemma COMP_map_aux: "fs \<in> lists (PRIMREC \<inter> {f. \<exists>kf. \<forall>l. f l < ack (kf, list_add l)})
 | 
273  | 
==> \<exists>k. \<forall>l. list_add (map (\<lambda>f. f l) fs) < ack (k, list_add l)"  | 
|
274  | 
apply (erule lists.induct)  | 
|
275  | 
apply (rule_tac x = 0 in exI)  | 
|
276  | 
apply simp  | 
|
277  | 
apply safe  | 
|
278  | 
apply simp  | 
|
279  | 
apply (rule exI)  | 
|
280  | 
apply (blast intro: add_less_mono ack_add_bound less_trans)  | 
|
281  | 
done  | 
|
282  | 
||
283  | 
lemma COMP_case:  | 
|
284  | 
"\<forall>l. g l < ack (kg, list_add l) ==>  | 
|
285  | 
  fs \<in> lists(PRIMREC Int {f. \<exists>kf. \<forall>l. f l < ack(kf, list_add l)})
 | 
|
286  | 
==> \<exists>k. \<forall>l. COMP g fs l < ack(k, list_add l)"  | 
|
287  | 
apply (unfold COMP_def)  | 
|
288  | 
apply (frule Int_lower1 [THEN lists_mono, THEN subsetD])  | 
|
| 16588 | 289  | 
    --{*Now, if meson tolerated map, we could finish with
 | 
| 16731 | 290  | 
  @{text "(drule COMP_map_aux, meson ack_less_mono2 ack_nest_bound less_trans)"} *}
 | 
| 16588 | 291  | 
apply (erule COMP_map_aux [THEN exE])  | 
292  | 
apply (rule exI)  | 
|
293  | 
apply (rule allI)  | 
|
294  | 
apply (drule spec)+  | 
|
295  | 
apply (erule less_trans)  | 
|
296  | 
apply (blast intro: ack_less_mono2 ack_nest_bound less_trans)  | 
|
| 11024 | 297  | 
done  | 
298  | 
||
299  | 
||
300  | 
text {* @{term PREC} case *}
 | 
|
| 3335 | 301  | 
|
| 11024 | 302  | 
lemma PREC_case_aux:  | 
303  | 
"\<forall>l. f l + list_add l < ack (kf, list_add l) ==>  | 
|
304  | 
\<forall>l. g l + list_add l < ack (kg, list_add l) ==>  | 
|
305  | 
PREC f g l + list_add l < ack (Suc (kf + kg), list_add l)"  | 
|
306  | 
apply (unfold PREC_def)  | 
|
307  | 
apply (case_tac l)  | 
|
308  | 
apply simp_all  | 
|
309  | 
apply (blast intro: less_trans)  | 
|
310  | 
  apply (erule ssubst) -- {* get rid of the needless assumption *}
 | 
|
311  | 
apply (induct_tac a)  | 
|
312  | 
apply simp_all  | 
|
313  | 
   txt {* base case *}
 | 
|
314  | 
apply (blast intro: le_add1 [THEN le_imp_less_Suc, THEN ack_less_mono1] less_trans)  | 
|
315  | 
  txt {* induction step *}
 | 
|
316  | 
apply (rule Suc_leI [THEN le_less_trans])  | 
|
317  | 
apply (rule le_refl [THEN add_le_mono, THEN le_less_trans])  | 
|
318  | 
prefer 2  | 
|
319  | 
apply (erule spec)  | 
|
320  | 
apply (simp add: le_add2)  | 
|
321  | 
  txt {* final part of the simplification *}
 | 
|
322  | 
apply simp  | 
|
323  | 
apply (rule le_add2 [THEN ack_le_mono1, THEN le_less_trans])  | 
|
324  | 
apply (erule ack_less_mono2)  | 
|
325  | 
done  | 
|
326  | 
||
327  | 
lemma PREC_case:  | 
|
328  | 
"\<forall>l. f l < ack (kf, list_add l) ==>  | 
|
329  | 
\<forall>l. g l < ack (kg, list_add l) ==>  | 
|
330  | 
\<exists>k. \<forall>l. PREC f g l < ack (k, list_add l)"  | 
|
331  | 
apply (rule exI)  | 
|
332  | 
apply (rule allI)  | 
|
333  | 
apply (rule le_less_trans [OF le_add1 PREC_case_aux])  | 
|
334  | 
apply (blast intro: ack_add_bound2)+  | 
|
335  | 
done  | 
|
336  | 
||
337  | 
lemma ack_bounds_PRIMREC: "f \<in> PRIMREC ==> \<exists>k. \<forall>l. f l < ack (k, list_add l)"  | 
|
338  | 
apply (erule PRIMREC.induct)  | 
|
| 19676 | 339  | 
apply (blast intro: SC_case CONSTANT_case PROJ_case COMP_case PREC_case)+  | 
| 11024 | 340  | 
done  | 
341  | 
||
342  | 
lemma ack_not_PRIMREC: "(\<lambda>l. case l of [] => 0 | x # l' => ack (x, x)) \<notin> PRIMREC"  | 
|
343  | 
apply (rule notI)  | 
|
344  | 
apply (erule ack_bounds_PRIMREC [THEN exE])  | 
|
345  | 
apply (rule less_irrefl)  | 
|
346  | 
apply (drule_tac x = "[x]" in spec)  | 
|
347  | 
apply simp  | 
|
348  | 
done  | 
|
| 3335 | 349  | 
|
350  | 
end  |