Library PrimeGapS1.MaynardSpec


From Stdlib Require Import ZArith List.
From mathcomp Require Import all_ssreflect all_algebra.
From PrimeGapS1 Require Import MaynardFactQ MaynardBasis.

Import ListNotations.

Set Implicit Arguments.
Unset Strict Implicit.
Unset Printing Implicit Defensive.

Import GRing.Theory.


Local Open Scope ring_scope.

Fixpoint compositions_aux (r remaining : nat) : seq (seq nat) :=
  match r with
  | 0 ⇒ if (remaining == 0)%N then [:: [::] ] else [::]
  | S r' ⇒
      flatten
        [seq [seq (a :: tl) | tl <- compositions_aux r' (remaining - a)%N]
           | a <- iota 1 remaining]
  end.

Definition compositions (r n : nat) : seq (seq nat) := compositions_aux r n.

Definition cff (a : seq nat) : rat :=
  \prod_(x <- a) (factQ (2 × x) / factQ x).

Definition G_2 (n k : nat) : rat :=
  if (n == 0)%N then 1
  else
    factQ n
    × \sum_(r <- iota 1 n) binQ k r × \sum_(a <- compositions r n) cff a.

Definition K1 : nat := 105.
Definition K2 : nat := 104.

Definition M1_entry (bi ci bj cj : nat) : rat :=
  let b := (bi + bj)%N in
  let c := (ci + cj)%N in
  factQ b / factQ (K1 + b + 2 × c)%N × G_2 c K1.

Definition alpha (b c cp : nat) : rat :=
  binQ c cp × factQ b × factQ (2 × c - 2 × cp)%N
    / factQ (b + 2 × c - 2 × cp + 1)%N.

Definition M2_entry (bi ci bj cj : nat) : rat :=
  \sum_(cp1 <- iota 0 ci.+1)
    \sum_(cp2 <- iota 0 cj.+1)
      let bp1 := (bi + 2 × ci - 2 × cp1 + 1)%N in
      let bp2 := (bj + 2 × cj - 2 × cp2 + 1)%N in
      let bsum := (bp1 + bp2)%N in
      let csum := (cp1 + cp2)%N in
      alpha bi ci cp1 × alpha bj cj cp2
        × factQ bsum / factQ (K2 + bsum + 2 × csum)%N
        × G_2 csum K2.

Definition M1_spec_ij (i j : nat) : rat :=
  let bci := List.nth i maynard_basis (0%N, 0%N) in
  let bcj := List.nth j maynard_basis (0%N, 0%N) in
  M1_entry bci.1 bci.2 bcj.1 bcj.2.

Definition M2_spec_ij (i j : nat) : rat :=
  let bci := List.nth i maynard_basis (0%N, 0%N) in
  let bcj := List.nth j maynard_basis (0%N, 0%N) in
  M2_entry bci.1 bci.2 bcj.1 bcj.2.


Local Close Scope ring_scope.
Local Open Scope Z_scope.

Fixpoint factZ (n : nat) : Z :=
  match n with
  | O ⇒ 1
  | S k ⇒ Z.of_nat (S k) × factZ k
  end.

Definition dblratZ (x : nat) : Z := factZ (2 × x)%nat / factZ x.

Fixpoint prod_dblratZ (xs : list nat) : Z :=
  match xs with
  | nil ⇒ 1
  | x :: r ⇒ dblratZ x × prod_dblratZ r
  end.

Fixpoint compositions_auxZ (r remaining : nat) : list (list nat) :=
  match r with
  | O ⇒ if Nat.eqb remaining 0 then [nil] else nil
  | S r' ⇒
      List.flat_map
        (fun a ⇒
           List.map (fun tl ⇒ a :: tl)
                    (compositions_auxZ r' (remaining - a)%nat))
        (List.seq 1 remaining)
  end.

Definition compositionsZ (r n : nat) : list (list nat) :=
  compositions_auxZ r n.

Definition cffZ (a : list nat) : Z := prod_dblratZ a.

Definition binZ (n k : nat) : Z :=
  if Nat.leb k n then factZ n / (factZ k × factZ (n - k)%nat) else 0.

Definition G2Z (n k : nat) : Z :=
  if Nat.eqb n O then 1
  else
    factZ n
    × List.fold_left Z.add
        (List.map
           (fun r ⇒
              binZ k r
              × List.fold_left Z.add
                  (List.map cffZ (compositionsZ r n)) 0)
           (List.seq 1 n)) 0.


Definition K1n : nat := 105.
Definition K2n : nat := 104.

Definition m1_num_den (bi ci bj cj : nat) : Z × Z :=
  let b := (bi + bj)%nat in
  let c := (ci + cj)%nat in
  (factZ b × G2Z c K1n, factZ (K1n + b + 2 × c)%nat).


Definition qplus (p q : Z × Z) : Z × Z :=
  let '(a, b) := p in
  let '(c, d) := q in
  (a × d + c × b, b × d).

Definition qmul (p q : Z × Z) : Z × Z :=
  let '(a, b) := p in
  let '(c, d) := q in
  (a × c, b × d).

Definition alphaZ (b c cp : nat) : Z × Z :=
  (binZ c cp × factZ b × factZ (2 × c - 2 × cp)%nat,
   factZ (b + 2 × c - 2 × cp + 1)%nat).

Definition m2_term_num_den (bi ci bj cj cp1 cp2 : nat) : Z × Z :=
  let bp1 := (bi + 2 × ci - 2 × cp1 + 1)%nat in
  let bp2 := (bj + 2 × cj - 2 × cp2 + 1)%nat in
  let bsum := (bp1 + bp2)%nat in
  let csum := (cp1 + cp2)%nat in
  qmul (qmul (alphaZ bi ci cp1) (alphaZ bj cj cp2))
       (factZ bsum × G2Z csum K2n, factZ (K2n + bsum + 2 × csum)%nat).

Definition m2_num_den (bi ci bj cj : nat) : Z × Z :=
  List.fold_left
    (fun acc cp1 ⇒
       List.fold_left
         (fun acc2 cp2 ⇒ qplus acc2 (m2_term_num_den bi ci bj cj cp1 cp2))
         (List.seq 0 (S cj)) acc)
    (List.seq 0 (S ci)) (0, 1).


Definition m1_num_den_at (i j : nat) : Z × Z :=
  let bci := List.nth i maynard_basis (0%nat, 0%nat) in
  let bcj := List.nth j maynard_basis (0%nat, 0%nat) in
  m1_num_den bci.1 bci.2 bcj.1 bcj.2.

Definition m2_num_den_at (i j : nat) : Z × Z :=
  let bci := List.nth i maynard_basis (0%nat, 0%nat) in
  let bcj := List.nth j maynard_basis (0%nat, 0%nat) in
  m2_num_den bci.1 bci.2 bcj.1 bcj.2.