-
Notifications
You must be signed in to change notification settings - Fork 1
/
Formula.v
2239 lines (2076 loc) · 64 KB
/
Formula.v
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
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
(* Euler Product Formula *)
(* https://en.wikipedia.org/wiki/Proof_of_the_Euler_product_formula_for_the_Riemann_zeta_function *)
Set Nested Proofs Allowed.
Require Import Utf8 Arith Psatz Setoid Morphisms.
Require Import Sorting.Permutation SetoidList.
Import List List.ListNotations.
Require Import Misc Primes.
(* ζ(s) = Σ (n ∈ ℕ* ) 1/n^s = Π (p ∈ Primes) 1/(1-1/p^s) *)
(* Here ζ is not applied to ℂ as usual, but to any field, whose
type is defined below; most of the theorems has a field f
as implicit first parameter.
And we have never to evaluate a value ζ(s) for a given s,
so the ζ function is just defined by the coefficients of
its terms. See type ln_series below. *)
Class field :=
{ f_type : Set;
f_zero : f_type;
f_one : f_type;
f_add : f_type → f_type → f_type;
f_mul : f_type → f_type → f_type;
f_opp : f_type → f_type;
f_inv : f_type → f_type;
f_add_comm : ∀ x y, f_add x y = f_add y x;
f_add_assoc : ∀ x y z, f_add x (f_add y z) = f_add (f_add x y) z;
f_add_0_l : ∀ x, f_add f_zero x = x;
f_add_opp_diag_l : ∀ x, f_add (f_opp x) x = f_zero;
f_mul_comm : ∀ x y, f_mul x y = f_mul y x;
f_mul_assoc : ∀ x y z, f_mul x (f_mul y z) = f_mul (f_mul x y) z;
f_mul_1_l : ∀ x, f_mul f_one x = x;
f_mul_inv_diag_l : ∀ x, x ≠ f_zero → f_mul (f_inv x) x = f_one;
f_mul_add_distr_l : ∀ x y z,
f_mul x (f_add y z) = f_add (f_mul x y) (f_mul x z) }.
Declare Scope field_scope.
Delimit Scope field_scope with F.
Definition f_sub {F : field} x y := f_add x (f_opp y).
Notation "- x" := (f_opp x) : field_scope.
Notation "x + y" := (f_add x y) : field_scope.
Notation "x - y" := (f_sub x y) : field_scope.
Notation "x * y" := (f_mul x y) : field_scope.
Notation "0" := (f_zero) : field_scope.
Notation "1" := (f_one) : field_scope.
Theorem f_add_0_r {F : field} : ∀ x, (x + 0)%F = x.
Proof.
intros.
rewrite f_add_comm.
apply f_add_0_l.
Qed.
Theorem f_opp_0 {F : field} : (- 0)%F = 0%F.
Proof.
rewrite <- (f_add_0_r (- 0)%F).
apply f_add_opp_diag_l.
Qed.
Theorem f_add_opp_diag_r {F : field} : ∀ x, (x + - x = 0)%F.
Proof.
intros.
rewrite f_add_comm.
apply f_add_opp_diag_l.
Qed.
Theorem f_add_sub {F : field} : ∀ x y, (x + y - y)%F = x.
Proof.
intros.
unfold f_sub.
rewrite <- f_add_assoc.
rewrite f_add_opp_diag_r.
now rewrite f_add_0_r.
Qed.
Theorem f_add_move_r {F : field} : ∀ x y z, (x + y)%F = z ↔ x = (z - y)%F.
Proof.
intros.
split.
-intros H.
rewrite <- H.
now rewrite f_add_sub.
-intros H.
rewrite H.
unfold f_sub.
rewrite <- f_add_assoc.
rewrite f_add_opp_diag_l.
now rewrite f_add_0_r.
Qed.
Theorem f_add_move_0_r {F : field} : ∀ x y, (x + y = 0)%F ↔ x = (- y)%F.
Proof.
intros.
split.
-intros H.
apply f_add_move_r in H.
unfold f_sub in H.
now rewrite f_add_0_l in H.
-intros H.
apply f_add_move_r.
unfold f_sub.
now rewrite f_add_0_l.
Qed.
Theorem f_add_add_swap {F : field} : ∀ x y z, (x + y + z = x + z + y)%F.
Proof.
intros.
do 2 rewrite <- f_add_assoc.
apply f_equal, f_add_comm.
Qed.
Theorem f_mul_mul_swap {F : field} : ∀ x y z, (x * y * z = x * z * y)%F.
Proof.
intros.
do 2 rewrite <- f_mul_assoc.
apply f_equal, f_mul_comm.
Qed.
Theorem f_opp_involutive {F : field} : ∀ x, (- - x)%F = x.
Proof.
intros.
symmetry.
apply f_add_move_0_r.
apply f_add_opp_diag_r.
Qed.
Theorem f_mul_add_distr_r {F : field} : ∀ x y z,
((x + y) * z)%F = (x * z + y * z)%F.
Proof.
intros.
rewrite f_mul_comm, f_mul_add_distr_l.
now do 2 rewrite (f_mul_comm z).
Qed.
Theorem f_mul_0_l {F : field} : ∀ x, (0 * x = 0)%F.
Proof.
intros.
assert (H : (0 * x + x = x)%F). {
transitivity ((0 * x + 1 * x)%F).
-now rewrite f_mul_1_l.
-rewrite <- f_mul_add_distr_r.
now rewrite f_add_0_l, f_mul_1_l.
}
apply f_add_move_r in H.
unfold f_sub in H.
now rewrite f_add_opp_diag_r in H.
Qed.
Theorem f_mul_0_r {F : field} : ∀ x, (x * 0 = 0)%F.
Proof.
intros.
rewrite f_mul_comm.
apply f_mul_0_l.
Qed.
Theorem f_eq_mul_0_l {F : field} : ∀ x y,
(x * y = 0)%F → y ≠ 0%F → x = 0%F.
Proof.
intros * Hxy Hy.
rewrite f_mul_comm in Hxy.
apply (f_equal (f_mul (f_inv y))) in Hxy.
rewrite f_mul_0_r, f_mul_assoc in Hxy.
rewrite f_mul_inv_diag_l in Hxy; [ | easy ].
now rewrite f_mul_1_l in Hxy.
Qed.
Theorem f_mul_opp_l {F : field} : ∀ x y, (- x * y = - (x * y))%F.
Proof.
intros.
apply f_add_move_0_r.
rewrite <- f_mul_add_distr_r.
rewrite f_add_opp_diag_l.
apply f_mul_0_l.
Qed.
Theorem f_mul_opp_r {F : field} : ∀ x y, (x * - y = - (x * y))%F.
Proof.
intros.
now rewrite f_mul_comm, f_mul_opp_l, f_mul_comm.
Qed.
Theorem f_mul_1_r {F : field} : ∀ x, (x * 1)%F = x.
Proof.
intros.
rewrite f_mul_comm.
apply f_mul_1_l.
Qed.
(* Euler product formula *)
(*
Riemann zeta function is
ζ(s) = 1 + 1/2^s + 1/3^s + 1/4^s + 1/5^s + ...
Euler product formula is the fact that
1
ζ(s) = -----------------------------------------------
(1-1/2^s) (1-1/3^s) (1-1/5^s) ... (1-1/p^s) ...
where the product in the denominator applies on all prime numbers
and only them.
The proof is the following.
We first prove that
ζ(s) (1-1/2^s) = 1 + 1/3^s + 1/5^s + 1/7^s + ...
i.e. all terms but the multiples of 2
i.e. all odd numbers
(this is easy to verify on a paper)
Then we continue by proving
ζ(s) (1-1/2^s) (1-1/3^s) =
1 + 1/5^s + 1/7^s + 1/11^s + ... + 1/23^s + 1/25^s + ...
i.e. all terms but the multiples of 2 and 3
Then we do it for the number 5 in the second term (1/5^s) of the series.
This number in the second term is always the next prime number, like in the
Sieve of Eratosthenes.
Up to prime number p, we have, using commutativity
ζ(s) (1-1/2^s) (1-1/3^s) ... (1-1/p^s) = 1 + 1/q^s + ...
where q is the prime number after p and the rest holds terms whose
number is greater than q and not divisible by the primes between
2 and p.
When p tends towards infinity, the term to the right is just 1
and we get Euler's formula.
---
Implementation.
ζ(s) and all the expressions above are actually of the form
a₁ + a₂/2^s + a₃/3^s + a₄/4^s + ...
We can represent them by the sequence
(a_n) = (a₁, a₂, a₃, ...)
For example, ζ is (1, 1, 1, 1, ...)
and (1-1/3^s) is (1, 0, -1, 0, 0, 0, ...)
We call them "series with logarithm powers" because they can be
written
a₁ + a₂ x^ln(2) + a₃ x^ln(3) + a₄ x^ln(4) + a₅ x^ln(5) + ...
with x = e^(-s). Easy to verify.
Note that we do not consider the parameters s or x. The fact that
they are supposed to be complex number is irrelevant in this proof.
We just consider they belong to a field (type "field" defined
above).
*)
(* Definition of the type of such a series; a value s of this
type is a function ls : nat → field representing the series
ls(1) + ls(2)/2^s + ls(3)/3^s + ls(4)/4^s + ...
or the equivalent form with x at a logarithm power
ls(1) + ls(2).x^ln(2) + ls(3).x^ln(3) + ls(4).x^ln(4)+...
where x = e^(-s)
*)
Class ln_series {F : field} :=
{ ls : nat → f_type }.
(* Definition of the type of a polynomial: this is just
a finite series; it can be represented by a list *)
Class ln_polyn {F : field} :=
{ lp : list f_type }.
(* Syntactic scopes, allowing to use operations on series and
polynomials with usual mathematical forms. For example we can
write e.g.
(s1 * s2 + s3)%LS
instead of the less readable
ls_add (ls_mul s1 s2) s3
*)
Declare Scope ls_scope.
Delimit Scope ls_scope with LS.
Declare Scope lp_scope.
Delimit Scope lp_scope with LP.
Arguments ls {_} _%LS _%nat.
Arguments lp {_}.
(* Equality between series; since these series start with 1, the
comparison is only on natural indices different from 0 *)
Definition ls_eq {F : field} s1 s2 := ∀ n, n ≠ 0 → ls s1 n = ls s2 n.
Arguments ls_eq _ s1%LS s2%LS.
(* which is an equivalence relation *)
Theorem ls_eq_refl {F : field} : reflexive _ ls_eq.
Proof. easy. Qed.
Theorem ls_eq_sym {F : field} : symmetric _ ls_eq.
Proof.
intros x y Hxy i Hi.
now symmetry; apply Hxy.
Qed.
Theorem ls_eq_trans {F : field} : transitive _ ls_eq.
Proof.
intros x y z Hxy Hyz i Hi.
now eapply eq_trans; [ apply Hxy | apply Hyz ].
Qed.
Add Parametric Relation {F : field} : (ln_series) ls_eq
reflexivity proved by ls_eq_refl
symmetry proved by ls_eq_sym
transitivity proved by ls_eq_trans
as ls_eq_rel.
(* The unit series: 1 + 0/2^s + 0/3^s + 0/4^s + ... *)
Definition ls_one {F : field} :=
{| ls n := match n with 1 => 1%F | _ => 0%F end |}.
(* Notation for accessing a series coefficient at index i *)
Notation "r ~{ i }" := (ls r i) (at level 1, format "r ~{ i }").
(* adding, opposing, subtracting polynomials *)
Definition lp_add {F : field} p q :=
{| lp :=
List.map (prod_curry f_add) (List_combine_all (lp p) (lp q) 0%F) |}.
Definition lp_opp {F : field} p := {| lp := List.map f_opp (lp p) |}.
Definition lp_sub {F : field} p q := lp_add p (lp_opp q).
Notation "x - y" := (lp_sub x y) : lp_scope.
Notation "1" := (ls_one) : ls_scope.
(* At last, the famous ζ function: all its coefficients are 1 *)
Definition ζ {F : field} := {| ls _ := 1%F |}.
(* Series where the indices, which are multiple of some n, are 0
1 + ls(2)/2^s + ls(3)/3^s + ... + ls(n-1)/(n-1)^s + 0/n^s +
... + ls(ni-1)/(ni-1)^s + 0/ni^s + ls(ni+1)/(ni+1)^s + ...
This special series allows to cumulate the multiplications of
terms of the form (1-1/p^s); when doing (1-1/p^s).ζ, the result
is ζ without all terms multiple of p *)
Definition series_but_mul_of {F : field} n s :=
{| ls i :=
match i mod n with
| 0 => 0%F
| _ => ls s i
end |}.
(* product of series is like the convolution product but
limited to divisors; indeed the coefficient of the term
in x^ln(n), resulting of the multiplication of two series
u and v, is the sum:
u_1.v_n + ... u_d.v_{n/d} + ... u_n.v_1
where d covers all the divisors of n *)
Definition log_prod_term {F : field} u v n i :=
(u i * v (n / i))%F.
Definition log_prod_list {F : field} u v n :=
List.map (log_prod_term u v n) (divisors n).
Definition log_prod {F : field} u v n :=
List.fold_left f_add (log_prod_list u v n) 0%F.
(* Σ (i = 1, ∞) s1_i x^ln(i) * Σ (i = 1, ∞) s2_i x^ln(i) *)
Definition ls_mul {F : field} s1 s2 :=
{| ls := log_prod (ls s1) (ls s2) |}.
(* polynomial seen as a series *)
Definition ls_of_pol {F : field} p :=
{| ls n :=
match n with
| 0 => 0%F
| S n' => List.nth n' (lp p) 0%F end |}.
Definition ls_pol_mul_r {F : field} s p :=
ls_mul s (ls_of_pol p).
Arguments ls_of_pol _ p%LP.
Arguments ls_pol_mul_r _ s%LS p%LP.
Notation "x = y" := (ls_eq x y) : ls_scope.
Notation "x * y" := (ls_mul x y) : ls_scope.
Notation "s *' p" := (ls_pol_mul_r s p) (at level 41, left associativity) :
ls_scope.
Theorem in_divisors : ∀ n,
n ≠ 0 → ∀ d, d ∈ divisors n → n mod d = 0 ∧ d ≠ 0.
Proof.
intros * Hn *.
unfold divisors.
intros Hd.
apply filter_In in Hd.
destruct Hd as (Hd, Hnd).
split; [ now apply Nat.eqb_eq | ].
apply in_seq in Hd; flia Hd.
Qed.
Theorem in_divisors_iff : ∀ n,
n ≠ 0 → ∀ d, d ∈ divisors n ↔ n mod d = 0 ∧ d ≠ 0.
Proof.
intros * Hn *.
unfold divisors.
split; [ now apply in_divisors | ].
intros (Hnd, Hd).
apply filter_In.
split; [ | now apply Nat.eqb_eq ].
apply in_seq.
split; [ flia Hd | ].
apply Nat.mod_divides in Hnd; [ | easy ].
destruct Hnd as (c, Hc).
rewrite Nat.mul_comm in Hc; rewrite Hc.
destruct c; [ easy | ].
cbn; flia.
Qed.
Theorem divisor_inv : ∀ n d, d ∈ divisors n → n / d ∈ divisors n.
Proof.
intros * Hd.
apply List.filter_In in Hd.
apply List.filter_In.
destruct Hd as (Hd, Hm).
apply List.in_seq in Hd.
apply Nat.eqb_eq in Hm.
rewrite Nat_mod_0_mod_div; [ | flia Hd | easy ].
split; [ | easy ].
apply Nat.mod_divides in Hm; [ | flia Hd ].
destruct Hm as (m, Hm).
rewrite Hm at 1.
apply List.in_seq.
rewrite Nat.mul_comm, Nat.div_mul; [ | flia Hd ].
split.
+apply (Nat.mul_lt_mono_pos_l d); [ flia Hd | ].
flia Hm Hd.
+rewrite Hm.
destruct d; [ flia Hd | cbn; flia ].
Qed.
(* allows to rewrite H1, H2 with
H1 : s1 = s3
H2 : s2 = s4
in expression
(s1 * s2)%LS
changing it into
(s3 * s4)%LS *)
Local Instance ls_mul_morph {F : field} :
Proper (ls_eq ==> ls_eq ==> ls_eq) ls_mul.
Proof.
intros s1 s2 Hs12 s'1 s'2 Hs'12 n Hn.
cbn - [ log_prod ].
unfold log_prod, log_prod_list; f_equal.
specialize (in_divisors n Hn) as Hd.
remember (divisors n) as l eqn:Hl; clear Hl.
induction l as [| a l]; [ easy | cbn ].
rewrite IHl; [ | now intros d Hdl; apply Hd; right ].
f_equal.
unfold log_prod_term.
specialize (Hd a (or_introl eq_refl)) as Ha.
destruct Ha as (Hna, Ha).
rewrite Hs12; [ | easy ].
rewrite Hs'12; [ easy | ].
apply Nat.mod_divides in Hna; [ | easy ].
destruct Hna as (c, Hc).
rewrite Hc, Nat.mul_comm, Nat.div_mul; [ | easy ].
now intros H; rewrite Hc, H, Nat.mul_0_r in Hn.
Qed.
Theorem divisors_are_sorted : ∀ n, Sorted.Sorted lt (divisors n).
Proof.
intros.
unfold divisors.
specialize (SetoidList.filter_sort eq_equivalence Nat.lt_strorder) as H2.
specialize (H2 Nat.lt_wd).
specialize (H2 (λ a, n mod a =? 0) (seq 1 n)).
now specialize (H2 (Sorted_Sorted_seq _ _)).
Qed.
Theorem sorted_gt_lt_rev : ∀ l, Sorted.Sorted gt l → Sorted.Sorted lt (rev l).
Proof.
intros l Hl.
induction l as [| a l]; [ constructor | cbn ].
apply (SetoidList.SortA_app eq_equivalence).
-now apply IHl; inversion Hl.
-now constructor.
-intros x y Hx Hy.
apply SetoidList.InA_alt in Hy.
destruct Hy as (z & Haz & Hza); subst z.
destruct Hza; [ subst a | easy ].
apply SetoidList.InA_rev in Hx.
rewrite List.rev_involutive in Hx.
apply SetoidList.InA_alt in Hx.
destruct Hx as (z & Haz & Hza); subst z.
apply Sorted.Sorted_inv in Hl.
destruct Hl as (Hl, Hyl).
clear IHl.
induction Hyl; [ easy | ].
destruct Hza as [Hx| Hx]; [ now subst x | ].
transitivity b; [ clear H | easy ].
assert (Hgtt : Relations_1.Transitive gt). {
unfold gt.
clear; intros x y z Hxy Hyz.
now transitivity y.
}
apply Sorted.Sorted_StronglySorted in Hl; [ | easy ].
inversion Hl; subst.
specialize (proj1 (Forall_forall (gt b) l) H2) as H3.
now apply H3.
Qed.
Theorem sorted_equiv_nat_lists : ∀ l l',
Sorted.Sorted lt l
→ Sorted.Sorted lt l'
→ (∀ a, a ∈ l ↔ a ∈ l')
→ l = l'.
Proof.
intros * Hl Hl' Hll.
revert l' Hl' Hll.
induction l as [| a l]; intros. {
destruct l' as [| a' l']; [ easy | ].
now specialize (proj2 (Hll a') (or_introl eq_refl)) as H1.
}
destruct l' as [| a' l']. {
now specialize (proj1 (Hll a) (or_introl eq_refl)) as H1.
}
assert (Hltt : Relations_1.Transitive lt). {
intros x y z Hxy Hyz.
now transitivity y.
}
assert (Haa : a = a'). {
specialize (proj1 (Hll a) (or_introl eq_refl)) as H1.
destruct H1 as [H1| H1]; [ easy | ].
specialize (proj2 (Hll a') (or_introl eq_refl)) as H2.
destruct H2 as [H2| H2]; [ easy | ].
apply Sorted.Sorted_StronglySorted in Hl; [ | easy ].
apply Sorted.Sorted_StronglySorted in Hl'; [ | easy ].
inversion Hl; subst.
inversion Hl'; subst.
specialize (proj1 (Forall_forall (lt a) l) H4) as H7.
specialize (proj1 (Forall_forall (lt a') l') H6) as H8.
specialize (H7 _ H2).
specialize (H8 _ H1).
flia H7 H8.
}
subst a; f_equal.
apply IHl.
-now apply Sorted.Sorted_inv in Hl.
-now apply Sorted.Sorted_inv in Hl'.
-intros a; split; intros Ha.
+specialize (proj1 (Hll _) (or_intror Ha)) as H1.
destruct H1 as [H1| H1]; [ | easy ].
subst a'.
apply Sorted.Sorted_StronglySorted in Hl; [ | easy ].
inversion Hl; subst.
specialize (proj1 (Forall_forall (lt a) l) H2) as H3.
specialize (H3 _ Ha); flia H3.
+specialize (proj2 (Hll _) (or_intror Ha)) as H1.
destruct H1 as [H1| H1]; [ | easy ].
subst a'.
apply Sorted.Sorted_StronglySorted in Hl'; [ | easy ].
inversion Hl'; subst.
specialize (proj1 (Forall_forall (lt a) l') H2) as H3.
specialize (H3 _ Ha); flia H3.
Qed.
Theorem map_inv_divisors : ∀ n,
divisors n = List.rev (List.map (λ i, n / i) (divisors n)).
Proof.
intros.
specialize (divisors_are_sorted n) as H1.
assert (H2 : Sorted.Sorted lt (rev (map (λ i : nat, n / i) (divisors n)))). {
apply sorted_gt_lt_rev.
destruct n; [ constructor | ].
specialize (in_divisors (S n) (Nat.neq_succ_0 _)) as H2.
remember (divisors (S n)) as l eqn:Hl; symmetry in Hl.
clear Hl.
induction l as [| a l]; [ constructor | ].
cbn; constructor.
-apply IHl; [ now inversion H1 | ].
now intros d; intros Hd; apply H2; right.
-clear IHl.
revert a H1 H2.
induction l as [| b l]; intros; [ constructor | ].
cbn; constructor; unfold gt.
apply Sorted.Sorted_inv in H1.
destruct H1 as (_, H1).
apply Sorted.HdRel_inv in H1.
assert (Ha : a ≠ 0). {
intros H; subst a.
now specialize (H2 0 (or_introl eq_refl)) as H3.
}
assert (Hb : b ≠ 0). {
intros H; subst b.
now specialize (H2 0 (or_intror (or_introl eq_refl))) as H3.
}
specialize (Nat.div_mod (S n) a Ha) as H3.
specialize (Nat.div_mod (S n) b Hb) as H4.
specialize (H2 a (or_introl eq_refl)) as H.
rewrite (proj1 H), Nat.add_0_r in H3; clear H.
specialize (H2 b (or_intror (or_introl eq_refl))) as H.
rewrite (proj1 H), Nat.add_0_r in H4; clear H.
apply (Nat.mul_lt_mono_pos_l b); [ flia Hb | ].
rewrite <- H4.
apply (Nat.mul_lt_mono_pos_l a); [ flia Ha | ].
rewrite (Nat.mul_comm _ (_ * _)), Nat.mul_shuffle0.
rewrite <- Nat.mul_assoc, <- H3.
apply Nat.mul_lt_mono_pos_r; [ flia | easy ].
}
apply sorted_equiv_nat_lists; [ easy | easy | ].
intros a.
split; intros Ha.
-apply List.in_rev; rewrite List.rev_involutive.
destruct (zerop n) as [Hn| Hn]; [ now subst n | ].
apply Nat.neq_0_lt_0 in Hn.
specialize (in_divisors n Hn a Ha) as (Hna, Haz).
apply List.in_map_iff.
exists (n / a).
split; [ | now apply divisor_inv ].
apply Nat_mod_0_div_div; [ | easy ].
split; [ flia Haz | ].
apply Nat.mod_divides in Hna; [ | easy ].
destruct Hna as (c, Hc); subst n.
destruct c; [ now rewrite Nat.mul_comm in Hn | ].
rewrite Nat.mul_comm; cbn; flia.
-apply List.in_rev in Ha.
destruct (zerop n) as [Hn| Hn]; [ now subst n | ].
apply Nat.neq_0_lt_0 in Hn.
apply in_divisors_iff; [ easy | ].
apply List.in_map_iff in Ha.
destruct Ha as (b & Hnb & Hb).
subst a.
apply in_divisors; [ easy | ].
now apply divisor_inv.
Qed.
(* Commutativity of product of series *)
Theorem fold_f_add_assoc {F : field} : ∀ a b l,
fold_left f_add l (a + b)%F = (fold_left f_add l a + b)%F.
Proof.
intros.
revert a.
induction l as [| c l]; intros; [ easy | cbn ].
rewrite <- IHl; f_equal.
apply f_add_add_swap.
Qed.
Theorem fold_f_mul_assoc {F : field} : ∀ a b l,
fold_left f_mul l (a * b)%F = (fold_left f_mul l a * b)%F.
Proof.
intros.
revert a.
induction l as [| c l]; intros; [ easy | cbn ].
rewrite <- IHl; f_equal.
apply f_mul_mul_swap.
Qed.
Theorem fold_log_prod_add_on_rev {F : field} : ∀ u v n l,
n ≠ 0
→ (∀ d, d ∈ l → n mod d = 0 ∧ d ≠ 0)
→ fold_left f_add (map (log_prod_term u v n) l) f_zero =
fold_left f_add (map (log_prod_term v u n) (rev (map (λ i, n / i) l)))
f_zero.
Proof.
intros * Hn Hd.
induction l as [| a l]; intros; [ easy | cbn ].
rewrite f_add_0_l.
rewrite List.map_app.
rewrite List.fold_left_app; cbn.
specialize (Hd a (or_introl eq_refl)) as H1.
destruct H1 as (H1, H2).
rewrite <- IHl.
-unfold log_prod_term at 2 4.
rewrite Nat_mod_0_div_div; [ | | easy ]; cycle 1. {
split; [ flia H2 | ].
apply Nat.mod_divides in H1; [ | easy ].
destruct H1 as (c, Hc).
destruct c; [ now rewrite Nat.mul_comm in Hc | ].
rewrite Hc, Nat.mul_comm; cbn; flia.
}
rewrite (f_mul_comm (v (n / a))).
now rewrite <- fold_f_add_assoc, f_add_0_l.
-intros d Hdl.
now apply Hd; right.
Qed.
Theorem fold_log_prod_comm {F : field} : ∀ u v i,
fold_left f_add (log_prod_list u v i) f_zero =
fold_left f_add (log_prod_list v u i) f_zero.
Proof.
intros u v n.
unfold log_prod_list.
rewrite map_inv_divisors at 2.
remember (divisors n) as l eqn:Hl; symmetry in Hl.
destruct (zerop n) as [Hn| Hn]; [ now subst n; cbn in Hl; subst l | ].
apply Nat.neq_0_lt_0 in Hn.
specialize (in_divisors n Hn) as Hd; rewrite Hl in Hd.
now apply fold_log_prod_add_on_rev.
Qed.
Theorem ls_mul_comm {F : field} : ∀ x y,
(x * y = y * x)%LS.
Proof.
intros * i Hi.
cbn - [ log_prod ].
apply fold_log_prod_comm.
Qed.
(* *)
Theorem f_mul_fold_add_distr_l {F : field} : ∀ a b l,
(a * fold_left f_add l b)%F =
(fold_left f_add (map (f_mul a) l) (a * b)%F).
Proof.
intros.
revert a b.
induction l as [| c l]; intros; [ easy | cbn ].
rewrite <- f_mul_add_distr_l.
apply IHl.
Qed.
Theorem f_mul_fold_add_distr_r {F : field} : ∀ a b l,
(fold_left f_add l a * b)%F =
(fold_left f_add (map (f_mul b) l) (a * b)%F).
Proof.
intros.
revert a b.
induction l as [| c l]; intros; [ easy | cbn ].
rewrite (f_mul_comm b).
rewrite <- f_mul_add_distr_r.
apply IHl.
Qed.
Theorem map_f_mul_fold_add_distr_l {F : field} : ∀ (a : nat → f_type) b f l,
map (λ i, (a i * fold_left f_add (f i) b)%F) l =
map (λ i, fold_left f_add (map (f_mul (a i)) (f i)) (a i * b)%F) l.
Proof.
intros a b.
induction l as [| c l]; [ easy | cbn ].
rewrite f_mul_fold_add_distr_l; f_equal.
apply IHl.
Qed.
Theorem map_f_mul_fold_add_distr_r {F : field} : ∀ a (b : nat → f_type) f l,
map (λ i, (fold_left f_add (f i) a * b i)%F) l =
map (λ i, fold_left f_add (map (f_mul (b i)) (f i)) (a * b i)%F) l.
Proof.
intros a b.
induction l as [| c l]; [ easy | cbn ].
rewrite f_mul_fold_add_distr_r; f_equal.
apply IHl.
Qed.
(* The product of series is associative; first, lemmas *)
Definition compare_trip '(i1, j1, k1) '(i2, j2, k2) :=
match Nat.compare i1 i2 with
| Eq =>
match Nat.compare j1 j2 with
| Eq => Nat.compare k1 k2
| c => c
end
| c => c
end.
Definition lt_triplet t1 t2 := compare_trip t1 t2 = Lt.
Definition xyz_zxy '((x, y, z) : (nat * nat * nat)) := (z, x, y).
Theorem map_mul_triplet {F : field} : ∀ u v w (f g h : nat → nat → nat) k l a,
fold_left f_add
(flat_map
(λ d, map (λ d', (u (f d d') * v (g d d') * w (h d d')))%F (k d)) l)
a =
fold_left f_add
(map (λ t, let '(i, j, k) := t in (u i * v j * w k)%F)
(flat_map
(λ d, map (λ d', (f d d', g d d', h d d')) (k d)) l))
a.
Proof.
intros.
revert a.
induction l as [| b l]; intros; [ easy | cbn ].
rewrite map_app.
do 2 rewrite fold_left_app.
rewrite IHl; f_equal; clear.
remember (k b) as l eqn:Hl; clear Hl.
revert a b.
induction l as [| c l]; intros; [ easy | cbn ].
apply IHl.
Qed.
Theorem StrictOrder_lt_triplet : StrictOrder lt_triplet.
Proof.
constructor.
-intros ((i, j), k) H.
unfold lt_triplet, compare_trip in H.
now do 3 rewrite Nat.compare_refl in H.
-unfold lt_triplet, compare_trip.
intros ((a1, a2), a3) ((b1, b2), b3) ((c1, c2), c3) Hab Hbc.
remember (a1 ?= b1) as ab1 eqn:Hab1; symmetry in Hab1.
remember (a1 ?= c1) as ac1 eqn:Hac1; symmetry in Hac1.
remember (b1 ?= c1) as bc1 eqn:Hbc1; symmetry in Hbc1.
remember (a2 ?= b2) as ab2 eqn:Hab2; symmetry in Hab2.
remember (b2 ?= c2) as bc2 eqn:Hbc2; symmetry in Hbc2.
remember (a2 ?= c2) as ac2 eqn:Hac2; symmetry in Hac2.
move ac2 before ab1; move bc2 before ab1; move ab2 before ab1.
move bc1 before ab1; move ac1 before ab1.
destruct ab1; [ | | easy ].
+apply Nat.compare_eq_iff in Hab1; subst b1.
destruct ab2; [ | | easy ].
*apply Nat.compare_eq_iff in Hab2; subst b2.
apply Nat.compare_lt_iff in Hab.
destruct bc1; [ | | easy ].
--apply Nat.compare_eq_iff in Hbc1; subst c1.
rewrite <- Hac1, Nat.compare_refl.
destruct bc2; [ | | easy ].
++apply Nat.compare_eq_iff in Hbc2; subst c2.
apply Nat.compare_lt_iff in Hbc.
rewrite <- Hac2, Nat.compare_refl.
apply Nat.compare_lt_iff.
now transitivity b3.
++apply Nat.compare_lt_iff in Hbc2.
destruct ac2; [ | easy | ].
**apply Nat.compare_eq_iff in Hac2; subst c2.
flia Hbc2.
**apply Nat.compare_gt_iff in Hac2.
flia Hbc2 Hac2.
--apply Nat.compare_lt_iff in Hbc1.
destruct ac1; [ | easy | ].
**apply Nat.compare_eq_iff in Hac1; flia Hbc1 Hac1.
**apply Nat.compare_gt_iff in Hac1; flia Hbc1 Hac1.
*destruct bc1; [ | | easy ].
--apply Nat.compare_eq_iff in Hbc1; subst c1.
destruct bc2; [ | | easy ].
++apply Nat.compare_eq_iff in Hbc2; subst c2.
rewrite <- Hac2, Hab2.
destruct ac1; [ easy | easy | ].
now rewrite Nat.compare_refl in Hac1.
++apply Nat.compare_lt_iff in Hab2.
apply Nat.compare_lt_iff in Hbc2.
destruct ac1; [ | easy | ].
**destruct ac2; [ | easy | ].
---apply Nat.compare_eq_iff in Hac2; subst c2.
flia Hab2 Hbc2.
---apply Nat.compare_gt_iff in Hac2.
flia Hab2 Hbc2 Hac2.
**now rewrite Nat.compare_refl in Hac1.
--now rewrite <- Hac1, Hbc1.
+destruct ac1; [ | easy | ].
*apply Nat.compare_eq_iff in Hac1; subst c1.
destruct ac2; [ | easy | ].
--apply Nat.compare_eq_iff in Hac2; subst c2.
destruct bc1; [ | | easy ].
++apply Nat.compare_eq_iff in Hbc1; subst b1.
now rewrite Nat.compare_refl in Hab1.
++apply Nat.compare_lt_iff in Hab1.
apply Nat.compare_lt_iff in Hbc1.
flia Hab1 Hbc1.
--destruct bc1; [ | | easy ].
++apply Nat.compare_eq_iff in Hbc1; subst b1.
now rewrite Nat.compare_refl in Hab1.
++apply Nat.compare_lt_iff in Hab1.
apply Nat.compare_lt_iff in Hbc1.
flia Hab1 Hbc1.
*destruct bc1; [ | | easy ].
--apply Nat.compare_eq_iff in Hbc1; subst c1.
now rewrite Hac1 in Hab1.
--apply Nat.compare_lt_iff in Hab1.
apply Nat.compare_lt_iff in Hbc1.
apply Nat.compare_gt_iff in Hac1.
flia Hab1 Hbc1 Hac1.
Qed.
Theorem mul_assoc_indices_eq : ∀ n,
flat_map (λ d, map (λ d', (d, d', n / d / d')) (divisors (n / d))) (divisors n) =
map xyz_zxy (flat_map (λ d, map (λ d', (d', d / d', n / d)) (divisors d)) (rev (divisors n))).
Proof.
intros.
destruct (zerop n) as [Hn| Hn]; [ now rewrite Hn | ].
apply Nat.neq_0_lt_0 in Hn.
do 2 rewrite flat_map_concat_map.
rewrite map_rev.
rewrite (map_inv_divisors n) at 2.
rewrite <- map_rev.
rewrite rev_involutive.
rewrite map_map.
rewrite concat_map.
rewrite map_map.
f_equal.
specialize (in_divisors n Hn) as Hin.
remember (divisors n) as l eqn:Hl; clear Hl.
induction l as [| a l]; [ easy | ].
cbn - [ divisors ].
rewrite IHl. 2: {
intros * Hd.
now apply Hin; right.
}
f_equal.
rewrite Nat_mod_0_div_div; cycle 1. {
specialize (Hin a (or_introl eq_refl)) as (H1, H2).
split; [ flia H2 | ].
apply Nat.mod_divides in H1; [ | easy ].
destruct H1 as (c, Hc); rewrite Hc.
destruct c; [ now rewrite Hc, Nat.mul_comm in Hn | ].
rewrite Nat.mul_comm; cbn; flia.
} {
apply (Hin a (or_introl eq_refl)).
}
now rewrite map_map.
Qed.
Theorem Permutation_f_sum_add {F : field} {A} : ∀ (l1 l2 : list A) f a,
Permutation l1 l2
→ fold_left f_add (map f l1) a =
fold_left f_add (map f l2) a.
Proof.
intros * Hperm.
induction Hperm using Permutation_ind; [ easy | | | ]. {
cbn; do 2 rewrite fold_f_add_assoc.
now rewrite IHHperm.
} {
now cbn; rewrite f_add_add_swap.
}
etransitivity; [ apply IHHperm1 | apply IHHperm2 ].
Qed.
Theorem fold_add_flat_prod_assoc {F : field} : ∀ n u v w,
n ≠ 0
→ fold_left f_add
(flat_map (λ d, map (f_mul (u d)) (log_prod_list v w (n / d)))
(divisors n))
0%F =
fold_left f_add
(flat_map (λ d, map (f_mul (w (n / d))) (log_prod_list u v d))
(divisors n))
0%F.
Proof.
intros * Hn.
do 2 rewrite flat_map_concat_map.
unfold log_prod_list.
do 2 rewrite List_map_map_map.
unfold log_prod_term.
assert (H : ∀ f l,
map (λ d, map (λ d', (u d * (v d' * w (n / d / d')))%F) (f d)) l =
map (λ d, map (λ d', (u d * v d' * w (n / d / d'))%F) (f d)) l). {
intros.
induction l as [| a l]; [ easy | cbn ].
rewrite IHl; f_equal; clear.
induction (f a) as [| b l]; [ easy | cbn ].
rewrite IHl; f_equal.
apply f_mul_assoc.
}
rewrite H; clear H.
assert (H : ∀ f l,
map (λ d, map (λ d', (w (n / d) * (u d' * v (d / d')))%F) (f d)) l =
map (λ d, map (λ d', (u d' * v (d / d') * w (n / d))%F) (f d)) l). {
intros.
induction l as [| a l]; [ easy | cbn ].
rewrite IHl; f_equal; clear.
induction (f a) as [| b l]; [ easy | cbn ].
rewrite IHl; f_equal.
apply f_mul_comm.
}
rewrite H; clear H.
do 2 rewrite <- flat_map_concat_map.
do 2 rewrite map_mul_triplet.
remember (
flat_map (λ d, map (λ d', (d, d', n / d / d')) (divisors (n / d)))
(divisors n))
as l1 eqn:Hl1.
remember (
flat_map (λ d, map (λ d', (d', d / d', n / d)) (divisors d))
(divisors n))
as l2 eqn:Hl2.
move l2 before l1.
assert (H1 : ∀ d1 d2 d3, d1 * d2 * d3 = n ↔ (d1, d2, d3) ∈ l1). {
split; intros Huvw.
-intros.
assert (Hd1 : d1 ≠ 0) by now intros H; rewrite <- Huvw, H in Hn.
assert (Hd2 : d2 ≠ 0). {
now intros H; rewrite <- Huvw, H, Nat.mul_0_r in Hn.
}
assert (Hd3 : d3 ≠ 0). {
now intros H; rewrite <- Huvw, H, Nat.mul_comm in Hn.
}
subst l1.