aboutsummaryrefslogtreecommitdiff
path: root/theories/Ints/Z/ZDivModAux.v
blob: be7955aaddc8363e77dbb9b225739806467d5e22 (plain)
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
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
(*************************************************************)
(*      This file is distributed under the terms of the      *)
(*      GNU Lesser General Public License Version 2.1        *)
(*************************************************************)
(*    Benjamin.Gregoire@inria.fr Laurent.Thery@inria.fr      *)
(*************************************************************)

(**********************************************************************
     ZDivModAux.v                                                              
                                                                               
     Auxillary functions & Theorems for Zdiv and Zmod                          
 **********************************************************************)

Require Export ZArith.
Require Export Znumtheory.
Require Export Tactic.
Require Import ZAux.
Require Import ZPowerAux.

Open Local Scope Z_scope. 

Hint  Extern 2 (Zle _ _) => 
 (match goal with
  |- Zpos _ <= Zpos _ => exact (refl_equal _)
  | H: _ <=  ?p |- _ <= ?p => apply Zle_trans with (2 := H)
  | H: _ <  ?p |- _ <= ?p => 
   apply Zlt_le_weak; apply Zle_lt_trans with (2 := H)
  end).

Hint  Extern 2 (Zlt _ _) => 
 (match goal with
   |- Zpos _ < Zpos _ => exact (refl_equal _)
|      H: _ <=  ?p |- _ <= ?p => apply Zlt_le_trans with (2 := H)
|   H: _ <  ?p |- _ <= ?p => apply Zle_lt_trans with (2 := H)
  end).

Hint Resolve Zlt_gt Zle_ge: zarith.

(************************************** 
  Properties Zmod 
**************************************)
 
 Theorem Zmod_mult:
   forall a b n, 0 < n ->  (a * b) mod n = ((a mod n) * (b mod n)) mod n.
 Proof.
  intros a b n H.
  pattern a at 1; rewrite (Z_div_mod_eq a n); auto with zarith.
  pattern b at 1; rewrite (Z_div_mod_eq b n); auto with zarith.
  replace ((n * (a / n) + a mod n) * (n * (b / n) + b mod n)) with
   ((a mod n) * (b mod n) +
   (((n*(a/n)) * (b/n) + (b mod n)*(a / n)) + (a mod n) * (b / n)) * n);
   auto with zarith.
  apply Z_mod_plus; auto with zarith.
  ring.
 Qed.

 Theorem Zmod_plus:
    forall a b n, 0 < n ->  (a + b) mod n = (a mod n + b mod n) mod n.
 Proof.
  intros a b n H.
  pattern a at 1; rewrite (Z_div_mod_eq a n); auto with zarith.
  pattern b at 1; rewrite (Z_div_mod_eq b n); auto with zarith.
  replace ((n * (a / n) + a mod n) + (n * (b / n) + b mod n))
     with ((a mod n + b mod n) + (a / n + b / n) * n); auto with zarith.
  apply Z_mod_plus; auto with zarith.
  ring.
 Qed.
 
 Theorem Zmod_mod: forall a n, 0 < n -> (a mod n) mod n = a mod n.
 Proof.
  intros a n H.
  pattern a at 2; rewrite (Z_div_mod_eq a n); auto with zarith.
  rewrite Zplus_comm; rewrite Zmult_comm.
  apply sym_equal; apply Z_mod_plus; auto with zarith.
 Qed.
 
 Theorem Zmod_def_small: forall a n, 0 <= a < n  ->  a mod n = a.
 Proof.
  intros a n [H1 H2]; unfold Zmod.
  generalize (Z_div_mod a n); case (Zdiv_eucl a n).
  intros q r H3; case H3; clear H3; auto with zarith.
  intros H4 [H5 H6].
  case (Zle_or_lt q (- 1)); intros H7.
  contradict H1; apply Zlt_not_le.
  subst a.
  apply Zle_lt_trans with (n * - 1 + r); auto with zarith.
  case (Zle_lt_or_eq 0 q); auto with zarith; intros H8.
  contradict H2; apply Zle_not_lt.
  apply Zle_trans with (n * 1 + r); auto with zarith.
  rewrite H4; auto with zarith.
  subst a; subst q; auto with zarith.
 Qed.

 Theorem Zmod_minus: 
     forall a b n, 0 < n -> (a - b) mod n = (a mod n - b mod n) mod n.
 Proof.
  intros a b n H; replace (a - b) with (a + (-1) * b); auto with zarith.
  replace (a mod n - b mod n) with (a mod n + (-1)*(b mod n));auto with zarith.
  rewrite Zmod_plus; auto with zarith.
  rewrite Zmod_mult; auto with zarith.
  rewrite (fun x y => Zmod_plus x  ((-1) * y)); auto with zarith.
  rewrite Zmod_mult; auto with zarith.
  rewrite (fun x => Zmod_mult x (b mod n)); auto with zarith.
  repeat rewrite Zmod_mod; auto.
 Qed.

 Theorem Zmod_le: forall a n, 0 < n -> 0 <= a -> (Zmod a n) <= a.
 Proof.
  intros a n H1 H2; case (Zle_or_lt n  a); intros H3.
  case (Z_mod_lt a n); auto with zarith.
  rewrite Zmod_def_small; auto with zarith.
 Qed.

 Theorem Zmod_le_first: forall a b, 0 <= a -> 0 < b -> 0 <= a mod b <= a.
 Proof.
  intros a b H H1;case (Z_mod_lt a b);auto with zarith;intros H2 H3;split;auto.
  case (Zle_or_lt b a); intros H4; auto with zarith.
  rewrite Zmod_def_small; auto with zarith.
 Qed.


