Library PrimeGapS1.CertRayleigh
From Stdlib Require Import ZArith List Lia.
Import ListNotations.
From mathcomp Require Import all_ssreflect all_algebra.
Import GRing.Theory Num.Theory.
From PrimeGapS1 Require Import IntMat CharPoly Witness Witness_Rayleigh.
From PrimeGapS1 Require Import MaynardSpec MaynardSpecBridge Cert.
From mathcomp.algebra_tactics Require Import ring.
Set Implicit Arguments.
Unset Strict Implicit.
Unset Printing Implicit Defensive.
Local Open Scope Z_scope.
Definition v_den : Z :=
List.fold_left (fun acc p ⇒ Z.lcm acc (snd p)) v_witness 1.
Definition v_num : list Z :=
List.map (fun p ⇒ fst p × (v_den / snd p)) v_witness.
Fixpoint row_dot (row v : list Z) : Z :=
match row, v with
| nil, _ ⇒ 0
| _, nil ⇒ 0
| r :: rs, x :: xs ⇒ r × x + row_dot rs xs
end.
Definition mat_vec_mul (M : list (list Z)) (v : list Z) : list Z :=
List.map (fun row ⇒ row_dot row v) M.
Definition quad (M : list (list Z)) (v : list Z) : Z :=
row_dot v (mat_vec_mul M v).
Definition num_M1 : Z := quad M1_int v_num.
Definition num_M2 : Z := quad M2_int v_num.
Lemma v_den_pos : 0 < v_den.
Proof. vm_compute. reflexivity. Qed.
Lemma rayleigh_witness_M1_positive : 0 < num_M1.
Proof. vm_compute. reflexivity. Qed.
Lemma rayleigh_witness_holds :
4 × D_M2 × num_M1 < 105 × D_M1 × num_M2.
Proof. vm_compute. reflexivity. Qed.
Local Open Scope ring_scope.
Definition v_rat (i : nat) : rat :=
Z2rat (List.nth i v_num BinInt.Z0) / Z2rat v_den.
Definition quad_spec (M_spec : nat → nat → rat) : rat :=
\sum_(i < 42) \sum_(j < 42)
v_rat i × M_spec i j × v_rat j.
Notation quad_M1_spec := (quad_spec M1_spec_ij) (only parsing).
Notation quad_M2_spec := (quad_spec M2_spec_ij) (only parsing).
Lemma Z2rat_mul (a b : Z) : Z2rat (a × b) = Z2rat a × Z2rat b.
Proof. by rewrite /Z2rat Z_to_int_mul intrM. Qed.
Lemma Z2rat_add (a b : Z) : Z2rat (a + b) = Z2rat a + Z2rat b.
Proof. by rewrite /Z2rat Z_to_int_add intrD. Qed.
Lemma Z2rat_0 : Z2rat 0 = 0.
Proof. by rewrite /Z2rat Z_to_int_0. Qed.
Lemma Z2rat_row_dot_eq_sum (row v : list Z) (n : nat) :
length v = n → length row = n →
Z2rat (row_dot row v) =
\sum_(i < n) Z2rat (List.nth i row BinInt.Z0)
× Z2rat (List.nth i v BinInt.Z0).
Proof.
elim: n row v ⇒ [|n IH] row v Hv Hr.
- destruct row; destruct v; try discriminate.
by rewrite /= Z2rat_0 big_ord0.
- destruct row as [|r row']; [discriminate|].
destruct v as [|x v']; [discriminate|].
simpl in Hv, Hr.
rewrite big_ord_recl /=.
rewrite Z2rat_add Z2rat_mul.
congr (_ + _).
rewrite (IH row' v');
[by apply: eq_bigr ⇒ i _ | by inversion Hv | by inversion Hr].
Qed.
Section QuadBridge.
Variable M : list (list Z).
Hypothesis HM_rows : length M = 42%nat.
Hypothesis HM_cols : ∀ i, (i < 42)%nat →
length (List.nth i M nil) = 42%nat.
Hypothesis Hv_len : length v_num = 42%nat.
Lemma Z2rat_quad_eq_sum :
Z2rat (quad M v_num) =
\sum_(i < 42) \sum_(j < 42)
Z2rat (List.nth i v_num BinInt.Z0) ×
Z2rat (mat_get M (nat_of_ord i) (nat_of_ord j)) ×
Z2rat (List.nth j v_num BinInt.Z0).
Proof.
rewrite /quad.
pose Mvec := mat_vec_mul M v_num.
have HMvec_len : length Mvec = 42%nat.
{ by rewrite /Mvec /mat_vec_mul List.length_map. }
rewrite (Z2rat_row_dot_eq_sum (n := 42) HMvec_len Hv_len).
apply: eq_bigr ⇒ i _.
rewrite /Mvec /mat_vec_mul.
have Hr_len : length (List.nth (nat_of_ord i) M nil) = 42%nat.
{ apply: HM_cols. exact: (ltn_ord i). }
have Hnth_map :
List.nth i (List.map (fun row ⇒ row_dot row v_num) M) BinInt.Z0
= row_dot (List.nth i M nil) v_num.
{ rewrite (List.nth_indep _ BinInt.Z0 (row_dot nil v_num)); last by
rewrite List.length_map HM_rows; apply/ltP; exact: (ltn_ord i).
by rewrite (List.map_nth (fun row ⇒ row_dot row v_num) M nil i). }
rewrite Hnth_map.
rewrite (Z2rat_row_dot_eq_sum (n := 42) Hv_len Hr_len).
rewrite GRing.mulr_sumr.
apply: eq_bigr ⇒ j _.
rewrite /mat_get /nth_Z.
by rewrite GRing.mulrA.
Qed.
End QuadBridge.
Lemma M1_int_rows : length M1_int = 42%nat.
Proof. by vm_compute. Qed.
Lemma M2_int_rows : length M2_int = 42%nat.
Proof. by vm_compute. Qed.
Lemma M1_int_cols : ∀ i, (i < 42)%nat →
length (List.nth i M1_int nil) = 42%nat.
Proof.
move⇒ i Hi.
have Hall : forallb (fun row ⇒ Nat.eqb (length row) 42) M1_int = true
by vm_compute.
have Hin : List.In (List.nth i M1_int nil) M1_int.
{ apply: List.nth_In; rewrite M1_int_rows; apply/ltP; exact: Hi. }
move: Hall; rewrite List.forallb_forall ⇒ /(_ _ Hin) /Nat.eqb_eq //.
Qed.
Lemma M2_int_cols : ∀ i, (i < 42)%nat →
length (List.nth i M2_int nil) = 42%nat.
Proof.
move⇒ i Hi.
have Hall : forallb (fun row ⇒ Nat.eqb (length row) 42) M2_int = true
by vm_compute.
have Hin : List.In (List.nth i M2_int nil) M2_int.
{ apply: List.nth_In; rewrite M2_int_rows; apply/ltP; exact: Hi. }
move: Hall; rewrite List.forallb_forall ⇒ /(_ _ Hin) /Nat.eqb_eq //.
Qed.
Lemma v_num_length : length v_num = 42%nat.
Proof. by vm_compute. Qed.
Lemma v_den_neq0_rat : Z2rat v_den != 0.
Proof. by apply: Z_to_int_pos_rat_neq0; exact: v_den_pos. Qed.
Lemma quad_cell_identity (dm vd vi mij vj : rat) :
vd != 0 → dm != 0 →
dm × vd^+2 × (vi / vd × (mij / dm) × (vj / vd)) = vi × mij × vj.
Proof. by move⇒ Hvd Hdm; rewrite expr2; field; apply/andP. Qed.
Lemma quad_spec_eq_Z (M_spec : nat → nat → rat) (M_int : list (list Z))
(D_M : Z)
(HM_rows : length M_int = 42%nat)
(HM_cols : ∀ i, (i < 42)%nat →
length (List.nth i M_int nil) = 42%nat)
(HD_M_pos : Z.lt 0 D_M)
(Hbridge : ∀ i j, (i < 42)%nat → (j < 42)%nat →
M_spec i j = Z2rat (mat_get M_int i j) /
Z2rat D_M) :
Z2rat D_M × Z2rat v_den ^+ 2 × quad_spec M_spec =
Z2rat (quad M_int v_num).
Proof.
rewrite (Z2rat_quad_eq_sum HM_rows HM_cols v_num_length).
rewrite /quad_spec.
rewrite [LHS]mulr_sumr.
apply: eq_bigr ⇒ i _.
rewrite [LHS]mulr_sumr.
apply: eq_bigr ⇒ j _.
rewrite (Hbridge i j (ltn_ord i) (ltn_ord j)) /v_rat.
apply: quad_cell_identity.
- exact: v_den_neq0_rat.
- by apply: Z_to_int_pos_rat_neq0; exact: HD_M_pos.
Qed.
Lemma quad_M1_spec_eq_Z :
Z2rat D_M1 × Z2rat v_den ^+ 2 × quad_spec M1_spec_ij =
Z2rat num_M1.
Proof.
apply: quad_spec_eq_Z;
[exact: M1_int_rows | exact: M1_int_cols
| exact: D_M1_pos | exact: @M1_spec_eq_int].
Qed.
Lemma quad_M2_spec_eq_Z :
Z2rat D_M2 × Z2rat v_den ^+ 2 × quad_spec M2_spec_ij =
Z2rat num_M2.
Proof.
apply: quad_spec_eq_Z;
[exact: M2_int_rows | exact: M2_int_cols
| exact: D_M2_pos | exact: @M2_spec_eq_int].
Qed.
Lemma Z2rat_pos (a : Z) : BinInt.Z.lt 0 a → (0 : rat) < Z2rat a.
Proof.
case: a ⇒ [//|p _|p Hp]; last by lia.
by rewrite /Z2rat Z_to_int_pos_pos ltr0z; apply/ltP; exact: Pos2Nat.is_pos.
Qed.
Lemma Z2rat_lt (a b : Z) : BinInt.Z.lt a b → Z2rat a < Z2rat b.
Proof.
move⇒ Hab; rewrite -subr_gt0.
have → : Z2rat b - Z2rat a = Z2rat (BinInt.Z.sub b a).
rewrite /Z2rat -intrB -Z_to_int_opp -Z_to_int_add.
by congr ((Z_to_int _)%:~R); lia.
by apply: Z2rat_pos; lia.
Qed.
Lemma rayleigh_witness_holds_rat :
Z2rat (4 × D_M2 × num_M1) < Z2rat (105 × D_M1 × num_M2).
Proof. by apply: Z2rat_lt; exact: rayleigh_witness_holds. Qed.
Section RayleighLift.
Variables (d1Z d2Z a1Z a2Z : Z) (v q1 q2 : rat).
Hypothesis Hd1 : BinInt.Z.lt 0 d1Z.
Hypothesis Hd2 : BinInt.Z.lt 0 d2Z.
Hypothesis Hv : (0 : rat) < v.
Hypothesis Ha1 : Z2rat d1Z × v ^+ 2 × q1 = Z2rat a1Z.
Hypothesis Ha2 : Z2rat d2Z × v ^+ 2 × q2 = Z2rat a2Z.
Hypothesis Hcmp : Z2rat (4 × d2Z × a1Z) < Z2rat (105 × d1Z × a2Z).
Lemma rayleigh_lift_generic : 4%:Q × q1 < 105%:Q × q2.
Proof.
have Hd1r : (0 : rat) < Z2rat d1Z by exact: Z2rat_pos.
have Hd2r : (0 : rat) < Z2rat d2Z by exact: Z2rat_pos.
have HK : (0 : rat) < Z2rat d1Z × Z2rat d2Z × v ^+ 2.
by rewrite expr2; do !apply: mulr_gt0.
rewrite -(ltr_pM2r HK).
have H4 : Z2rat 4 = 4%:Q by rewrite /Z2rat /=.
have H105 : Z2rat 105 = 105%:Q by rewrite /Z2rat /=.
have HLHS : 4%:Q × q1 × (Z2rat d1Z × Z2rat d2Z × v ^+ 2)
= Z2rat (4 × d2Z × a1Z).
by rewrite !Z2rat_mul -Ha1 H4; ring.
have HRHS : 105%:Q × q2 × (Z2rat d1Z × Z2rat d2Z × v ^+ 2)
= Z2rat (105 × d1Z × a2Z).
by rewrite !Z2rat_mul -Ha2 H105; ring.
by rewrite HLHS HRHS; exact: Hcmp.
Qed.
End RayleighLift.
Lemma rayleigh_lt_main : 4%:Q × quad_spec M1_spec_ij <
105%:Q × quad_spec M2_spec_ij.
Proof.
exact: (rayleigh_lift_generic D_M1_pos D_M2_pos
(Z2rat_pos v_den_pos)
quad_M1_spec_eq_Z quad_M2_spec_eq_Z
rayleigh_witness_holds_rat).
Qed.
Theorem maynard_M105_certified_rayleigh :
(∀ i j, (i < 42)%nat → (j < 42)%nat →
M1_spec_ij i j = Z2rat (mat_get M1_int i j) / Z2rat D_M1) ∧
(∀ i j, (i < 42)%nat → (j < 42)%nat →
M2_spec_ij i j = Z2rat (mat_get M2_int i j) / Z2rat D_M2) ∧
4%:Q × quad_spec M1_spec_ij < 105%:Q × quad_spec M2_spec_ij.
Proof.
split; first by move⇒ i j Hi Hj; apply: M1_spec_eq_int.
split; first by move⇒ i j Hi Hj; apply: M2_spec_eq_int.
exact: rayleigh_lt_main.
Qed.