1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
|
Require Export NDomain.
(*********************************************************************
* Peano Axioms *
*********************************************************************)
Module Type NatSignature.
Declare Module Export DomainModule : DomainSignature.
(* We use Export in the previous line to make sure that if we import a
module of type NatSignature, then we also import (i.e., get access
without path qualifiers to) DomainModule. For example, the functor
NatProperties below, which accepts an implementation of NatSignature
as an argument and imports it, will have access to N. Indeed, it does
not make sense to get unqualified access to O and S but not to N. *)
Open Local Scope NScope.
Parameter Inline O : N.
Parameter Inline S : N -> N.
Notation "0" := O : NScope.
Notation "1" := (S O) : NScope.
Add Morphism S with signature E ==> E as S_wd.
(* It is natural to formulate induction for well-defined predicates
only because standard induction
forall P, P 0 -> (forall n, P n -> P (S n)) -> forall n, P n
does not hold in the setoid context (for example, there is no reason
for (P x) hold when x == 0 but x <> 0). However, it is possible to
formulate induction without mentioning well-defidedness (see OtherInd.v);
this formulation is equivalent. *)
Axiom induction :
forall P : N -> Prop, pred_wd E P ->
P 0 -> (forall n : N, P n -> P (S n)) -> forall n : N, P n.
(* Why do we separate induction and recursion?
(1) When induction and recursion are the same, they are dependent
(nondependent induction does not make sense). However, one must impose
conditions on the predicate, or codomain, that it respects the setoid
equality. For induction this means considering predicates P for which
forall n n', n == n' -> (P n <-> P n') holds. For recursion, where P :
nat -> Set, we cannot say (P n <-> P n'). It may make sense to require
forall n n', n == n' -> (P n = P n').
(2) Unlike induction, recursion requires that two equalities hold:
[recursion a f 0 == a] and [recursion a f (S n) == f n (recursion a f n)]
(or something like this). It may be difficult to state, let alone prove,
these equalities because the left- and the right-hand sides may have
different types (P t1) and (P t2) where t1 == t2 is provable but t1 and t2
are not convertible into each other. Nevertheless, these equalities may
be proved using dependent equality (EqdepFacts) or JM equality (JMeq).
However, requiring this for any implementation of natural numbers seems
a little complex. It may make sense to devote a separate module to dependent
recursion (see DepRec.v). *)
Parameter Inline recursion : forall A : Set, A -> (N -> A -> A) -> N -> A.
Implicit Arguments recursion [A].
(* Suppose the codomain A has a setoid equality relation EA. If A is a
function space C -> D, it makes sense to consider extensional
functional equality as EA. Indeed, suppose, for example, that we say
[Definition g (x : N) : C -> D := (recursion ... x ...)]. We would
like to show that the function g of two arguments is well-defined.
This requirement is the same as the requirement that the functions of
one argument (g x) and (g x') are extensionally equal whenever x ==
x', i.e.,
forall x x' : N, x == x' -> eq_fun (g x) (g x'),
which is the same as
forall x x' : N, x == x' -> forall y y' : C, EC y y' -> ED (g x y) (g x' y')
where EC and ED are setoid equalities on C and D, respectively.
Now, if we consider EA to be extensional equality on the function
space, we cannot require that EA is reflexive. Indeed, reflexivity of
EA:
forall f : C -> D, eq_fun f f
or
forall f : C -> D, forall x x', EC x x' -> ED (f x) (f x')
means that every function f ; C -> D is well-defined, which is in
general false. We can expect that EA is symmetric and transitive,
i.e., that EA is a partial equivalence relation (PER). However, there
seems to be no need to require this in the following axioms.
When we defined a function by recursion, the arguments of this
function may occur in the recursion's base case a, the counter x, or
the step function f. For example, in the following definition:
Definition plus (x y : N) := recursion y (fun _ p => S p) x.
one argument becomes the base case and the other becomes the counter.
In the definitions of times:
Definition times (x y : N) := recursion 0 (fun x p => plus y p) x.
the argument y occurs in the step function. Thus it makes sense to
formulate an axiom saying that (recursion a f x) is equal to
(recursion a' f' x') whenever (EA a a'), x == x', and eq_fun2 f f'. We
need to vary all three arguments; for example, claiming that
(recursion a f x) equals (recursion a' f x') with the same f whenever
(EA a a') and x == x' is not enough to prove well-defidedness of
multiplication defined above.
This leads to the axioms given below. There is a question if it is
possible to formulate simpler axioms that would imply this statement
for any implementation. Indeed, the proof seems to have to proceed by
straighforward induction on x. The difficulty is that we cannot prove
(EA (recursion a f x) (recursion a' f' x')) using the induction axioms
above because recursion is not declared to be a setoid morphism:
that's what we are proving! Therefore, this has to be proved by
induction inside each particular implementation. *)
Axiom recursion_wd : forall (A : Set) (EA : relation A),
forall a a' : A, EA a a' ->
forall f f' : N -> A -> A, eq_fun2 E EA EA f f' ->
forall x x' : N, x == x' ->
EA (recursion a f x) (recursion a' f' x').
(* Can we instead declare recursion as a morphism? It does not seem
so. For this, we need to register the relation EA, and for this we
need to declare it as a variable in a section. But information about
morhisms is lost when sections are closed. *)
(* When the function recursion is polymorphic on the codomain A, there
seems no other option than to return the given base case a when the
counter is 0. Therefore, we can formulate the following axioms with
Leibniz equality. *)
Axiom recursion_0 :
forall (A : Set) (a : A) (f : N -> A -> A), recursion a f 0 = a.
Axiom recursion_S :
forall (A : Set) (EA : relation A) (a : A) (f : N -> A -> A),
EA a a -> fun2_wd E EA EA f ->
forall n : N, EA (recursion a f (S n)) (f n (recursion a f n)).
(* It may be possible to formulate recursion_0 and recursion_S as follows:
Axiom recursion_0 :
forall (a : A) (f : N -> A -> A),
EA a a -> forall x : N, x == 0 -> EA (recursion a f x) a.
Axiom recursion_S :
forall (a : A) (f : N -> A -> A),
EA a a -> fun2_wd E EA EA f ->
forall n m : N, n == S m -> EA (recursion a f n) (f m (recursion a f m)).
Then it is possible to prove recursion_wd (see IotherInd.v). This
raises some questions:
(1) Can the axioms recursion_wd, recursion_0 and recursion_S (both
variants) proved for all reasonable implementations?
(2) Can these axioms be proved without assuming that EA is symmetric
and transitive? In OtherInd.v, recursion_wd can be proved from
recursion_0 and recursion_S by assuming symmetry and transitivity.
(2) Which variant requires proving less for each implementation? Can
it be that proving all three axioms about recursion has some common
parts which have to be repeated? *)
Implicit Arguments recursion_wd [A].
Implicit Arguments recursion_0 [A].
Implicit Arguments recursion_S [A].
End NatSignature.
Module NatProperties (Export NatModule : NatSignature).
Module Export DomainPropertiesModule := DomainProperties DomainModule.
Open Local Scope NScope.
(* This tactic applies the induction axioms and solves the resulting
goal "pred_wd E P" *)
Ltac induct n :=
try intros until n;
pattern n; apply induction; clear n;
[unfold NumPrelude.pred_wd;
let n := fresh "n" in
let m := fresh "m" in
let H := fresh "H" in intros n m H; qmorphism n m | |].
Definition if_zero (A : Set) (a b : A) (n : N) : A :=
recursion a (fun _ _ => b) n.
Add Morphism if_zero with signature LE_Set ==> LE_Set ==> E ==> LE_Set as if_zero_wd.
Proof.
unfold LE_Set.
intros; unfold if_zero; now apply recursion_wd with (EA := (@eq A));
[| unfold eq_fun2; now intros |].
Qed.
Theorem if_zero_0 : forall (A : Set) (a b : A), if_zero A a b 0 = a.
Proof.
unfold if_zero; intros; now rewrite recursion_0.
Qed.
Theorem if_zero_S : forall (A : Set) (a b : A) (n : N), if_zero A a b (S n) = b.
Proof.
intros; unfold if_zero.
now rewrite (recursion_S (@eq A)); [| | unfold fun2_wd; now intros].
Qed.
Implicit Arguments if_zero [A].
(* To prove this statement, we need to provably different terms,
e.g., true and false *)
Theorem S_0 : forall n, ~ S n == 0.
Proof.
intros n H.
assert (true = false); [| discriminate].
replace true with (if_zero false true (S n)) by apply if_zero_S.
pattern false at 2; replace false with (if_zero false true 0) by apply if_zero_0.
change (LE_Set bool (if_zero false true (S n)) (if_zero false true 0)).
rewrite H. unfold LE_Set. reflexivity.
Qed.
Definition pred (n : N) : N := recursion 0 (fun m _ => m) n.
Add Morphism pred with signature E ==> E as pred_wd.
Proof.
intros; unfold pred.
now apply recursion_wd with (EA := E); [| unfold eq_fun2; now intros |].
Qed.
Theorem pred_0 : pred 0 == 0.
Proof.
unfold pred; now rewrite recursion_0.
Qed.
Theorem pred_S : forall n, pred (S n) == n.
Proof.
intro n; unfold pred; now rewrite (recursion_S E); [| unfold fun2_wd; now intros |].
Qed.
Theorem S_inj : forall m n, S m == S n -> m == n.
Proof.
intros m n H.
setoid_replace m with (pred (S m)) by (symmetry; apply pred_S).
setoid_replace n with (pred (S n)) by (symmetry; apply pred_S).
now apply pred_wd.
Qed.
Theorem not_eq_S : forall n m, n # m -> S n # S m.
Proof.
intros n m H1 H2. apply S_inj in H2. now apply H1.
Qed.
Theorem not_eq_Sn_n : forall n, S n # n.
Proof.
induct n.
apply S_0.
intros n IH H. apply S_inj in H. now apply IH.
Qed.
Theorem not_all_eq_0 : ~ forall n, n == 0.
Proof.
intro H; apply (S_0 0). apply H.
Qed.
Theorem not_0_implies_S : forall n, n # 0 <-> exists m, n == S m.
Proof.
intro n; split.
induct n; [intro H; now elim H | intros n _ _; now exists n].
intro H; destruct H as [m H]; rewrite H; apply S_0.
Qed.
Theorem nondep_induction :
forall P : N -> Prop, NumPrelude.pred_wd E P ->
P 0 -> (forall n, P (S n)) -> forall n, P n.
Proof.
intros; apply induction; auto.
Qed.
Ltac nondep_induct n :=
try intros until n;
pattern n; apply nondep_induction; clear n;
[unfold NumPrelude.pred_wd;
let n := fresh "n" in
let m := fresh "m" in
let H := fresh "H" in intros n m H; qmorphism n m | |].
Theorem O_or_S : forall n, n == 0 \/ exists m, n == S m.
Proof.
nondep_induct n; [now left | intros n; right; now exists n].
Qed.
(* The following is useful for reasoning about, e.g., Fibonacci numbers *)
Section DoubleInduction.
Variable P : N -> Prop.
Hypothesis P_correct : NumPrelude.pred_wd E P.
Add Morphism P with signature E ==> iff as P_morphism.
Proof.
exact P_correct.
Qed.
Theorem double_induction :
P 0 -> P 1 ->
(forall n, P n -> P (S n) -> P (S (S n))) -> forall n, P n.
Proof.
intros until 3.
assert (D : forall n, P n /\ P (S n)); [ |intro n; exact (proj1 (D n))].
induct n; [ | intros n [IH1 IH2]]; auto.
Qed.
End DoubleInduction.
(* The following is useful for reasoning about, e.g., Ackermann function *)
Section TwoDimensionalInduction.
Variable R : N -> N -> Prop.
Hypothesis R_correct : rel_wd E R.
Add Morphism R with signature E ==> E ==> iff as R_morphism.
Proof.
exact R_correct.
Qed.
Theorem two_dim_induction :
R 0 0 ->
(forall n m, R n m -> R n (S m)) ->
(forall n, (forall m, R n m) -> R (S n) 0) -> forall n m, R n m.
Proof.
intros H1 H2 H3. induct n.
induct m.
exact H1. exact (H2 0).
intros n IH. induct m.
now apply H3. exact (H2 (S n)).
Qed.
End TwoDimensionalInduction.
End NatProperties.
|