(**************************************
 Properties of Zdivide
**************************************)
 
 Theorem Zdiv_pos: forall a b, 0 < b -> 0 <= a -> 0 <= a / b.
 Proof.
  intros; apply Zge_le; apply Z_div_ge0; auto with zarith.
 Qed. 
 Hint Resolve Zdiv_pos: zarith.

 Theorem Zdiv_mult_le:
   forall a b c, 0 <= a -> 0 < b -> 0 <= c -> c * (a/b) <= (c * a)/ b.
 Proof.
  intros a b c H1 H2 H3.
  case (Z_mod_lt a b); auto with zarith; intros Hu1 Hu2.
  case (Z_mod_lt c b); auto with zarith; intros Hv1 Hv2.
  apply Zmult_le_reg_r with b; auto with zarith.
  rewrite <- Zmult_assoc.
  replace (a / b * b) with (a - a mod b).
  replace (c * a / b * b) with (c * a - (c * a) mod b).
  rewrite Zmult_minus_distr_l.
  unfold Zminus; apply Zplus_le_compat_l.
  match goal with |- - ? X <= -?Y => assert (Y <= X); auto with zarith end.
  apply Zle_trans with ((c mod b) * (a mod b)); auto with zarith.
  rewrite Zmod_mult; case (Zmod_le_first ((c mod b) * (a mod b)) b); 
    auto with zarith.
  apply Zmult_le_compat_r; auto with zarith.
  case (Zmod_le_first c b); auto.
  pattern (c * a) at 1; rewrite (Z_div_mod_eq (c * a) b); try ring; 
    auto with zarith.
  pattern a at 1; rewrite (Z_div_mod_eq a b); try ring; auto with zarith.
 Qed.

 Theorem Zdiv_unique:
   forall n d q r, 0 < d -> ( 0 <= r < d ) -> n = d * q + r ->  q = n / d.
 Proof.
  intros n d q r H H0 H1.
  assert (H2: n = d * (n / d) + n mod d).
  apply Z_div_mod_eq; auto with zarith.
  assert (H3:  0 <= n mod d < d ).
  apply Z_mod_lt; auto with zarith.
  case (Ztrichotomy q (n / d)); auto.
  intros H4.
  absurd (n < n); auto with zarith.
  pattern n at 1; rewrite H1; rewrite H2.
  apply Zlt_le_trans with (d * (q + 1)); auto with zarith.
  rewrite Zmult_plus_distr_r; auto with zarith.
  apply Zle_trans with (d * (n / d)); auto with zarith.
  intros tmp; case tmp; auto; intros H4; clear tmp.
  absurd (n < n); auto with zarith.
  pattern n at 2; rewrite H1; rewrite H2.
  apply Zlt_le_trans with (d * (n / d + 1)); auto with zarith.
  rewrite Zmult_plus_distr_r; auto with zarith.
  apply Zle_trans with (d * q); auto with zarith.
 Qed.

 Theorem Zmod_unique:
   forall n d q r, 0 < d -> ( 0 <= r < d ) -> n = d * q + r ->  r = n mod d.
 Proof.
  intros n d q r H H0 H1.
  assert (H2: n = d * (n / d) + n mod d).
  apply Z_div_mod_eq; auto with zarith.
  rewrite (Zdiv_unique n d q r) in H1; auto.
  apply (Zplus_reg_l (d * (n / d))); auto with zarith.
 Qed.

 Theorem Zmod_Zmult_compat_l: forall a b c, 
   0 < b -> 0 < c -> c * a  mod (c * b) = c * (a mod b).
 Proof.
  intros a b c H2 H3.
  pattern a at 1; rewrite (Z_div_mod_eq a b); auto with zarith.
  rewrite Zplus_comm; rewrite Zmult_plus_distr_r.
  rewrite Zmult_assoc; rewrite (Zmult_comm (c * b)).
  rewrite Z_mod_plus; auto with zarith.
  apply Zmod_def_small; split; auto with zarith.
  apply Zmult_le_0_compat; auto with zarith.
  destruct (Z_mod_lt a b);auto with zarith.
  apply Zmult_lt_compat_l; auto with zarith.
  destruct (Z_mod_lt a b);auto with zarith.
 Qed.

 Theorem Zdiv_Zmult_compat_l: 
   forall a b c, 0 <= a -> 0 < b -> 0 < c -> c * a / (c * b) = a / b.
 Proof.
  intros a b c H1 H2 H3; case (Z_mod_lt a b); auto with zarith; intros H4 H5.
  apply Zdiv_unique with (a mod b); auto with zarith.
  apply Zmult_reg_l with c; auto with zarith.
  rewrite Zmult_plus_distr_r; rewrite <- Zmod_Zmult_compat_l; auto with zarith.
  rewrite Zmult_assoc; apply Z_div_mod_eq; auto with zarith.
 Qed.

 Theorem Zdiv_0: forall a, 0 < a -> 0 / a = 0.
 Proof.
  intros a H;apply sym_equal;apply Zdiv_unique with (r := 0); auto with zarith.
 Qed.

 Theorem Zdiv_le_upper_bound: 
   forall a b q, 0 <= a -> 0 < b -> a <= q * b -> a / b <= q.
 Proof.
  intros a b q H1 H2 H3.
  apply Zmult_le_reg_r with b; auto with zarith.
  apply Zle_trans with (2 := H3).
  pattern a at 2; rewrite (Z_div_mod_eq a b); auto with zarith.
  rewrite (Zmult_comm b); case (Z_mod_lt a b); auto with zarith.
 Qed.

 Theorem Zdiv_lt_upper_bound: 
   forall a b q, 0 <= a -> 0 < b -> a < q * b -> a / b < q.
 Proof.
  intros a b q H1 H2 H3.
  apply Zmult_lt_reg_r with b; auto with zarith.
  apply Zle_lt_trans with (2 := H3).
  pattern a at 2; rewrite (Z_div_mod_eq a b); auto with zarith.
  rewrite (Zmult_comm b); case (Z_mod_lt a b); auto with zarith.
 Qed.

 Theorem Zdiv_le_lower_bound: 
   forall a b q, 0 <= a -> 0 < b -> q * b <= a -> q <= a / b.
 Proof.
  intros a b q H1 H2 H3.
  assert (q < a / b + 1); auto with zarith.
  apply Zmult_lt_reg_r with b; auto with zarith.
  apply Zle_lt_trans with (1 := H3).
  pattern a at 1; rewrite (Z_div_mod_eq a b); auto with zarith.
  rewrite Zmult_plus_distr_l; rewrite (Zmult_comm b); case (Z_mod_lt a b);
   auto with zarith.
 Qed.

 Theorem Zmult_mod_distr_l: 
   forall a b c, 0 < a -> 0 < c -> (a * b) mod (a * c) = a * (b mod c).
 Proof.
  intros a b c H Hc.
  apply sym_equal; apply Zmod_unique with (b / c); auto with zarith.
  apply Zmult_lt_0_compat; auto.
  case (Z_mod_lt b c); auto with zarith; intros; split; auto with zarith.
  apply Zmult_lt_compat_l; auto.
  rewrite <- Zmult_assoc; rewrite <- Zmult_plus_distr_r.
  rewrite <- Z_div_mod_eq; auto with zarith.
 Qed.


 Theorem Zmod_distr: forall a b r t, 0 <= a <= b -> 0 <= r -> 0 <= t < 2 ^a ->
  (2 ^a * r + t) mod (2 ^ b) = (2 ^a * r) mod (2 ^ b) + t.
 Proof.
  intros a b r t (H1, H2) H3 (H4, H5).
  assert (t < 2 ^ b).
  apply Zlt_le_trans with (1:= H5); auto with zarith.
  apply Zpower_le_monotone; auto with zarith.
  rewrite Zmod_plus; auto with zarith.
  rewrite Zmod_def_small with (a := t); auto with zarith.
  apply Zmod_def_small; auto with zarith.
  split; auto with zarith.
  assert (0 <= 2 ^a * r); auto with zarith.
  apply Zplus_le_0_compat; auto with zarith.
  match goal with |- context [?X mod ?Y] => case (Z_mod_lt X Y) end;
   auto with zarith.
  pattern (2 ^ b) at 2; replace (2 ^ b) with ((2 ^ b - 2 ^a) + 2 ^ a);
    try ring.
  apply Zplus_le_lt_compat; auto with zarith.
  replace b with ((b - a) + a); try ring.
  rewrite Zpower_exp; auto with zarith.
  pattern (2 ^a) at 4; rewrite <- (Zmult_1_l (2 ^a)); 
   try rewrite <- Zmult_minus_distr_r.
  rewrite (Zmult_comm (2 ^(b - a))); rewrite  Zmult_mod_distr_l; 
   auto with zarith.
  rewrite (Zmult_comm (2 ^a)); apply Zmult_le_compat_r; auto with zarith.
  match goal with |- context [?X mod ?Y] => case (Z_mod_lt X Y) end;
   auto with zarith.
 Qed.

 Theorem Zmult_mod_distr_r:
   forall a b c : Z, 0 < a -> 0 < c -> (b * a) mod (c * a) = (b mod c) * a.
 Proof.
  intros; repeat rewrite (fun x => (Zmult_comm x a)).
  apply Zmult_mod_distr_l; auto.
 Qed.

 Theorem Z_div_plus_l: forall a b c : Z, 0 < b -> (a * b + c) / b = a  + c / b.
 Proof.
  intros a b c H; rewrite Zplus_comm; rewrite Z_div_plus;
   try apply Zplus_comm; auto with zarith. 
 Qed.

 Theorem Zmod_shift_r:
   forall a b r t, 0 <= a <= b -> 0 <= r -> 0 <= t < 2 ^a ->
     (r * 2 ^a + t) mod (2 ^ b) = (r * 2 ^a) mod (2 ^ b) + t.
 Proof.
  intros a b r t (H1, H2) H3 (H4, H5).
  assert (t < 2 ^ b).
  apply Zlt_le_trans with (1:= H5); auto with zarith.
  apply Zpower_le_monotone; auto with zarith.
  rewrite Zmod_plus; auto with zarith.
  rewrite Zmod_def_small with (a := t); auto with zarith.
  apply Zmod_def_small; auto with zarith.
  split; auto with zarith.
  assert (0 <= 2 ^a * r); auto with zarith.
  apply Zplus_le_0_compat; auto with zarith.
  match goal with |- context [?X mod ?Y] => case (Z_mod_lt X Y) end; 
   auto with zarith.
  pattern (2 ^ b) at 2;replace (2 ^ b) with ((2 ^ b - 2 ^a) + 2 ^ a); try ring.
  apply Zplus_le_lt_compat; auto with zarith.
  replace b with ((b - a) + a); try ring.
  rewrite Zpower_exp; auto with zarith.
  pattern (2 ^a) at 4; rewrite <- (Zmult_1_l (2 ^a)); 
   try rewrite <- Zmult_minus_distr_r.
  repeat rewrite (fun x => Zmult_comm x (2 ^ a)); rewrite Zmult_mod_distr_l;
   auto with zarith.
  apply Zmult_le_compat_l; auto with zarith.
  match goal with |- context [?X mod ?Y] => case (Z_mod_lt X Y) end; 
   auto with zarith.
 Qed.

  Theorem Zdiv_lt_0: forall a b, 0 <= a < b -> a / b = 0.
  intros a b H; apply sym_equal; apply Zdiv_unique with a; auto with zarith.
  Qed.

  Theorem Zmod_mult_0: forall a b, 0 < b  -> (a * b) mod b = 0.
  Proof.
   intros a b H; rewrite <- (Zplus_0_l (a * b)); rewrite Z_mod_plus;
    auto with zarith.
  Qed.

  Theorem Zdiv_shift_r: 
    forall a b r t, 0 <= a <= b -> 0 <= r -> 0 <= t < 2 ^a ->
      (r * 2 ^a + t) /  (2 ^ b) = (r * 2 ^a) / (2 ^ b).
  Proof.
   intros a b r t (H1, H2) H3 (H4, H5).
   assert (Eq: t < 2 ^ b); auto with zarith.
   apply Zlt_le_trans with (1 := H5); auto with zarith.
   apply Zpower_le_monotone; auto with zarith.
   pattern (r * 2 ^ a) at 1; rewrite Z_div_mod_eq with (b := 2 ^ b);
    auto with zarith.
   rewrite <- Zplus_assoc.
   rewrite <- Zmod_shift_r; auto with zarith.
   rewrite (Zmult_comm (2 ^ b)); rewrite Z_div_plus_l; auto with zarith.
   rewrite (fun x y => @Zdiv_lt_0 (x mod y)); auto with zarith.
   match goal with |- context [?X mod ?Y] => case (Z_mod_lt X Y) end; 
    auto with zarith.
  Qed.


  Theorem Zpos_minus: 
     forall a b, Zpos a < Zpos b -> Zpos (b- a) = Zpos b - Zpos a.
  Proof.
   intros a b H.
   repeat rewrite Zpos_eq_Z_of_nat_o_nat_of_P; autorewrite with pos_morph;
     auto with zarith.
   rewrite inj_minus1; auto with zarith.
   match goal with |- (?X <= ?Y)%nat =>
    case (le_or_lt X Y); auto; intro tmp; absurd (Z_of_nat X < Z_of_nat Y); 
        try apply Zle_not_lt; auto with zarith
    end.
   repeat rewrite <- Zpos_eq_Z_of_nat_o_nat_of_P; auto with zarith.
   generalize (Zlt_gt _ _ H); auto.
 Qed.

  Theorem Zdiv_Zmult_compat_r:
     forall a b c : Z, 0 <= a -> 0 < b -> 0 < c -> a * c / (b * c) = a / b.
  Proof.
   intros a b c H H1 H2; repeat rewrite (fun x => Zmult_comm x c); 
    apply Zdiv_Zmult_compat_l; auto.
  Qed.


 Lemma shift_unshift_mod : forall n p a,
     0 <= a < 2^n ->
     0 <= p <= n ->
     a * 2^p = a / 2^(n - p) * 2^n + (a*2^p) mod 2^n.
 Proof.
  intros n p a H1 H2.
  pattern (a*2^p) at 1;replace (a*2^p) with 
     (a*2^p/2^n * 2^n + a*2^p mod 2^n). 
  2:symmetry;rewrite (Zmult_comm (a*2^p/2^n));apply Z_div_mod_eq.
  replace (a * 2 ^ p / 2 ^ n) with (a / 2 ^ (n - p));trivial.
  replace (2^n) with (2^(n-p)*2^p).
  symmetry;apply Zdiv_Zmult_compat_r.
  destruct H1;trivial.
  apply Zpower_lt_0;auto with zarith.
  apply Zpower_lt_0;auto with zarith.
  rewrite <- Zpower_exp.
  replace (n-p+p) with n;trivial. ring.
  omega. omega.
  apply Zlt_gt. apply Zpower_lt_0;auto with zarith.
 Qed.

 Lemma Zdiv_Zdiv : forall a b c, 0 < b -> 0 < c -> (a/b)/c = a / (b*c).
 Proof.
  intros a b c H H0.
  pattern a at 2;rewrite (Z_div_mod_eq a b);auto with zarith.
  pattern (a/b) at 2;rewrite (Z_div_mod_eq (a/b) c);auto with zarith.
  replace (b * (c * (a / b / c) + (a / b) mod c) + a mod b) with
    ((a / b / c)*(b * c)  + (b * ((a / b) mod c) + a mod b));try ring.
  rewrite Z_div_plus_l;auto with zarith.
  rewrite (Zdiv_lt_0 (b * ((a / b) mod c) + a mod b)).
  ring.
  split.
  apply Zplus_le_0_compat;auto with zarith.
  apply Zmult_le_0_compat;auto with zarith.
  destruct (Z_mod_lt (a/b) c);auto with zarith.
  destruct (Z_mod_lt a b);auto with zarith.
  apply Zle_lt_trans with (b * ((a / b) mod c) + (b-1)).
  destruct (Z_mod_lt a b);auto with zarith.
  apply Zle_lt_trans with (b * (c-1) + (b - 1)).
  apply Zplus_le_compat;auto with zarith.
  destruct (Z_mod_lt (a/b) c);auto with zarith.
  replace (b * (c - 1) + (b - 1)) with (b*c-1);try ring;auto with zarith.
  apply Zmult_lt_0_compat;auto with zarith.
 Qed.

 Lemma div_le_0 : forall p x, 0 <= x -> 0 <= x / 2 ^ p.
 Proof.
  intros p x Hle;destruct (Z_le_gt_dec 0 p).
  apply  Zdiv_le_lower_bound;auto with zarith. 
  replace (2^p) with 0.
  destruct x;compute;intro;discriminate.
  destruct p;trivial;discriminate z.
 Qed.
 
 Lemma div_lt : forall p x y, 0 <= x < y -> x / 2^p < y.
 Proof.
  intros p x y H;destruct (Z_le_gt_dec 0 p).
  apply Zdiv_lt_upper_bound;auto with zarith. 
  apply Zlt_le_trans with y;auto with zarith.
  rewrite <- (Zmult_1_r y);apply Zmult_le_compat;auto with zarith.
  assert (0 < 2^p);auto with zarith.
  replace (2^p) with 0.
  destruct x;change (0<y);auto with zarith.
  destruct p;trivial;discriminate z.
 Qed.