1 (**************************************************************************)
4 (* ||A|| A project by Andrea Asperti *)
6 (* ||I|| Developers: *)
7 (* ||T|| The HELM team. *)
8 (* ||A|| http://helm.cs.unibo.it *)
10 (* \ / This file is distributed under the terms of the *)
11 (* v GNU General Public License Version 2 *)
13 (**************************************************************************)
15 After some experience in the use of Matita I could realize how
16 useful Andrea's tutorial:
17 http://citeseerx.ist.psu.edu/viewdoc/summary?doi=10.1.1.149.7928
18 can be, since it is compact, and allows to focus on the esssential
19 aspects for a fruitful approach to Matita.
20 So, I decided to start converting it for the current (23rd
21 of February 2013) version of Matita. The reason I like to have it
22 available via web browser is that, quite often, I access
25 For the moment I am very interested to the more 'advanced' parts,
26 i.e. those ones that start after double induction.
27 Initially, I will introduce the least amount of code which is
28 essential to have the advanced part working. Gradually, I plan to
29 include the whole text as comments to the code.
32 Until not explicitly otherwise written, every part of the content
35 include "basics/relations.ma".
37 (*****************************************************************)
38 (**************** Chapter 1. Getting started *********************)
39 (*****************************************************************)
40 (* Natural numbers are the smallest set generated by a constant O
41 and a successor function S. Sets of this kind, freely generated by
42 a finite number of constructors, are known as inductive types.
43 The definition of natural numbers in Matita reads as follows: *)
45 inductive nat : Type[0] ≝
48 interpretation "Natural numbers" 'N = nat.
49 alias num (instance 0) = "natural number".
51 (* By this syntax, we declare we are defining an inductive type of
52 name nat (which is a Type[0]), built up from the two constructors O
53 of type nat and S of type nat → nat.
54 Let us now define a simple function over natural numbers.
55 The sum of two natural numbers n and m may be defined as follows:
56 if n is O then the sum is m, otherwise, if n is the successor of
57 some natural number p, then the sum of n and m is equal to the
58 successor of the sum of p and m. In this way, we have reduced the
59 computation of the sum of two natural numbers to a similar problem,
60 but on smaller input values. This is an example of a recursive
61 definition, that is a definition of a function in terms of the
62 function itself. In Matita, the previous definition of the sum
63 over natural numbers would be written in the following way: *)
66 match n with [ O ⇒ m | S p ⇒ S (plus p m) ].
67 interpretation "natural plus" 'plus x y = (plus x y).
69 (* Equalities ***************************************************************)
71 theorem plus_O_n: ∀n:nat. n = O + n.
72 #n normalize @refl qed.
74 theorem plus_n_O: ∀n:nat. n = n + O.
76 [ @refl | #n #H <H @eq_f @refl ] qed.
78 theorem plus_n_Sm : ∀n,m:nat. S (n+m) = n + S m.
81 |#m #H #p @eq_f <(H p) @eq_f @eq_f2
84 (* The monotonicity of plus is not in the original
85 Apserti's tutorial but, as far as I could understand
86 the way the current version of Matita works, requires
87 it to prove the equivalence of the two equivalence
88 relations le2 and le we shall see later. *)
89 theorem plus_monotone:∀n,m:nat. n=m → (S n) = (S m).
91 [#m #Om <Om @eq_f @refl
92 |#m #H #p #Smp >Smp @eq_f @refl] qed.
94 theorem plus_sym: ∀ n,m:nat. n+m = m+n.
95 #n #m elim n normalize
97 | #p #H >H @(plus_n_Sm m p)] qed.
100 lemma not_eq_plus_S_m_O: ∀ n,m:nat. Not ((S n)+m = O).
101 #n #m @nmk >(plus_sym (S n) m) <(plus_n_Sm m n) #abs destruct qed .*)
103 (**************** Section 1.2 Double induction ***************)
107 → (∀n:nat. R (S n) O)
108 → (∀n,m:nat. R n m → R (S n) (S m))
110 #R #ROn #RSO #RSS #n (elim n)
115 |#m' @(RSS Pred_n m') @(RPred_nm m')]
118 (**************** Section 1.3 Negation and Discrimination ***)
119 (* Two major axioms of Peano axiomatization of naturals are:
120 1) the inequality between O and S x, for any x, and
121 2) the injectivity of S.
122 More generally, given any inductive type, we expect to be
123 able to prove that all constructors are injective and
124 distinguishable each from the other.
126 The statement ∀x. Not (O = (Sx)) is our first example
129 In the logical framework of Matita, negation is not
130 considered as a primitive connective, but is instead defined
131 in terms of the absurdity proposition False. Explicitly, we
132 may conclude Not P, if and only if assuming P leads
133 to an asburdity, that is P → False.
135 What about False? The only logical principle related to
136 False is the ancient property expressed by the latin motto
137 'ex falso quodlibet', that is, everything may be deduced
138 under a false assumption.
140 Formally, this is expressed by the following property that,
141 for the moment, we may assume to be a primitive constant
144 False_ind : ∀P:Prop. False → P
146 [Ndr: In fact, False_ind *is* a primitive in Matita as it
147 is used in many points when building libraries! ]
149 Concerning injectivity (or separability) of constructors,
150 Matita provides the tactic destruct. The tactic expects in
151 input a term of type e1 = e2. It recursively compares e1
152 and e2, skipping common constructors (injectivity) and halts
153 on subexpressions differing on their leftmost outermost
154 symbols. If any of these correponding symbols are two
155 different constructors the tactics automatically closes the
156 goal [Ndr: that depends on them] having obtained a
157 contradiction. Otherwise, destruct adds to the context all
158 new equalities between the different subformulae in
159 corresponding positions. Luckily, the tactic is much simpler
160 to use than to explain. Let us see a couple of examples. *)
162 theorem not_eq_O_S: ∀ n:nat. Not (O = S n).
163 #n (* apply the definition of Not *) @nmk #Habs destruct qed.
166 lemma not_eq_S_O: ∀ n:nat. Not (S n = O).
167 #n (* apply the definition of Not *) @nmk #Habs destruct qed. *)
169 theorem S_inj: ∀ n,m:nat. S n = S m → n = m.
170 #n #m #Hinj destruct @refl qed .
172 (*****************************************************************)
173 (**************** Chapter 2. Defining properties *****************)
174 (*****************************************************************)
175 (* So far, the only property we have been dealing with has
176 been equality that we have essentially assumed as a
177 primitive notion of Matita, governed via rewriting and
178 reflexivity. As an exercise one can prove simmetry and
179 transitivity of the equality, as follows: *)
181 lemma eq_sym: ∀A:Type[0]. ∀x,y:A. x=y → y=x.
182 #A #x #y #eqxy <eqxy @refl qed .
184 lemma eq_tran: ∀A:Type[0]. ∀x,y,z:A. x=y → y=z → x=z.
185 #A #x #y #z #eqxy #eqyz >eqxy @eqyz qed .
187 (* The next step is to define a binary predicate
189 asserting that n is less or equal to m. As we shall see,
190 we have some alternatives.
192 We start with a natural mathematical definition:
193 n is less or equal to m
194 if and only if it exists p such n + p = m.
196 We have essentially two different, almost equivalent, ways
197 to encode such a predicate in Matita:
198 1) as a definition, or
199 2) as an inductive type.
201 As a definition it is: *)
203 definition le1: nat → nat → Prop ≝
206 (* However, an experienced Matita user would probably prefer
207 to transform the previous definition of le into the smallest
208 property induced by *an integer p and a proof of n+p=m *
211 inductive le2 (n,m:nat) : Prop ≝
212 le_witness : ∀p:nat.n+p = m → le2 n m.
214 (* The constructor le_witness is a user-defined name that
215 can bw chosen arbitrarily and which idetifies a proof of:
217 ∀n,m,p:nat.n + p = m → le2 n m
219 Namely, the two parameters n and m are also parameters
220 for the constructor whose fully blown type is exactly:
222 le_witness: ∀n,m,p:nat.n + p = m → le2 n m
224 We formally prove the equivalence between the two
225 previous definitions.
227 We start proving that the first definition implies the
230 lemma le1_to_le2: ∀n,m:nat.le1 n m → le2 n m.
231 (* This is the proof pattern we shall follow:
232 --------------------------------------------------- @npeqm
233 n:nat,m:nat,∃p:nat.n+p=m,
234 p:nat,npeqm:n+p=m ⊢ n+p=m
235 ----------------------------------------------- @(le_witness n m p)
236 n:nat,m:nat,∃p:nat.n+p=m,
237 p:nat,npeqm:n+p=m ⊢ n+p=m→le2 n m
238 ----------------------------------------------- #p #npeqm
239 n:nat,m:nat,∃p:nat.n+p=m
241 ----------------------------------------------- elim le1
242 n:nat,m:nat,∃p:nat.n+p=m
244 ----------------------------------- normalize in le1;
245 n:nat,m:nat,le1 n m ⊢ le2 n m
246 ------------------------------- #n #m #le1
247 ∀n,m:nat.le1 n m → le2 n m *)
249 normalize in le1; elim le1 (* (0) *)
250 #p #npeqm @(le_witness n m p) @npeqm qed .
252 (* Then, the second definition implies the first one: *)
253 lemma le2_to_le1: ∀n,m:nat.le2 n m → le1 n m.
254 (* This is the proof pattern we shall follow:
255 ---------- (ex_intro nat (λp:ℕ.n+p=m)) ---------
256 n:ℕ,m:ℕ,le2:le2 n m ⊢ ∀p:ℕ.n+p=m → ∃p0:ℕ.n+p0=m
257 ------------------------------------------------ normalize
258 n:ℕ,m:ℕ,le2:le2 n m ⊢ ∀p:ℕ.n+p=m → le1 n m
259 ------------------------------------------- elim le2
260 n:ℕ,m:ℕ,le2:le2 n m ⊢ le1 n m
261 -------------------------------- #n #m #le2
262 ∀n:ℕ.∀m:ℕ.le2 n m→le1 n m *)
263 #n #m #le2 elim le2 normalize (* (1) *)
264 (* (* One may *) check (ex_intro nat (λp:ℕ.n+p=m)) *)
265 @(ex_intro nat (λp:ℕ.n+p=m)) (* (2) *)
268 (* In the previous proof we do not follow original Asperti's
269 proof pattern. We directly exploit ex_intro, defined in
270 lib/basics/logic.ma whose type is:
272 eq_intro: ∀A:Type.∀P:A→Prop.∀x:A.Px→∃x:A.Px
274 I have do guess the two arguments of ex_intro. In fact,
275 I have experimented with the original Asperti's proof pattern
276 which, keep going from (1) above, must develop as follows:
278 #p #npeqm @(ex_intro ? ? p npeqm))
281 check (ex_intro ? ? p npeqm))
282 lets Matita to automatically build:
283 (ex_intro ℕ (λ_:ℕ.n+__1=m) p npeqm:∃_:ℕ.n+__1=m)
284 from which one can synthesize (2).
286 We remark that the proof of le2_to_le1 is slightly more
287 compact than the proof of le1_to_le2. The reason is that
288 le2_to_le1 does not require the normalization of the
289 definition of le2 before eliminating it as in (0) above.
290 This is one of the practical reason for preferring le2 over
291 le1. More generally, the existential quantifier is just a
292 particular case of inductive type, and the direct definition
293 of a property as an inductive types usually allows a simpler
294 and more direct destructuration of the corresponding
297 (**************** Section 2.1 Recursive properties ***)
298 (* The previous definition of le relies on the definition of
299 the sum, that is not very elegant. An alternative way to look
300 at the less or equal relation is as the smallest relation R
301 being reflexive and such that R n m implies R n (S m). This
302 notion is precisely captured by the following inductive type: *)
303 inductive le (n:nat) : nat → Prop ≝
305 | le_S : ∀ m:nat. le n m → le n (S m).
307 (* Again, let us prove the equivalence between this definition
308 and the definition of le2. As suggested by the original
309 tutorial, we start showing why the tactics we learned so far
310 are not enough. To experiment it, just uncomment in the
312 (* <-- Erase this....
313 lemma le2_to_le_not_general_enough: ∀ n,m:nat. le2 n m → le n m.
314 (* As suggested, one can start as follows: *)
315 #n #m #le2 elim le2 #p
317 n:ℕ,m:ℕ,le2:le2 n m,p:ℕ ⊢ n+p=m→le n m
318 At this point, we can try to proceed by induction on p: *)
320 [ (* We can prove the base case *)
321 normalize <(plus_n_O n) #nm <nm @le_n
322 | (* However the assumptions are too weak
325 ] .... and erase this --> *)
327 (* In fact, in the course of the proof of le_to_le2
328 instead of getting to the point where the goal is
330 we need to arrive to the stronger goal:
332 The tactic we need is
333 generalize in match m;
334 The working proof follows. *)
336 lemma le2_to_le: ∀ n,m:nat. le2 n m → le n m .
338 The following proof can be seen as split into two
339 phases. The first one aims at getting to the goal
340 n:nat,p:ℕ ⊢ ∀m:nat.n+p=m → le n m (1)
341 which we shall prove by inducton on
343 The goal (1) here above needs the introduction to
344 the right of ∀m, after m has been moved among the
345 assumptions to discharge all the other assumptions
348 n:nat,p:ℕ ⊢ ∀m:nat.n+p=m → le n m
349 ------------------------------------ generalize in match m;
350 n:nat,m:nat,p:ℕ ⊢ n+p=m → le n m
351 ------------------------------------ #p
352 n:nat,m:nat ⊢ ∀p:ℕ.n+p=m→le n m
353 ------------------------------------ elim le2 -le2
354 n:nat,m:nat,le2 n m ⊢ le n m
355 ------------------------------------ #n #m #le2
356 ∀n,m:nat.le2 n m → le n m *)
357 #n #m #le2 elim le2 -le2
358 #p generalize in match m;
359 (* The second part proves (1) by induction on p: *)
361 [ <(plus_n_O n) #n' #neqn' <neqn' @le_n
362 | #x #Hind #y #nSxeqy <nSxeqy <(plus_n_Sm) @(le_S)
364 (* eq_f2 is in lib/basics/logic.ma *)
368 (* The converse holds as well: *)
369 lemma le_to_le2: ∀ n,m:nat. le n m → le2 n m .
370 #n #m #le elim le -le
371 [ @(le_witness n n O) <(plus_n_O n) @refl
377 (* The coming steps have n,m,x,p as global assumptions and essentially
378 build the following proof:
381 ----------------- -------------
382 ⊢ n+p=x→S(n+p)=Sx n+p=x ⊢ n+p=x plus_n_Sm
383 →E-------------------------------- -------------
384 n+p=x ⊢ S(n+p)=Sx ⊢ S(n+p)=n+Sp ∀n,m,p.n+p=m->le2 n (S x)
385 eq ---------------------------------------- -------------------------
386 n+p=x ⊢ n+Sp=Sx ⊢ n+Sp=Sx → le2 n (S x)
387 →E-----------------------------------------------------
389 →I-----------------------
390 ⊢ n+p=x → le2 n (S x) *)
392 (* check (plus_monotone (n+p) x npeqx) *)
393 lapply (plus_monotone (n+p) x npeqx) -npeqx
395 (* check (le_witness n (S x) (S p)) *)
396 @(le_witness n (S x) (S p))
399 (**************** Section 2.2 Prop vs. Bool ***)
400 (* The definition of le of the previous section does not give an
401 effective way to decide if n is less or equal to m. What we are looking
402 for is a binary boolean function returning true if n ≤ m, and f alse
403 otherwise. Such a computable function is usually called a decision
404 procedure. A property admitting a decision procedure is called recursive,
405 or decidable. We start defining the type of booleans as the smallest type
406 containing the two elements true and false: *)
407 inductive bool : Type[0] ≝
411 (* Then, we define a decision procedure for the less or equal relation: *)
414 [ O ⇒ true | (S p) ⇒ match m with
415 [ O ⇒ false | (S q) ⇒ leb p q]].
417 (* Once given a decision procedure, it is convenient to define a
418 corresponding elimination principle, which relates in a very general
419 way the boolean function to its propositional counterpart (le). In our
420 case the boolean function is leb, and its propositional counterpart
421 is le. The elimination principle says that:
422 for all natural numbers n and m, and any proposition P over booleans,
423 provided we may prove (P true) under the assumption (le n m), and
424 (P false) under the assumption ¬(le n m), then we can conclude
425 (P (leb n m)). Namely:
427 (n ≤ m → (P true)) → (n ≰ m → (P false)) → P (leb n m)
429 The proof requires preliminary steps:
430 1) the proof of lemmas le_O_n, not_le_Sn_O, le_S_S,
431 2) the definition of pred
432 3) the proof the pred is monotonic
433 4) the proof of le_S_S_to_le.
434 5) the proof of contraposition, called not_to_not in
435 lib/basics/logic.ma. Tuttavia, si potrebbe immaginare
436 di spostare contraposition nella sezione relativa alle
437 dimostrazioni per assurdo, visto il modo di dimostrarla. *)
439 lemma le_O_n : ∀n:nat. le O n.
440 #n (elim n) [@le_n | #x @le_S ] qed.
442 lemma not_le_Sn_O: ∀ n:nat. Not (le (S n) O).
444 lapply ((le_to_le2 (S n) O) abs) -abs #le2 elim le2 -le2 #p
445 >(plus_sym (S n) p) <(plus_n_Sm p n) #abs destruct qed .
447 lemma le_S_S: ∀n,m:nat. (le n m) → (le (S n) (S m)).
448 #n #m #lenm elim lenm -lenm
449 [ @le_n | #x #H -H @(le_S) ] qed .
452 λn. match n with [ O ⇒ O | S p ⇒ p].
454 theorem pred_monotonic:
455 ∀n,m:nat. le n m → le (pred n) (pred m).
456 #n #m #lenm (elim lenm)
458 | #x normalize in match (pred (S x));
459 cases x normalize in match (pred O);
461 | #y normalize in match (pred (S y));
464 lemma le_S_S_to_le: ∀n,m:nat. (le (S n) (S m)) → (le n m).
466 (* check ((pred_monotonic (S n) (S m)) leSnSn) *)
467 lapply ((pred_monotonic (S n) (S m)) leSnSn)
468 normalize in match (pred (S n));
469 normalize in match (pred (S m)); #H @H qed .
471 theorem contraposition : ∀A,B:Prop. (A → B) → ¬B →¬A.
472 #A #B #AB #nB @nmk #A lapply nB lapply (AB A) @absurd qed .
474 theorem leb_elim: ∀n,m:nat. ∀P:bool → Prop.
475 (le n m → P true) → (Not (le n m) → P false) → P (leb n m).
477 [normalize #n #P #Pt #Pf @Pt @(le_O_n)
478 |normalize #n #P #Pt #Pf @Pf @(not_le_Sn_O)
479 |normalize #n #m #Hind #P #Pt #Pf @Hind
480 [#lenm @Pt @le_S_S @lenm
481 |#nlenm @Pf lapply nlenm @contraposition @le_S_S_to_le ]
484 (* Le seguenti prorietà che si trovano anche in
485 lib/arithmetics/nat.ma ma sinora non mi paiono necessarie
486 per questo tutorial, quindi le commento.
489 lemma le_n_Sn : ∀n:nat. le n (S n).
492 lemma le_tran : ∀n,m,o:nat. le n m → le m o → le n o.
493 #n #m #o #lenm #lemo (elim lemo)
494 [@lenm | #x #dummy @le_S ] qed.
496 lemma le_pred_n : ∀n:nat. le (pred n) n.
499 | #m #H normalize @(le_S) @le_n] qed . *)
502 (* Le seguenti proprietà sfruttano pesantemente leb_elim e sono
503 un esempio fondamentale.*)
504 theorem leb_true_to_le:∀n,m.leb n m = true → (le n m).
506 (* check (λb:bool. b=true→le n m)) *)
507 check (∀b:bool. b=true→le n m)
508 (* check ((λb:bool. b=true→le n m) (leb n m)) *)
509 @(leb_elim n m (λb:bool. b=true→le n m))
511 (* DA QUI !!!!!!!!!!!!!!!!!*)
513 @leb_elim // #_ #abs @False_ind /2/ qed.
515 theorem leb_false_to_not_le:∀n,m.
516 leb n m = false → n ≰ m.
517 #n #m @leb_elim // #_ #abs @False_ind /2/ qed.
519 theorem le_to_leb_true: ∀n,m. n ≤ m → leb n m = true.
520 #n #m @leb_elim // #H #H1 @False_ind /2/ qed.
522 theorem not_le_to_leb_false: ∀n,m. n ≰ m → leb n m = false.
523 #n #m @leb_elim // #H #H1 @False_ind /2/ qed.
525 theorem lt_to_leb_false: ∀n,m. m < n → leb n m = false.
529 (*****************************************************************)
530 (**************** Chapter 3. A non trivial example ***************)
531 (*****************************************************************)
532 (* In a way similar to plus we may define the product of two natural
537 match n with [ O ⇒ 0 | S p ⇒ m + (times p m) ].
539 interpretation "natural times" 'times x y = (times x y).
541 definition divides1: nat \to nat \to Prop \def
542 \lambda n,m.\exist p:nat.m = times n p.
544 (* However, as we have seen, it is preferable to define divides as
545 the smallest property induced by a 'witness' p and a proof that
548 inductive divides (n,m:nat) : Prop \def
549 witness : \forall p:nat.m = times n p \to divides n m.
552 (* Let us now address the decidability of divides, i.e. the problem
553 to define an algorithmic boolean function that taken in input two
554 integers n and m returns true if n divides m, and f alse otherwise.
555 A convenient way to proceed is to address the slightly more general
556 problem to compute the modulus (mod) of two numbers (i.e. the rest
557 of an integewr division); obviously n divides m if and only if
558 m mod n = 0. The natural way to define mod as a recursive function
559 would look something like the following: *)
561 let rec mod m n: nat \def
562 match (leb (S m) n) with
564 | false \Rightarrow mod (m-n) n
567 (* The problem with this definition is that the calculus is based on
568 a particular kind or recursion that must be guaranteed to be
569 well-founded (never diverge) . This is typically the case when the
570 recursive parameter 'decreases' in the recursive call. Unfortunately,
571 there is no trivial way, for the system, to understand that m − n is
572 'smaller' than m w.r.t. some well founded ordering
573 (minus is a user defined operation!). What the system is able to
574 understand is essentially a syntactic ordering, based on the structure
575 of inductive data: for instance n is 'smaller' of S n.
576 A simple but effective approach to this problem is that of defining
577 an auxiliary function accepting in input an extra-parameter t
578 providing an upper bound to the complexity of the function, and then
579 recurring on such an argument. For instance, in the case of the
580 modulus, we may eventually complete the computation of mod m n in
581 less than m steps. So, we define: *)
583 let rec mod_aux t m n: nat \def
584 match (leb (S m) n) with
589 (* if t is large enough this case never happens *)
590 |(S t1) \Rightarrow mod_aux t1 (m-n) n
594 definition mod : nat \to nat \to nat \def
595 \lambda m,n.mod_aux m m n.
597 (* When we define a function having several cases as the previous
598 one, it is good practice to specify the behavour with a distinct
599 lemma for each possible branch. In the case of the previous function,
600 we have the following relevant cases, whose proof is more or less
601 straightforward. The only novelty is the use of the change tactic,
602 that allows to replace a goal with an equivalent one (up to
603 convertibility). Sometimes, the heuristic used by the simplify
604 tactic simplifies too much, and it turns out to be convenient to
605 give the system the expected transformation in an explicit way. *)
607 lemma O_to_mod_aux: \forall m,n. mod_aux O m n = m.
609 simplify.elim (leb (S m) n);reflexivity.
613 \forall t,m,n. m < n \to mod_aux (S t) m n = m.
616 ( match (leb (S m) n) with
618 | false \Rightarrow mod_aux t (m-n) n] = m).
619 rewrite > (le_to_leb_true ? ? H).
625 n \le m \to mod_aux (S t) m n = mod_aux t (m-n) n.
628 (match (leb (S m) n) with
630 | false \Rightarrow mod_aux t (m-n) n] = mod_aux t (m-n) n).
631 apply (leb_elim (S m) n);intro
632 [apply False_ind.apply (le_to_not_lt ? ? H).apply H1
637 (* In order to understand the use of the previous lemmas, let us
638 try to prove a simple property of the modulus operation, namely that
639 for any positive n, m mod n < n. The proof has the following
642 theorem lt_mod_aux_m_m:
644 \forall t,m. m \leq t \to (mod_aux t m n) < n.
647 [rewrite > O_to_mod_aux.
648 apply (le_n_O_elim ? H1).
650 |elim (decidable_lt m n)
651 [rewrite > lt_to_mod_aux[assumption|assumption]
652 |rewrite > le_to_mod_aux
662 (* Mimicking the definition of mod_aux, the proof proceeds by
663 induction on the recursive parameter t. The case t = 0 is closed
664 by O_to_mod_aux; in case t = Sn1, we distinguish two more cases
665 according the situations m < n or m ≥ n. In the former case, we use
666 lt_to_mod_aux while in the latter we use le_to_mod_aux
667 and the inductive hypothesis H1. The dots correspond to a trivial
668 but formally cumbersome fragment of the proof. Indeed, after
669 applying the inductive hypothesis H1 we are left with the following
673 (* Very likely here it will benecessary to expand what
674 Andrea writes .... *)
676 (* The proof requires several elementary arithmetical results,
677 but is not particualry informative, so we shall skip it here.
678 Having defined the modulus, we define: *)
680 definition divides_b : nat \to nat \to bool \def
681 \lambda n,m :nat. (eqb (m \mod n) O).