| author | popescua | 
| Tue, 28 May 2013 13:22:06 +0200 | |
| changeset 52200 | 6324f30e23b6 | 
| parent 35762 | af3ff2ba4c54 | 
| child 58623 | 2db1df2c8467 | 
| permissions | -rw-r--r-- | 
| 12560 | 1 | (* Title: ZF/Induct/Primrec.thy | 
| 12088 | 2 | Author: Lawrence C Paulson, Cambridge University Computer Laboratory | 
| 3 | Copyright 1994 University of Cambridge | |
| 12610 | 4 | *) | 
| 12088 | 5 | |
| 12610 | 6 | header {* Primitive Recursive Functions: the inductive definition *}
 | 
| 12088 | 7 | |
| 16417 | 8 | theory Primrec imports Main begin | 
| 12560 | 9 | |
| 12610 | 10 | text {*
 | 
| 11 |   Proof adopted from \cite{szasz}.
 | |
| 12 | ||
| 13 |   See also \cite[page 250, exercise 11]{mendelson}.
 | |
| 14 | *} | |
| 15 | ||
| 16 | ||
| 17 | subsection {* Basic definitions *}
 | |
| 18 | ||
| 24893 | 19 | definition | 
| 20 | SC :: "i" where | |
| 12610 | 21 | "SC == \<lambda>l \<in> list(nat). list_case(0, \<lambda>x xs. succ(x), l)" | 
| 12560 | 22 | |
| 24893 | 23 | definition | 
| 24 | CONSTANT :: "i=>i" where | |
| 19676 | 25 | "CONSTANT(k) == \<lambda>l \<in> list(nat). k" | 
| 12560 | 26 | |
| 24893 | 27 | definition | 
| 28 | PROJ :: "i=>i" where | |
| 12610 | 29 | "PROJ(i) == \<lambda>l \<in> list(nat). list_case(0, \<lambda>x xs. x, drop(i,l))" | 
| 12560 | 30 | |
| 24893 | 31 | definition | 
| 32 | COMP :: "[i,i]=>i" where | |
| 26059 | 33 | "COMP(g,fs) == \<lambda>l \<in> list(nat). g ` map(\<lambda>f. f`l, fs)" | 
| 12610 | 34 | |
| 24893 | 35 | definition | 
| 36 | PREC :: "[i,i]=>i" where | |
| 12610 | 37 | "PREC(f,g) == | 
| 38 | \<lambda>l \<in> list(nat). list_case(0, | |
| 39 | \<lambda>x xs. rec(x, f`xs, \<lambda>y r. g ` Cons(r, Cons(y, xs))), l)" | |
| 40 |   -- {* Note that @{text g} is applied first to @{term "PREC(f,g)`y"} and then to @{text y}! *}
 | |
