-
Notifications
You must be signed in to change notification settings - Fork 1
Expand file tree
/
Copy pathLagrange_four_square.v
More file actions
666 lines (559 loc) · 20.6 KB
/
Lagrange_four_square.v
File metadata and controls
666 lines (559 loc) · 20.6 KB
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
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
Require Import ZArith Lia Znumtheory.
Require Import Natsets MyNat Ztools Zeqm Znumfacts.
(** Definition of the predicate : being the sum of four squares *)
Definition foursquare (n : Z) : Type :=
{a : _ & { b: _ & { c : _ & { d |
n = a * a + b * b + c * c + d * d
}}}}.
(** Euler's identity and compatibility of the 4-square property wrt. multiplication *)
Lemma euler's_identity : forall a b c d w x y z : Z,
let s z := z * z in
(a * a + b * b + c * c + d * d) * (w * w + x * x + y * y + z * z) =
s (a*w + b*x + c*y + d*z) +
s (a*x - b*w - c*z + d*y) +
s (a*y + b*z - c*w - d*x) +
s (a*z - b*y + c*x - d*w).
Proof.
intros; unfold s.
ring.
Qed.
Lemma mult_foursquare_compat : forall n m : Z,
foursquare n -> foursquare m -> foursquare (n * m)%Z.
Proof.
intros n m (a, (b, (c, (d, Hn)))) (x, (y, (z, (t, Hm)))); subst.
rewrite euler's_identity.
repeat eexists.
Defined.
Lemma Zmod_sqrt_eq_compat : forall p i j, prime p ->
(0 <= i -> 0 <= j -> 2 * i < p -> 2 * j < p ->
i * i ≡ j * j [p] -> i = j)%Z.
Proof.
intros p i j Pp Pi Pj Bi Bj ES.
destruct (Z.eq_dec ((i + j) mod p) 0) as [ E | E ].
cut (i + j = 0); [ lia | ].
cut (i + j < p); [ intros H | lia ].
rewrite <- E; symmetry; apply Zmod_small.
lia.
destruct (modular_inverse _ _ Pp E) as (a, Ha).
cut (i ≡ j [p]).
intros M; red in M.
rewrite (Zmod_small i p), (Zmod_small j p) in M; lia.
apply eqm_minus_0.
replace (i - j) with ((i - j) * 1) by ring.
rewrite <- Ha.
apply eqm_minus_0 in ES.
replace 0 with (0 * a) by ring.
rewrite <- ES.
apply eq_eqm; ring.
Qed.
Lemma prime_odd : forall p, 2 <> p -> prime p -> p mod 2 = 1.
Proof.
intros p N2 Pp.
rem (p mod 2) r Er.
pose proof Z_mod_lt p 2 as help_lia.
cut (r <> 0).
lia.
clear help_lia; intros Rn; subst.
apply Zmod_divide in Rn; [ | lia ].
refine (N2 (prime_div_prime _ _ _ _ _)); auto.
apply prime_2.
Qed.
Lemma odd_bound_1 : forall p i, p mod 2 = 1 -> i < Z.succ (p / 2) -> 2 * i < p.
Proof.
intros p i Op Bi.
unfold Z.succ in Bi.
apply Z.le_lt_trans with (2 * (p / 2)).
lia.
rewrite Z_mult_div_mod; [ | auto with * ].
rewrite Op; auto with *.
Qed.
(** [modsym x m] is the unique y congruent to x such that -m/2≤x<m/2 *)
Definition modsym x m := (x + m / 2) mod m - m / 2.
Lemma modsym_bounds : forall x m, 0 < m -> - m <= 2 * modsym x m < m.
Proof.
intros x m Pm; unfold modsym.
pose proof Z_mod_lt (x + m / 2) m.
pose proof Z_mod_lt m 2.
split; ring_simplify; rewrite Z_mult_div_mod; lia.
Qed.
Lemma modsym_mod_compat : forall x m, (modsym x m) mod m = x mod m.
Proof.
intros x m; unfold modsym.
rewrite Zminus_mod_idemp_l.
f_equal; ring.
Qed.
Lemma mod_modsym_compat : forall x m, modsym (x mod m) m = modsym x m.
Proof.
intros x m; unfold modsym.
rewrite Zplus_mod_idemp_l; auto.
Qed.
Lemma modsym_mod_diff : forall x m, 0 < m -> { k | modsym x m = x mod m + m * k }.
Proof.
intros x m.
exists ((modsym x m - x mod m) / m).
rewrite Z_mult_div_mod; [ | auto with * ].
rewrite Zminus_mod, modsym_mod_compat.
rewrite Zminus_mod_idemp_l.
do 2 rewrite Zminus_mod_idemp_r.
rewrite Z.sub_diag, Zmod_0_l.
ring.
Qed.
Lemma modsym_eqm : forall x m, modsym x m ≡ x [ m ].
Proof.
intros x m.
apply modsym_mod_compat.
Qed.
Lemma prime_div_false : forall a p, prime p -> (a | p) -> 1 < a < p -> False.
Proof.
intros a p Pp D Bp.
destruct (prime_divisors p Pp a D) as [|[|[|]]]; lia.
Qed.
Lemma Zbounding_square : forall x m, 0 < m -> -m <= x <= m -> x ^ 2 <= m ^ 2.
Proof.
intros x m Pm Bx.
simpl; unfold Zpower_pos; simpl.
rewrite Zmult_assoc.
rewrite <- Z.abs_square.
apply Z.le_trans with (Z.abs x * m).
rewrite <- Zmult_assoc.
apply Zmult_le_compat_l; lia.
rewrite Zmult_comm.
apply Zmult_le_compat_l; lia.
Qed.
(** All prime numbers divides some [1+l²+m²] (plus convenient conditions on [l,m]) *)
Lemma prime_dividing_sum_of_two_squares_plus_one : forall p,
prime p -> 3 <= p ->
{l : _ & {m : _ & { k |
p * k = 1 + l * l + m * m /\
2 * m < p /\ 2 * l < p /\ 0 < k /\ 0 <= l /\ 0 <= m /\ (0 < l \/ 0 < m)}}}.
Proof.
intros p Pp Op.
pose (np := Z.abs_nat p).
assert (p_odd : p mod 2 = 1) by (apply prime_odd; auto || lia).
pose (s := fun x : Z => x * x).
assert (s_pos : forall x, 0 <= s x).
intros; unfold s; rewrite <- Z.abs_square.
apply Zmult_le_0_compat; auto with *.
assert (mod_pos : forall x, 0 <= x mod p).
intros; apply Z_mod_lt; destruct Pp; lia.
assert (hp_pos : 0 <= p / 2) by (apply Z_div_pos; lia).
assert (autobound : forall i, (i < S (Z.abs_nat (p / 2)))%nat -> 2 * Z_of_nat i < p).
intros i Li.
apply inj_lt in Li.
rewrite inj_S, inj_Zabs_nat, Z.abs_eq in Li; auto.
apply odd_bound_1; auto.
pose (FL := fun l => Z.abs_nat (s (Z_of_nat l) mod p)).
pose (FM := fun m => Z.abs_nat ((-1 - s (Z_of_nat m)) mod p)).
assert (IFL : injective (S (Z.abs_nat (p / 2))) FL).
intros i j Li Lj E.
unfold FL in E.
apply Zabs_nat_inj in E; eauto.
apply inj_eq_rev.
apply (Zmod_sqrt_eq_compat p (Z_of_nat i) (Z_of_nat j)); auto with *.
assert (IFM : injective (S (Z.abs_nat (p / 2))) FM).
intros i j Li Lj E.
unfold FM in E.
apply inj_eq_rev.
apply (Zmod_sqrt_eq_compat p (Z_of_nat i) (Z_of_nat j)); auto with *.
apply Zabs_nat_inj in E; eauto.
symmetry; apply eqm_minus_0.
apply eqm_minus_0 in E.
rewrite <- E.
apply eq_eqm; unfold s; ring.
assert (BFL : bounded (S (Z.abs_nat (p / 2))) (Z.abs_nat p) FL).
intros i _.
unfold FL.
apply inj_lt_rev; do 2 rewrite inj_Zabs_nat.
repeat rewrite Z.abs_eq; auto with *.
apply Z_mod_lt; auto with *.
assert (BFM : bounded (S (Z.abs_nat (p / 2))) (Z.abs_nat p) FM).
intros i _.
unfold FM.
apply inj_lt_rev; do 2 rewrite inj_Zabs_nat.
repeat rewrite Z.abs_eq; auto with *.
apply Z_mod_lt; auto with *.
assert (CL := count_image_injective (S (Z.abs_nat (p / 2))) np FL IFL BFL).
assert (CM := count_image_injective (S (Z.abs_nat (p / 2))) np FM IFM BFM).
remember (image FL (S (Z.abs_nat (p / 2)))) as L.
remember (image FM (S (Z.abs_nat (p / 2)))) as M.
destruct (count_drawers L M np) as (i, (Bi, (Li, Mi))).
rewrite CL, CM.
apply inj_lt_rev.
rewrite inj_plus, inj_S, inj_Zabs_nat.
rewrite Z.abs_eq; auto.
unfold np; rewrite inj_Zabs_nat, Z.abs_eq; auto with *.
unfold Z.succ.
ring_simplify.
pose proof Z_mult_div_bounds p 2.
lia.
rewrite HeqL in Li; rewrite HeqM in Mi.
destruct (image_true _ _ _ Li) as (l, (Bl, Hl)).
destruct (image_true _ _ _ Mi) as (m, (Bm, Hm)).
exists (Z_of_nat l); exists (Z_of_nat m).
unfold FL in Hl; unfold FM in Hm.
clear HeqL CL HeqM CM Li Mi IFL IFM BFL BFM FL FM.
subst.
apply inj_eq in Hm; do 2 rewrite inj_Zabs_nat in Hm.
do 2 rewrite Z.abs_eq in Hm; auto.
symmetry in Hm; apply eqm_minus_0 in Hm.
rewrite divide_eqm in Hm; notzero.
pose proof s_pos (Z_of_nat l).
pose proof s_pos (Z_of_nat m).
destruct (Zdivide_inf _ _ Hm) as (k, Hk).
exists k.
assert (0 < k * p) by lia.
assert (0 < k) by (apply Zmult_lt_0_reg_r with p; assumption || lia).
assert (3 <= k * p).
(* TODO Zle transitif dans MyZ *)
replace 3 with (1 * 3) by reflexivity.
apply Zmult_le_compat; lia.
repeat split; auto with *.
rewrite Zmult_comm, <- Hk.
unfold s; ring.
rem (Z_of_nat l) lz Elz.
rem (Z_of_nat m) mz Emz.
cut (0 <> lz \/ 0 <> mz); [ lia | ].
cut (0 <> s lz \/ 0 <> s mz).
cut (forall a, 0 <> s a -> 0 <> a). (* TODO : MyZ (?) *)
intros Hyp [?|?]; [left|right]; apply Hyp; auto.
clear; intros [] H; tauto || zify; auto with *.
lia.
Defined.
(** Building bounds to prove things like x1²+x2²+x3²+x4²=m² /\ -m/2≤xi<m/2 => xi=-m/2 *)
Lemma egality_case_sum_of_four : forall a b c d M,
a <= M -> b <= M -> c <= M -> d <= M ->
a + b + c + d = 4 * M -> ((a = M) /\ (b = M)) /\ ((c = M) /\ (d = M)).
Proof.
intros.
lia.
Qed.
Lemma square_bound_equality_case : forall a M,
-M <= a < M -> M * M <= a * a -> a = - M.
Proof.
intros a M Bounds Bsqr.
destruct (Z_le_dec 0 M); [ | lia ].
cut (Z.abs M <= Z.abs a).
intro; lia.
rewrite <- (Z.abs_square M), <- (Z.abs_square a) in Bsqr.
apply sqrt_le_compat; auto with *.
Qed.
Lemma square_bound : forall x m, -m <= x <= m -> x * x <= m * m.
Proof.
intros x m Bx.
assert (Pm : 0 <= m) by lia.
rewrite <- Z.abs_square.
apply Z.le_trans with (Z.abs x * m).
apply Zmult_le_compat_l; auto with *; try lia.
apply Zmult_le_compat_r; auto with *; try lia.
Qed.
Lemma square_bound_opp : forall x m, m <= x <= -m -> x * x <= m * m.
Proof.
intros x m Bx.
rewrite <- (Zmult_opp_opp m m).
apply square_bound; auto with *.
Qed.
Lemma egality_case_sum_of_four_squares : forall a b c d M,
-M <= a < M -> -M <= b < M -> -M <= c < M -> -M <= d < M ->
a * a + b * b + c * c + d * d = 4 * (M * M) ->
((a = -M) /\ (b = -M)) /\ ((c = -M) /\ (d = -M)).
Proof.
intros a b c d m Ba Bb Bc Bd E.
assert (P : forall x, -m <= x < m -> -m <= x <= m) by (intros; lia).
pose proof square_bound _ _ (P _ Ba).
pose proof square_bound _ _ (P _ Bb).
pose proof square_bound _ _ (P _ Bc).
pose proof square_bound _ _ (P _ Bd).
assert (Pm : 0 < m) by lia.
cut ((Z.abs a = m /\ Z.abs b = m) /\ (Z.abs c = m /\ Z.abs d = m)).
intros; lia.
split; split; (rewrite <- (Z.abs_eq m); [ | auto with * ]);
apply sqrt_eq_compat_abs;
lia.
Qed.
(** If [mp] is the sum of four squares, then so is [np] for a smaller [n] *)
Lemma foursquare_prime_factor_decreasing :
forall p, prime p -> forall m, (1 < m /\ m < p)%Z ->
foursquare (m * p) ->
sigT (fun n => ((0 < n /\ n < m)%Z * foursquare (n * p))%type).
Proof.
intros p Pp m (LBm, UBm) FSmp.
assert (help0 : m <> 0); auto with *.
assert (help1 : 0 < m); auto with *.
destruct FSmp as (x1, (x2, (x3, (x4, Hx)))).
pose (y1 := modsym x1 m).
pose (y2 := modsym x2 m).
pose (y3 := modsym x3 m).
pose (y4 := modsym x4 m).
assert (eqm1 : y1 ≡ x1 [m]) by apply modsym_eqm.
assert (eqm2 : y2 ≡ x2 [m]) by apply modsym_eqm.
assert (eqm3 : y3 ≡ x3 [m]) by apply modsym_eqm.
assert (eqm4 : y4 ≡ x4 [m]) by apply modsym_eqm.
assert (Dm : (m | y1 * y1 + y2 * y2 + y3 * y3 + y4 * y4)).
apply divide_eqm; auto.
rewrite eqm1, eqm2, eqm3, eqm4.
rewrite <-Hx, divide_eqm; auto.
apply Z.divide_factor_l.
assert (Dmp : ~ (m | p)).
intros D.
eapply prime_div_false; eauto.
destruct (Zdivide_inf _ _ Dm) as (r, Hr).
exists r.
split.
(* Bounds for the new r *)
assert (Pr : 0 <= r).
apply Zmult_le_0_reg_r with m; auto with *.
rewrite <- Hr.
pose proof Zle_0_square y1.
pose proof Zle_0_square y2.
pose proof Zle_0_square y3.
pose proof Zle_0_square y4.
lia.
assert (Nr : 0 <> r).
(* otherwise yi=0 ⇒ m|xi ⇒ m²|xi² ⇒ m²|mp ⇒ m|p ⇒ baad *)
intros Zr; subst.
(* yi = 0 *)
ring_simplify (0 * m) in Hr.
assert (y0 : (y1 = 0 /\ y2 = 0) /\ (y3 = 0 /\ y4 = 0)).
pose proof Zle_0_square y1.
pose proof Zeq_0_square y1.
pose proof Zle_0_square y2.
pose proof Zeq_0_square y2.
pose proof Zle_0_square y3.
pose proof Zeq_0_square y3.
pose proof Zle_0_square y4.
pose proof Zeq_0_square y4.
lia.
apply Dmp.
apply Zmult_divide_compat_rev_l with m; auto.
rewrite Hx.
repeat apply Zdivide_plus_r;
apply Zdivide_square, divide_eqm; auto.
rewrite <- eqm1; apply eq_eqm; tauto.
rewrite <- eqm2; apply eq_eqm; tauto.
rewrite <- eqm3; apply eq_eqm; tauto.
rewrite <- eqm4; apply eq_eqm; tauto.
assert (Lrm : r <= m).
(* -m≤2*yi<m ⇒ 4yi²≤m² ⇒ 4rm≤4m² ⇒ r≤m *)
apply Zmult_le_reg_r with m; auto with *.
rewrite <- Hr.
apply Zmult_le_reg_r with 4; auto with *.
ring_simplify.
clear -help1 LBm.
assert (B : forall x, 4 * (modsym x m) ^ 2 <= m ^2).
clear -help1; intros x.
pose proof modsym_bounds x m help1 as Bms.
set (y := modsym x m); fold y in Bms; clearbody y.
replace (4 * y ^ 2) with ((2 * y) ^ 2) by ring.
apply Zbounding_square; auto.
now auto with *.
pose proof B x1 as Ey1; fold y1 in Ey1.
pose proof B x2 as Ey2; fold y2 in Ey2.
pose proof B x3 as Ey3; fold y3 in Ey3.
pose proof B x4 as Ey4; fold y4 in Ey4.
lia.
assert (Nmr : r <> m).
(* like for 0 <> r but harder : yi=-m/2 → xi≡m²/4 [m²] → m²|m*p*)
intros Emr; subst.
assert (Eyi : (2 * - y1 = m /\ 2 * - y2 = m) /\ (2 * - y3 = m /\ 2 * - y4 = m)).
(* -m/2≤yi<m/2 donc |yi|≤m/2 mais Σyi²=m² donc |yi|=m/2 donc yi=-m/2 *)
assert (Eyi : (2 * y1 = - m /\ 2 * y2 = - m) /\ (2 * y3 = - m /\ 2 * y4 = - m)).
apply egality_case_sum_of_four_squares;
try (apply modsym_bounds; notzero).
rewrite <- Hr; ring.
lia.
destruct Eyi as ((Ey1, Ey2), (Ey3, Ey4)).
apply Dmp.
apply Zmult_divide_compat_rev_l with m; auto.
rewrite Hx.
apply Zmult_divide_compat_rev_l with 4; notzero.
rewrite <- divide_eqm; notzero.
ring_simplify.
assert (REW : forall x, 4 * x ^ 2 = (2 * x) * (2 * x)) by (intros; ring).
repeat rewrite REW; clear REW.
transitivity (m * m + m * m + m * m + m * m).
cut (forall x y, 2 * -y = m -> y ≡ x [m] ->
(2 * x) * (2 * x) ≡ m * m [4 * (m * m)]).
intros HYP.
repeat apply Zplus_eqm;
(eapply HYP; [ | eassumption ]; eassumption).
intros x y Ey Mxy.
apply eqm_square_half; notzero.
rewrite <- Ey at 2.
apply eqm_mult_compat_l.
rewrite <- Mxy.
replace (- y) with (y + 2 * - y) by ring.
rewrite Ey.
rewrite eqm_minus_0.
apply divide_eqm; notzero.
exists (- 1); ring.
apply divide_eqm; notzero.
exists 1; ring.
lia.
(* FS(r*p) *)
assert (Erpm : (r * p) * (m * m) = (r * m) * (m * p)) by ring.
rewrite Hx, <-Hr in Erpm.
rewrite euler's_identity in Erpm.
rem (y1 * x1 + y2 * x2 + y3 * x3 + y4 * x4) t1 Et1.
rem (y1 * x2 - y2 * x1 - y3 * x4 + y4 * x3) t2 Et2.
rem (y1 * x3 + y2 * x4 - y3 * x1 - y4 * x2) t3 Et3.
rem (y1 * x4 - y2 * x3 + y3 * x2 - y4 * x1) t4 Et4.
assert (D1 : (m | t1)).
rewrite <- divide_eqm; auto; rewrite Et1.
unfold y1, y2, y3, y4; repeat rewrite modsym_eqm.
rewrite <-Hx, divide_eqm; auto.
apply Z.divide_factor_l.
assert (D2 : (m | t2)).
rewrite <- divide_eqm; auto; rewrite Et2.
unfold y1, y2, y3, y4; repeat rewrite modsym_eqm.
try ring (* :-( :-( :-( *).
red; f_equal; ring.
assert (D3 : (m | t3)).
rewrite <- divide_eqm; auto; rewrite Et3.
unfold y1, y2, y3, y4; repeat rewrite modsym_eqm.
red; f_equal; ring.
assert (D4 : (m | t4)).
rewrite <- divide_eqm; auto; rewrite Et4.
unfold y1, y2, y3, y4; repeat rewrite modsym_eqm.
red; f_equal; ring.
exists (t1 / m); exists (t2 / m); exists (t3 / m); exists (t4 / m).
apply Zmult_reg_r with (m * m).
clear -help0; destruct m; auto; intro H; inversion H.
rewrite Erpm.
ring_simplify.
cut (forall a, (m | a) -> (a / m) ^ 2 * m ^ 2 = a ^ 2).
intros Q.
do 4 (rewrite Q; auto).
clear -help0.
intros a D.
destruct (Zdivide_inf m a D) as (k, E); subst.
rewrite Z_div_mult_full; auto.
ring.
Defined.
(** Induction scheme to use the previous lemma *)
(* TODO déplacer ça ? *)
Definition lt_wf_rect :=
fun p (P : nat -> Type) F =>
well_founded_induction_type
(well_founded_ltof nat (fun m => m)) P F p.
(** Using the previous lemma, one can decrease [mp] into [np] to eventually get [p] *)
Lemma foursquare_prime : forall p, prime p -> foursquare p.
Proof.
intros p Pp.
destruct (Z.eq_dec p 2) as [E | E].
(* Case p = 2 *)
do 2 exists 1%Z; do 2 exists 0%Z; auto.
(* Case p >= 3 *)
assert (3 <= p) as Op by
(pose proof (prime_ge_2 p Pp); lia); clear E.
(* We prove : ∃m>0 FS(kp) *)
pose (fs_mult := fun p m =>
prod (foursquare (Z_of_nat (S m) * p))
(Z_of_nat (S m) < p)).
assert (sigT (fs_mult p)) as Hm.
(* .. using the previous lemma *)
destruct (prime_dividing_sum_of_two_squares_plus_one p Pp Op) as
(l, (m, (k, (Ep, (Bm, (Bl, (Pk, Plm))))))).
assert (tech1 : Z_of_nat (S (Z.abs_nat (k - 1))) = k).
rewrite inj_S, inj_Zabs_nat, Z.abs_eq; [ | lia ]; auto with *.
exists (Z.abs_nat (k - 1)); split.
(* FS(kp) *)
exists 0%Z; exists 1%Z; exists l; exists m.
transitivity (p * k).
rewrite tech1; ring.
rewrite Ep; auto.
(* Big part, the bound: k<p *)
rewrite tech1; clear tech1.
apply Zmult_lt_reg_r with (4 * p); [ auto with * | ].
replace (p * (4 * p)) with (2 * (p * p) + 2 * (p * p)) by ring.
replace (k * (4 * p)) with (4 * (p * k)) by ring.
rewrite Ep.
assert (tech2 : forall a b, 0 < a -> 2 * a < b -> 4 * a * a + 4 < b * b).
clear; intros a b Pa LT.
assert (LE : 2 * a + 1 <= b) by lia.
assert (Pda : 0 <= 2 * a + 1) by lia.
assert (LE2 := Zmult_le_compat _ _ _ _ LE LE Pda Pda).
eapply Z.lt_le_trans; [ | apply LE2 ].
ring_simplify.
lia.
assert (tech3 : forall a b, 0 <= a -> 2 * a < b -> 4 * a * a < b * b).
clear; intros a b Pa LT.
assert (LE : 2 * a + 1 <= b) by lia.
assert (Pda : 0 <= 2 * a + 1) by lia.
assert (LE2 := Zmult_le_compat _ _ _ _ LE LE Pda Pda).
eapply Z.lt_le_trans; [ | apply LE2 ].
ring_simplify.
lia.
assert (p2_pos : 0 < p * p).
transitivity (1 * p).
lia.
apply Zmult_lt_compat_r; lia.
rem (l * l) ll Ell.
rem (m * m) mm Emm.
rem (p * p) pp Epp.
destruct Plm as (NNl, (NNm, [Pl | Pm])).
specialize (tech2 _ p Pl Bl).
specialize (tech3 _ p NNm Bm).
rewrite <- Zmult_assoc, <-Ell, <-Emm, <-Epp in *.
clear -tech2 tech3 p2_pos.
ring_simplify.
lia.
specialize (tech2 _ p Pm Bm).
specialize (tech3 _ p NNl Bl).
rewrite <- Zmult_assoc, <-Ell, <-Emm, <-Epp in *.
clear -tech2 tech3 p2_pos.
ring_simplify.
lia.
(* De "k<p" à ici : majoration beaucoup trop fine ! (2p² au
lieu de 4p²) Donc partie potentiellement beaucoup plus courte
et rapide à exécuter. *)
(* To prove FS(p) we can prove ∀m>0 (FS(mp) -> FS(p)) *)
clear Op.
destruct Hm as (m, Hm).
generalize p Pp m Hm; clear Hm m Pp p.
intros p Pp m.
refine (lt_wf_rect m (fun n => fs_mult p n -> foursquare p) _); clear m.
intros [|m] IH (FSm, UBm).
(* m=1 *)
destruct p; assumption.
(* m>1 *)
assert (LBm : 1 < Z_of_nat (S (S m))) by lia.
destruct (foursquare_prime_factor_decreasing p Pp _ (conj LBm UBm) FSm) as (n, ((LBn, UBn), FSn)).
apply IH with (Z.abs_nat (n - 1)).
unfold ltof.
lia.
unfold fs_mult.
rewrite inj_S, inj_Zabs_nat, Z.abs_eq; auto with *; unfold Z.succ.
replace (n - 1 + 1) with n by ring.
split; auto; lia.
Defined.
(** Trivial application of the previous lemma and euler's identity *)
Theorem lagrange_4_square_theorem : forall n, 0 <= n -> foursquare n.
Proof.
intros n; eapply Z_prime_rect; auto.
repeat (exists 0); auto.
exists 1; repeat (exists 0); auto.
apply foursquare_prime.
apply mult_foursquare_compat.
Defined.
Definition lagrange_fun (n : Z) : (Z * Z) * (Z * Z) :=
let (a, ha) := lagrange_4_square_theorem (Z.abs n) (Zabs_pos n) in
let (b, hb) := ha in
let (c, hc) := hb in
let (d, _ ) := hc in
((a, b), (c, d)).
Lemma lagrange_fun_spec (n : Z) :
(let (ab, cd) := lagrange_fun n in let (a, b) := ab in let (c, d) := cd in
Z.abs n = a * a + b * b + c * c + d * d).
Proof.
unfold lagrange_fun.
destruct (lagrange_4_square_theorem (Z.abs n) (Zabs_pos n)) as (a, (b, (c, (d, pr)))).
exact pr.
Qed.
(*
Require Extraction.
Extraction "Lagrange_four_square.ml" lagrange_fun.
*)
(*
Eval compute in lagrange_fun 0.
Print Opaque Dependencies lagrange_4_square_theorem.
*)