| 12560 | 41 | |
| 12088 | 42 | consts | 
| 12610 | 43 | ACK :: "i=>i" | 
| 12560 | 44 | primrec | 
| 12610 | 45 | "ACK(0) = SC" | 
| 19676 | 46 | "ACK(succ(i)) = PREC (CONSTANT (ACK(i) ` [1]), COMP(ACK(i), [PROJ(0)]))" | 
| 12560 | 47 | |
| 24892 | 48 | abbreviation | 
| 49 | ack :: "[i,i]=>i" where | |
| 50 | "ack(x,y) == ACK(x) ` [y]" | |
| 12560 | 51 | |
| 52 | ||
| 12610 | 53 | text {*
 | 
| 54 | \medskip Useful special cases of evaluation. | |
| 55 | *} | |
| 12560 | 56 | |
| 57 | lemma SC: "[| x \<in> nat; l \<in> list(nat) |] ==> SC ` (Cons(x,l)) = succ(x)" | |
| 12610 | 58 | by (simp add: SC_def) | 
| 12560 | 59 | |
| 19676 | 60 | lemma CONSTANT: "l \<in> list(nat) ==> CONSTANT(k) ` l = k" | 
| 61 | by (simp add: CONSTANT_def) | |
| 12560 | 62 | |
| 63 | lemma PROJ_0: "[| x \<in> nat; l \<in> list(nat) |] ==> PROJ(0) ` (Cons(x,l)) = x" | |
| 12610 | 64 | by (simp add: PROJ_def) | 
| 12560 | 65 | |
| 66 | lemma COMP_1: "l \<in> list(nat) ==> COMP(g,[f]) ` l = g` [f`l]" | |
| 12610 | 67 | by (simp add: COMP_def) | 
| 12560 | 68 | |
| 69 | lemma PREC_0: "l \<in> list(nat) ==> PREC(f,g) ` (Cons(0,l)) = f`l" | |
| 12610 | 70 | by (simp add: PREC_def) | 
| 12560 | 71 | |
| 12610 | 72 | lemma PREC_succ: | 
| 73 | "[| x \<in> nat; l \<in> list(nat) |] | |
| 74 | ==> PREC(f,g) ` (Cons(succ(x),l)) = | |
| 75 | g ` Cons(PREC(f,g)`(Cons(x,l)), Cons(x,l))" | |
| 76 | by (simp add: PREC_def) | |
| 12560 | 77 | |
| 78 | ||
| 12610 | 79 | subsection {* Inductive definition of the PR functions *}
 | 
| 80 | ||
| 12560 | 81 | consts | 
| 12610 | 82 | prim_rec :: i | 
| 12088 | 83 | |
| 84 | inductive | |
| 12610 | 85 | domains prim_rec \<subseteq> "list(nat)->nat" | 
| 12560 | 86 | intros | 
| 87 | "SC \<in> prim_rec" | |
| 19676 | 88 | "k \<in> nat ==> CONSTANT(k) \<in> prim_rec" | 
| 12560 | 89 | "i \<in> nat ==> PROJ(i) \<in> prim_rec" | 
| 12610 | 90 | "[| g \<in> prim_rec; fs\<in>list(prim_rec) |] ==> COMP(g,fs) \<in> prim_rec" | 
| 91 | "[| f \<in> prim_rec; g \<in> prim_rec |] ==> PREC(f,g) \<in> prim_rec" | |
| 92 | monos list_mono | |
| 19676 | 93 | con_defs SC_def CONSTANT_def PROJ_def COMP_def PREC_def | 
| 12610 | 94 | type_intros nat_typechecks list.intros | 
| 26059 | 95 | lam_type list_case_type drop_type map_type | 
| 12610 | 96 | apply_type rec_type | 
| 12560 | 97 | |
| 98 | ||
| 12610 | 99 | lemma prim_rec_into_fun [TC]: "c \<in> prim_rec ==> c \<in> list(nat) -> nat" | 
| 100 | by (erule subsetD [OF prim_rec.dom_subset]) | |
| 12560 | 101 | |
| 102 | lemmas [TC] = apply_type [OF prim_rec_into_fun] | |
| 103 | ||
| 104 | declare prim_rec.intros [TC] | |
| 105 | declare nat_into_Ord [TC] | |
| 106 | declare rec_type [TC] | |
| 107 | ||
| 12610 | 108 | lemma ACK_in_prim_rec [TC]: "i \<in> nat ==> ACK(i) \<in> prim_rec" | 
| 18415 | 109 | by (induct set: nat) simp_all | 
| 12560 | 110 | |
| 12610 | 111 | lemma ack_type [TC]: "[| i \<in> nat; j \<in> nat |] ==> ack(i,j) \<in> nat" | 
| 112 | by auto | |
| 12560 | 113 | |
| 12610 | 114 | |
| 115 | subsection {* Ackermann's function cases *}
 | |
| 12560 | 116 | |
| 12610 | 117 | lemma ack_0: "j \<in> nat ==> ack(0,j) = succ(j)" | 
| 118 |   -- {* PROPERTY A 1 *}
 | |
| 119 | by (simp add: SC) | |
| 120 | ||
| 12560 | 121 | lemma ack_succ_0: "ack(succ(i), 0) = ack(i,1)" | 
| 12610 | 122 |   -- {* PROPERTY A 2 *}
 | 
| 19676 | 123 | by (simp add: CONSTANT PREC_0) | 
| 12560 | 124 | |
| 125 | lemma ack_succ_succ: | |
| 12610 | 126 | "[| i\<in>nat; j\<in>nat |] ==> ack(succ(i), succ(j)) = ack(i, ack(succ(i), j))" | 
| 127 |   -- {* PROPERTY A 3 *}
 | |
| 19676 | 128 | by (simp add: CONSTANT PREC_succ COMP_1 PROJ_0) | 
| 12560 | 129 | |
| 12610 | 130 | lemmas [simp] = ack_0 ack_succ_0 ack_succ_succ ack_type | 
| 131 | and [simp del] = ACK.simps | |
| 12560 | 132 | |
| 133 | ||
| 18415 | 134 | lemma lt_ack2: "i \<in> nat ==> j \<in> nat ==> j < ack(i,j)" | 
| 12610 | 135 |   -- {* PROPERTY A 4 *}
 | 
| 20503 | 136 | apply (induct i arbitrary: j set: nat) | 
| 12610 | 137 | apply simp | 
| 138 | apply (induct_tac j) | |
| 139 | apply (erule_tac [2] succ_leI [THEN lt_trans1]) | |
| 140 | apply (rule nat_0I [THEN nat_0_le, THEN lt_trans]) | |
| 141 | apply auto | |
| 142 | done | |
| 12560 | 143 | |
| 144 | lemma ack_lt_ack_succ2: "[|i\<in>nat; j\<in>nat|] ==> ack(i,j) < ack(i, succ(j))" | |
| 12610 | 145 |   -- {* PROPERTY A 5-, the single-step lemma *}
 | 
| 18415 | 146 | by (induct set: nat) (simp_all add: lt_ack2) | 
| 12560 | 147 | |
| 148 | lemma ack_lt_mono2: "[| j<k; i \<in> nat; k \<in> nat |] ==> ack(i,j) < ack(i,k)" | |
| 12610 | 149 |   -- {* PROPERTY A 5, monotonicity for @{text "<"} *}
 | 
| 150 | apply (frule lt_nat_in_nat, assumption) | |
| 151 | apply (erule succ_lt_induct) | |
| 152 | apply assumption | |
| 153 | apply (rule_tac [2] lt_trans) | |
| 154 | apply (auto intro: ack_lt_ack_succ2) | |
| 155 | done | |
| 12560 | 156 | |
| 157 | lemma ack_le_mono2: "[|j\<le>k; i\<in>nat; k\<in>nat|] ==> ack(i,j) \<le> ack(i,k)" | |
| 12610 | 158 |   -- {* PROPERTY A 5', monotonicity for @{text \<le>} *}
 | 
| 159 | apply (rule_tac f = "\<lambda>j. ack (i,j) " in Ord_lt_mono_imp_le_mono) | |
| 160 | apply (assumption | rule ack_lt_mono2 ack_type [THEN nat_into_Ord])+ | |
| 161 | done | |
| 12560 | 162 | |
| 163 | lemma ack2_le_ack1: | |
| 12610 | 164 | "[| i\<in>nat; j\<in>nat |] ==> ack(i, succ(j)) \<le> ack(succ(i), j)" | 
| 165 |   -- {* PROPERTY A 6 *}
 | |
| 166 | apply (induct_tac j) | |
| 167 | apply simp_all | |
| 168 | apply (rule ack_le_mono2) | |
| 169 | apply (rule lt_ack2 [THEN succ_leI, THEN le_trans]) | |
| 170 | apply auto | |
| 171 | done | |
| 12560 | 172 | |
| 173 | lemma ack_lt_ack_succ1: "[| i \<in> nat; j \<in> nat |] ==> ack(i,j) < ack(succ(i),j)" | |
| 12610 | 174 |   -- {* PROPERTY A 7-, the single-step lemma *}
 | 
| 175 | apply (rule ack_lt_mono2 [THEN lt_trans2]) | |
| 176 | apply (rule_tac [4] ack2_le_ack1) | |
| 177 | apply auto | |
| 178 | done | |
| 12560 | 179 | |
| 180 | lemma ack_lt_mono1: "[| i<j; j \<in> nat; k \<in> nat |] ==> ack(i,k) < ack(j,k)" | |
| 12610 | 181 |   -- {* PROPERTY A 7, monotonicity for @{text "<"} *}
 | 
| 182 | apply (frule lt_nat_in_nat, assumption) | |
| 183 | apply (erule succ_lt_induct) | |
| 184 | apply assumption | |
| 185 | apply (rule_tac [2] lt_trans) | |
| 186 | apply (auto intro: ack_lt_ack_succ1) | |
| 187 | done | |
| 12560 | 188 | |
| 189 | lemma ack_le_mono1: "[| i\<le>j; j \<in> nat; k \<in> nat |] ==> ack(i,k) \<le> ack(j,k)" | |
| 12610 | 190 |   -- {* PROPERTY A 7', monotonicity for @{text \<le>} *}
 | 
| 191 | apply (rule_tac f = "\<lambda>j. ack (j,k) " in Ord_lt_mono_imp_le_mono) | |
| 192 | apply (assumption | rule ack_lt_mono1 ack_type [THEN nat_into_Ord])+ | |
| 193 | done | |
| 12560 | 194 | |
| 195 | lemma ack_1: "j \<in> nat ==> ack(1,j) = succ(succ(j))" | |
| 12610 | 196 |   -- {* PROPERTY A 8 *}
 | 
| 18415 | 197 | by (induct set: nat) simp_all | 
| 12560 | 198 | |
| 199 | lemma ack_2: "j \<in> nat ==> ack(succ(1),j) = succ(succ(succ(j#+j)))" | |
| 12610 | 200 |   -- {* PROPERTY A 9 *}
 | 
| 18415 | 201 | by (induct set: nat) (simp_all add: ack_1) | 
| 12560 | 202 | |
| 203 | lemma ack_nest_bound: | |
| 12610 | 204 | "[| i1 \<in> nat; i2 \<in> nat; j \<in> nat |] | 
| 205 | ==> ack(i1, ack(i2,j)) < ack(succ(succ(i1#+i2)), j)" | |
| 206 |   -- {* PROPERTY A 10 *}
 | |
| 207 | apply (rule lt_trans2 [OF _ ack2_le_ack1]) | |
| 208 | apply simp | |
| 209 | apply (rule add_le_self [THEN ack_le_mono1, THEN lt_trans1]) | |
| 210 | apply auto | |
| 211 | apply (force intro: add_le_self2 [THEN ack_lt_mono1, THEN ack_lt_mono2]) | |
| 212 | done | |
| 12560 | 213 | |
| 214 | lemma ack_add_bound: | |
| 12610 | 215 | "[| i1 \<in> nat; i2 \<in> nat; j \<in> nat |] | 
| 216 | ==> ack(i1,j) #+ ack(i2,j) < ack(succ(succ(succ(succ(i1#+i2)))), j)" | |
| 217 |   -- {* PROPERTY A 11 *}
 | |
| 13339 
0f89104dd377
Fixed quantified variable name preservation for ball and bex (bounded quants)
 paulson parents: 
12610diff
changeset | 218 | apply (rule_tac j = "ack (succ (1), ack (i1 #+ i2, j))" in lt_trans) | 
| 12610 | 219 | apply (simp add: ack_2) | 
| 220 | apply (rule_tac [2] ack_nest_bound [THEN lt_trans2]) | |
| 221 | apply (rule add_le_mono [THEN leI, THEN leI]) | |
| 222 | apply (auto intro: add_le_self add_le_self2 ack_le_mono1) | |
| 223 | done | |
| 12560 | 224 | |
| 225 | lemma ack_add_bound2: | |
| 12610 | 226 | "[| i < ack(k,j); j \<in> nat; k \<in> nat |] | 
| 12560 | 227 | ==> i#+j < ack(succ(succ(succ(succ(k)))), j)" | 
| 12610 | 228 |   -- {* PROPERTY A 12. *}
 | 
| 229 |   -- {* Article uses existential quantifier but the ALF proof used @{term "k#+#4"}. *}
 | |
| 230 |   -- {* Quantified version must be nested @{text "\<exists>k'. \<forall>i,j \<dots>"}. *}
 | |
| 231 | apply (rule_tac j = "ack (k,j) #+ ack (0,j) " in lt_trans) | |
| 232 | apply (rule_tac [2] ack_add_bound [THEN lt_trans2]) | |
| 233 | apply (rule add_lt_mono) | |
| 234 | apply auto | |
| 235 | done | |
| 12560 | 236 | |
| 12610 | 237 | |
| 238 | subsection {* Main result *}
 | |
| 12560 | 239 | |
| 240 | declare list_add_type [simp] | |
| 241 | ||
| 242 | lemma SC_case: "l \<in> list(nat) ==> SC ` l < ack(1, list_add(l))" | |
| 12610 | 243 | apply (unfold SC_def) | 
| 244 | apply (erule list.cases) | |
| 245 | apply (simp add: succ_iff) | |
| 246 | apply (simp add: ack_1 add_le_self) | |
| 247 | done | |
| 12560 | 248 | |
| 249 | lemma lt_ack1: "[| i \<in> nat; j \<in> nat |] ==> i < ack(i,j)" | |
| 19676 | 250 |   -- {* PROPERTY A 4'? Extra lemma needed for @{text CONSTANT} case, constant functions. *}
 | 
| 12610 | 251 | apply (induct_tac i) | 
| 252 | apply (simp add: nat_0_le) | |
| 253 | apply (erule lt_trans1 [OF succ_leI ack_lt_ack_succ1]) | |
| 254 | apply auto | |
| 255 | done | |
| 12560 | 256 | |
| 19676 | 257 | lemma CONSTANT_case: | 
| 258 | "[| l \<in> list(nat); k \<in> nat |] ==> CONSTANT(k) ` l < ack(k, list_add(l))" | |
| 259 | by (simp add: CONSTANT_def lt_ack1) | |
| 12560 | 260 | |
| 12610 | 261 | lemma PROJ_case [rule_format]: | 
| 12560 | 262 | "l \<in> list(nat) ==> \<forall>i \<in> nat. PROJ(i) ` l < ack(0, list_add(l))" | 
| 12610 | 263 | apply (unfold PROJ_def) | 
| 264 | apply simp | |
| 265 | apply (erule list.induct) | |
| 266 | apply (simp add: nat_0_le) | |
| 267 | apply simp | |
| 268 | apply (rule ballI) | |
| 13339 
0f89104dd377
Fixed quantified variable name preservation for ball and bex (bounded quants)
 paulson parents: 
12610diff
changeset | 269 | apply (erule_tac n = i in natE) | 
| 12610 | 270 | apply (simp add: add_le_self) | 
| 271 | apply simp | |
| 272 | apply (erule bspec [THEN lt_trans2]) | |
| 273 | apply (rule_tac [2] add_le_self2 [THEN succ_leI]) | |
| 274 | apply auto | |
| 275 | done | |
| 12560 | 276 | |
| 12610 | 277 | text {*
 | 
| 278 |   \medskip @{text COMP} case.
 | |
| 279 | *} | |
| 12560 | 280 | |
| 281 | lemma COMP_map_lemma: | |
| 12610 | 282 |   "fs \<in> list({f \<in> prim_rec. \<exists>kf \<in> nat. \<forall>l \<in> list(nat). f`l < ack(kf, list_add(l))})
 | 
| 283 | ==> \<exists>k \<in> nat. \<forall>l \<in> list(nat). | |
| 284 | list_add(map(\<lambda>f. f ` l, fs)) < ack(k, list_add(l))" | |
| 18415 | 285 | apply (induct set: list) | 
| 12610 | 286 | apply (rule_tac x = 0 in bexI) | 
| 287 | apply (simp_all add: lt_ack1 nat_0_le) | |
| 288 | apply clarify | |
| 289 | apply (rule ballI [THEN bexI]) | |
| 290 | apply (rule add_lt_mono [THEN lt_trans]) | |
| 291 | apply (rule_tac [5] ack_add_bound) | |
| 292 | apply blast | |
| 293 | apply auto | |
| 294 | done | |
| 12560 | 295 | |
| 12610 | 296 | lemma COMP_case: | 
| 297 | "[| kg\<in>nat; | |
| 298 | \<forall>l \<in> list(nat). g`l < ack(kg, list_add(l)); | |
| 299 |      fs \<in> list({f \<in> prim_rec .
 | |
| 300 | \<exists>kf \<in> nat. \<forall>l \<in> list(nat). | |
| 12560 | 301 | f`l < ack(kf, list_add(l))}) |] | 
| 302 | ==> \<exists>k \<in> nat. \<forall>l \<in> list(nat). COMP(g,fs)`l < ack(k, list_add(l))" | |
| 12610 | 303 | apply (simp add: COMP_def) | 
| 304 | apply (frule list_CollectD) | |
| 305 | apply (erule COMP_map_lemma [THEN bexE]) | |
| 306 | apply (rule ballI [THEN bexI]) | |
| 307 | apply (erule bspec [THEN lt_trans]) | |
| 308 | apply (rule_tac [2] lt_trans) | |
| 309 | apply (rule_tac [3] ack_nest_bound) | |
| 310 | apply (erule_tac [2] bspec [THEN ack_lt_mono2]) | |
| 311 | apply auto | |
| 312 | done | |
| 12560 | 313 | |
| 12610 | 314 | text {*
 | 
| 315 |   \medskip @{text PREC} case.
 | |
| 316 | *} | |
| 12560 | 317 | |
| 12610 | 318 | lemma PREC_case_lemma: | 
| 319 | "[| \<forall>l \<in> list(nat). f`l #+ list_add(l) < ack(kf, list_add(l)); | |
| 320 | \<forall>l \<in> list(nat). g`l #+ list_add(l) < ack(kg, list_add(l)); | |
| 321 | f \<in> prim_rec; kf\<in>nat; | |
| 322 | g \<in> prim_rec; kg\<in>nat; | |
| 12560 | 323 | l \<in> list(nat) |] | 
| 324 | ==> PREC(f,g)`l #+ list_add(l) < ack(succ(kf#+kg), list_add(l))" | |
| 12610 | 325 | apply (unfold PREC_def) | 
| 326 | apply (erule list.cases) | |
| 327 | apply (simp add: lt_trans [OF nat_le_refl lt_ack2]) | |
| 328 | apply simp | |
| 329 |   apply (erule ssubst)  -- {* get rid of the needless assumption *}
 | |
| 330 | apply (induct_tac a) | |
| 331 | apply simp_all | |
| 332 |    txt {* base case *}
 | |
| 333 | apply (rule lt_trans, erule bspec, assumption) | |
| 334 | apply (simp add: add_le_self [THEN ack_lt_mono1]) | |
| 335 |   txt {* ind step *}
 | |
| 336 | apply (rule succ_leI [THEN lt_trans1]) | |
| 337 | apply (rule_tac j = "g ` ?ll #+ ?mm" in lt_trans1) | |
| 338 | apply (erule_tac [2] bspec) | |
| 339 | apply (rule nat_le_refl [THEN add_le_mono]) | |
| 340 | apply typecheck | |
| 341 | apply (simp add: add_le_self2) | |
| 342 |    txt {* final part of the simplification *}
 | |
| 343 | apply simp | |
| 344 | apply (rule add_le_self2 [THEN ack_le_mono1, THEN lt_trans1]) | |
| 345 | apply (erule_tac [4] ack_lt_mono2) | |
| 346 | apply auto | |
| 347 | done | |
| 12560 | 348 | |
| 349 | lemma PREC_case: | |
| 12610 | 350 | "[| f \<in> prim_rec; kf\<in>nat; | 
| 351 | g \<in> prim_rec; kg\<in>nat; | |
| 352 | \<forall>l \<in> list(nat). f`l < ack(kf, list_add(l)); | |
| 353 | \<forall>l \<in> list(nat). g`l < ack(kg, list_add(l)) |] | |
| 354 | ==> \<exists>k \<in> nat. \<forall>l \<in> list(nat). PREC(f,g)`l< ack(k, list_add(l))" | |
| 355 | apply (rule ballI [THEN bexI]) | |
| 356 | apply (rule lt_trans1 [OF add_le_self PREC_case_lemma]) | |
| 357 | apply typecheck | |
| 358 | apply (blast intro: ack_add_bound2 list_add_type)+ | |
| 359 | done | |
| 12560 | 360 | |
| 361 | lemma ack_bounds_prim_rec: | |
| 12610 | 362 | "f \<in> prim_rec ==> \<exists>k \<in> nat. \<forall>l \<in> list(nat). f`l < ack(k, list_add(l))" | 
| 18415 | 363 | apply (induct set: prim_rec) | 
| 19676 | 364 | apply (auto intro: SC_case CONSTANT_case PROJ_case COMP_case PREC_case) | 
| 12610 | 365 | done | 
| 12560 | 366 | |
| 12610 | 367 | theorem ack_not_prim_rec: | 
| 368 | "(\<lambda>l \<in> list(nat). list_case(0, \<lambda>x xs. ack(x,x), l)) \<notin> prim_rec" | |
| 369 | apply (rule notI) | |
| 370 | apply (drule ack_bounds_prim_rec) | |
| 371 | apply force | |
| 372 | done | |
| 12088 | 373 | |
| 374 | end |