import Mathlib set_option linter.unusedVariables false set_option linter.unusedSimpArgs false set_option linter.unnecessarySeqFocus false def largestPrimeFactor (n : ℕ) : ℕ := WithBot.unbotD 0 n.primeFactors.max def truncatedObtuseRegion (n : ℕ) (η : ℝ) : Set (ℤ × ℤ) := {pq : ℤ × ℤ | η * (n : ℝ) ≤ (pq.1 : ℝ) ∧ η * (n : ℝ) ≤ (pq.2 : ℝ) ∧ (pq.1 : ℝ) + (pq.2 : ℝ) < (n : ℝ) / 2 ∧ Int.gcd (Int.gcd pq.1 pq.2) (n : ℤ) = 1} def intervalSet (n : ℕ) (m : ℕ) : Set (ZMod n) := {x : ZMod n | 1 ≤ ZMod.val x ∧ ZMod.val x ≤ m} instance intervalSet_decidableMem (n : ℕ) (m : ℕ) : DecidablePred (· ∈ intervalSet n m) := fun _ => instDecidableAnd def countingFunctionS (n : ℕ) (p q : ℤ) : ℕ := if h : n = 0 then 0 else haveI : NeZero n := ⟨h⟩ let mp := (2 * p - 1).toNat let mq := (2 * q - 1).toNat (Finset.univ.filter fun a : (ZMod n)ˣ => (a.val * (p : ZMod n)) ∈ intervalSet n mp ∧ (a.val * (q : ZMod n)) ∈ intervalSet n mq).card def badPairsSet (n : ℕ) (η : ℝ) : Set (ℤ × ℤ) := {pq ∈ truncatedObtuseRegion n η | Int.gcd pq.2 (largestPrimeFactor n : ℤ) = 1 ∧ countingFunctionS n pq.1 pq.2 < 5} lemma truncatedObtuseRegion_subset_box (n : ℕ) (η : ℝ) : truncatedObtuseRegion n η ⊆ (Set.Icc (⌈η * (n : ℝ)⌉ - 1 : ℤ) (⌊(n : ℝ) / 2 - η * (n : ℝ)⌋ : ℤ)) ×ˢ (Set.Icc (⌈η * (n : ℝ)⌉ - 1 : ℤ) (⌊(n : ℝ) / 2 - η * (n : ℝ)⌋ : ℤ)) := by intro ⟨p, q⟩ h simp only [truncatedObtuseRegion, Set.mem_setOf_eq, Set.mem_prod, Set.mem_Icc] at h ⊢ have h₁ : (η * (n : ℝ) : ℝ) ≤ (p : ℝ) := h.1 have h₂ : (η * (n : ℝ) : ℝ) ≤ (q : ℝ) := h.2.1 have h₃ : (p : ℝ) + (q : ℝ) < (n : ℝ) / 2 := h.2.2.1 have h₄ : Int.gcd (Int.gcd p q) (n : ℤ) = 1 := h.2.2.2 constructor · have h₅ : (⌈η * (n : ℝ)⌉ : ℝ) - 1 ≤ (p : ℝ) := by have h₅₂ : (⌈η * (n : ℝ)⌉ : ℝ) - 1 ≤ (η * (n : ℝ)) := by linarith [Int.ceil_lt_add_one (η * (n : ℝ))] linarith have h₆ : (p : ℝ) ≤ (⌊(n : ℝ) / 2 - η * (n : ℝ)⌋ : ℝ) := by have h₆₁ : (p : ℝ) + (q : ℝ) < (n : ℝ) / 2 := h₃ have h₆₂ : (η * (n : ℝ)) ≤ (q : ℝ) := h₂ have h₆₃ : (p : ℝ) < (n : ℝ) / 2 - η * (n : ℝ) := by linarith have h₆₄ : (p : ℝ) ≤ ⌊(n : ℝ) / 2 - η * (n : ℝ)⌋ := by have h₆₅ : (⌊(n : ℝ) / 2 - η * (n : ℝ)⌋ : ℝ) ≤ (n : ℝ) / 2 - η * (n : ℝ) := by exact Int.floor_le ((n : ℝ) / 2 - η * (n : ℝ)) have h₆₆ : (p : ℝ) < (n : ℝ) / 2 - η * (n : ℝ) := h₆₃ have h₆₇ : (p : ℝ) ≤ ⌊(n : ℝ) / 2 - η * (n : ℝ)⌋ := by have h₆₈ : (p : ℤ) ≤ ⌊(n : ℝ) / 2 - η * (n : ℝ)⌋ := by apply Int.le_floor.mpr norm_num at h₆₃ ⊢ <;> (try norm_cast at h₆₃ ⊢) <;> (try simp_all [Int.floor_lt]) <;> (try linarith) exact by exact_mod_cast h₆₈ exact h₆₇ exact_mod_cast h₆₄ have h₇ : (⌈η * (n : ℝ)⌉ - 1 : ℤ) ≤ p := by have h₇₂ : (⌈η * (n : ℝ)⌉ : ℤ) - 1 ≤ p := by have h₇₅ : (⌈η * (n : ℝ)⌉ : ℤ) - 1 ≤ p := by by_contra h₇₆ have h₇₇ : p < (⌈η * (n : ℝ)⌉ : ℤ) - 1 := by linarith have h₇₈ : (p : ℝ) < (⌈η * (n : ℝ)⌉ : ℝ) - 1 := by exact_mod_cast h₇₇ linarith [Int.le_ceil (η * (n : ℝ))] exact h₇₅ exact_mod_cast h₇₂ have h₈ : p ≤ (⌊(n : ℝ) / 2 - η * (n : ℝ)⌋ : ℤ) := by have h₈₁ : (p : ℝ) ≤ (⌊(n : ℝ) / 2 - η * (n : ℝ)⌋ : ℝ) := h₆ have h₈₂ : (p : ℤ) ≤ (⌊(n : ℝ) / 2 - η * (n : ℝ)⌋ : ℤ) := by exact_mod_cast h₈₁ exact h₈₂ exact ⟨h₇, h₈⟩ · have h₅ : (⌈η * (n : ℝ)⌉ : ℝ) - 1 ≤ (q : ℝ) := by have h₅₂ : (⌈η * (n : ℝ)⌉ : ℝ) - 1 ≤ (η * (n : ℝ)) := by linarith [Int.ceil_lt_add_one (η * (n : ℝ))] linarith have h₆ : (q : ℝ) ≤ (⌊(n : ℝ) / 2 - η * (n : ℝ)⌋ : ℝ) := by have h₆₁ : (p : ℝ) + (q : ℝ) < (n : ℝ) / 2 := h₃ have h₆₂ : (η * (n : ℝ)) ≤ (p : ℝ) := h₁ have h₆₃ : (q : ℝ) < (n : ℝ) / 2 - η * (n : ℝ) := by linarith have h₆₄ : (q : ℝ) ≤ ⌊(n : ℝ) / 2 - η * (n : ℝ)⌋ := by have h₆₅ : (⌊(n : ℝ) / 2 - η * (n : ℝ)⌋ : ℝ) ≤ (n : ℝ) / 2 - η * (n : ℝ) := by exact Int.floor_le ((n : ℝ) / 2 - η * (n : ℝ)) have h₆₆ : (q : ℝ) < (n : ℝ) / 2 - η * (n : ℝ) := h₆₃ have h₆₇ : (q : ℝ) ≤ ⌊(n : ℝ) / 2 - η * (n : ℝ)⌋ := by have h₆₈ : (q : ℤ) ≤ ⌊(n : ℝ) / 2 - η * (n : ℝ)⌋ := by apply Int.le_floor.mpr norm_num at h₆₃ ⊢ <;> (try norm_cast at h₆₃ ⊢) <;> (try simp_all [Int.floor_lt]) <;> (try linarith) exact by exact_mod_cast h₆₈ exact h₆₇ exact_mod_cast h₆₄ have h₇ : (⌈η * (n : ℝ)⌉ - 1 : ℤ) ≤ q := by have h₇₂ : (⌈η * (n : ℝ)⌉ : ℤ) - 1 ≤ q := by have h₇₅ : (⌈η * (n : ℝ)⌉ : ℤ) - 1 ≤ q := by by_contra h₇₆ have h₇₇ : q < (⌈η * (n : ℝ)⌉ : ℤ) - 1 := by linarith have h₇₈ : (q : ℝ) < (⌈η * (n : ℝ)⌉ : ℝ) - 1 := by exact_mod_cast h₇₇ linarith [Int.le_ceil (η * (n : ℝ))] exact h₇₅ exact_mod_cast h₇₂ have h₈ : q ≤ (⌊(n : ℝ) / 2 - η * (n : ℝ)⌋ : ℤ) := by have h₈₁ : (q : ℝ) ≤ (⌊(n : ℝ) / 2 - η * (n : ℝ)⌋ : ℝ) := h₆ have h₈₂ : (q : ℤ) ≤ (⌊(n : ℝ) / 2 - η * (n : ℝ)⌋ : ℤ) := by exact_mod_cast h₈₁ exact h₈₂ exact ⟨h₇, h₈⟩ lemma truncatedObtuseRegion_finite (n : ℕ) (η : ℝ) : (truncatedObtuseRegion n η).Finite := ((Set.finite_Icc _ _).prod (Set.finite_Icc _ _)).subset (truncatedObtuseRegion_subset_box n η) lemma badPairsSet_finite (n : ℕ) (η : ℝ) : (badPairsSet n η).Finite := by exact (truncatedObtuseRegion_finite n η).subset (fun _ h => h.1) lemma coprime_triangle_subset_truncatedObtuseRegion (n : ℕ) (η : ℝ) : {pq : ℤ × ℤ | η * (n : ℝ) ≤ (pq.1 : ℝ) ∧ η * (n : ℝ) ≤ (pq.2 : ℝ) ∧ (pq.1 : ℝ) + (pq.2 : ℝ) < (n : ℝ) / 2 ∧ Int.gcd pq.1 pq.2 = 1} ⊆ truncatedObtuseRegion n η := by intro ⟨p, q⟩ h simp only [Set.mem_setOf_eq, truncatedObtuseRegion] at h ⊢ have h₁ : η * (n : ℝ) ≤ (p : ℝ) := h.1 have h₂ : η * (n : ℝ) ≤ (q : ℝ) := h.2.1 have h₃ : (p : ℝ) + (q : ℝ) < (n : ℝ) / 2 := h.2.2.1 have h₄ : Int.gcd p q = 1 := h.2.2.2 have h₅ : Int.gcd (Int.gcd p q) (n : ℤ) = 1 := by have h₅₁ : (Int.gcd p q : ℤ) = 1 := by exact_mod_cast h₄ have h₅₂ : Int.gcd (Int.gcd p q) (n : ℤ) = 1 := by rw [h₅₁] simp [Int.gcd_eq_right] exact h₅₂ exact ⟨h₁, h₂, h₃, h₅⟩ lemma coprime_triangle_finite (n : ℕ) (η : ℝ) : {pq : ℤ × ℤ | η * (n : ℝ) ≤ (pq.1 : ℝ) ∧ η * (n : ℝ) ≤ (pq.2 : ℝ) ∧ (pq.1 : ℝ) + (pq.2 : ℝ) < (n : ℝ) / 2 ∧ Int.gcd pq.1 pq.2 = 1}.Finite := by exact Set.Finite.subset (truncatedObtuseRegion_finite n η) (coprime_triangle_subset_truncatedObtuseRegion n η) lemma sum_lt_half_zero_case (p q : ℤ) (hp : p ≤ ⌊((0 : ℕ) : ℝ) / 6⌋) (hq : q ≤ ⌊((0 : ℕ) : ℝ) / 6⌋) (hgcd : Int.gcd p q = 1) : (p : ℝ) + (q : ℝ) < ((0 : ℕ) : ℝ) / 2 := by have h₁ : ⌊((0 : ℕ) : ℝ) / 6⌋ = 0 := by norm_num [Int.floor_eq_iff] have h₂ : p ≤ 0 := by have h₃ : (p : ℤ) ≤ ⌊((0 : ℕ) : ℝ) / 6⌋ := hp have h₄ : ⌊((0 : ℕ) : ℝ) / 6⌋ = 0 := h₁ have h₅ : (p : ℤ) ≤ 0 := by simpa [h₄] using h₃ exact_mod_cast h₅ have h₃ : q ≤ 0 := by have h₄ : (q : ℤ) ≤ ⌊((0 : ℕ) : ℝ) / 6⌋ := hq have h₅ : ⌊((0 : ℕ) : ℝ) / 6⌋ = 0 := h₁ have h₆ : (q : ℤ) ≤ 0 := by simpa [h₅] using h₄ exact_mod_cast h₆ have h₄ : (p : ℝ) + (q : ℝ) < ((0 : ℕ) : ℝ) / 2 := by have h₇ : Int.gcd p q = 1 := hgcd have h₈ : (p : ℝ) + (q : ℝ) < ((0 : ℕ) : ℝ) / 2 := by have h₉ : p < 0 ∨ q < 0 := by by_contra! h have h₁₀ : p = 0 := by linarith have h₁₁ : q = 0 := by linarith have h₁₂ : Int.gcd p q = 0 := by simp [h₁₀, h₁₁] rw [h₁₂] at h₇ norm_num at h₇ cases h₉ with | inl h₉ => have h₁₀ : (p : ℝ) < 0 := by exact_mod_cast h₉ have h₁₁ : (q : ℝ) ≤ 0 := by exact_mod_cast h₃ have h₁₂ : (p : ℝ) + (q : ℝ) < 0 := by linarith norm_num at h₁₂ ⊢ <;> linarith | inr h₉ => have h₁₀ : (q : ℝ) < 0 := by exact_mod_cast h₉ have h₁₁ : (p : ℝ) ≤ 0 := by exact_mod_cast h₂ have h₁₂ : (p : ℝ) + (q : ℝ) < 0 := by linarith norm_num at h₁₂ ⊢ <;> linarith exact h₈ exact h₄ lemma sum_lt_half_pos_case (n : ℕ) (p q : ℤ) (hn : 1 ≤ n) (hp : p ≤ ⌊(n : ℝ) / 6⌋) (hq : q ≤ ⌊(n : ℝ) / 6⌋) : (p : ℝ) + (q : ℝ) < (n : ℝ) / 2 := by have h_p_le : (p : ℝ) ≤ (n : ℝ) / 6 := by calc (p : ℝ) ≤ (⌊(n : ℝ) / 6⌋ : ℤ) := by exact_mod_cast hp _ ≤ (n : ℝ) / 6 := Int.floor_le _ have h_q_le : (q : ℝ) ≤ (n : ℝ) / 6 := by calc (q : ℝ) ≤ (⌊(n : ℝ) / 6⌋ : ℤ) := by exact_mod_cast hq _ ≤ (n : ℝ) / 6 := Int.floor_le _ have h_n_pos : (n : ℝ) > 0 := by exact_mod_cast hn have h_final : (p : ℝ) + (q : ℝ) < (n : ℝ) / 2 := by nlinarith assumption lemma sum_lt_half_of_le_floor_sixth (n : ℕ) (p q : ℤ) (hp : p ≤ ⌊(n : ℝ) / 6⌋) (hq : q ≤ ⌊(n : ℝ) / 6⌋) (hgcd : Int.gcd p q = 1) : (p : ℝ) + (q : ℝ) < (n : ℝ) / 2 := by rcases Nat.eq_zero_or_pos n with rfl | hn · exact sum_lt_half_zero_case p q hp hq hgcd · exact sum_lt_half_pos_case n p q hn hp hq lemma rectangle_coprime_subset_target (n : ℕ) (η : ℝ) : {pq : ℤ × ℤ | (⌈η * (n : ℝ)⌉ : ℤ) ≤ pq.1 ∧ pq.1 ≤ (⌊(n : ℝ) / 6⌋ : ℤ) ∧ (⌈η * (n : ℝ)⌉ : ℤ) ≤ pq.2 ∧ pq.2 ≤ (⌊(n : ℝ) / 6⌋ : ℤ) ∧ Int.gcd pq.1 pq.2 = 1} ⊆ {pq : ℤ × ℤ | η * (n : ℝ) ≤ (pq.1 : ℝ) ∧ η * (n : ℝ) ≤ (pq.2 : ℝ) ∧ (pq.1 : ℝ) + (pq.2 : ℝ) < (n : ℝ) / 2 ∧ Int.gcd pq.1 pq.2 = 1} := by intro ⟨p, q⟩ hpq simp only [Set.mem_setOf_eq] at hpq ⊢ obtain ⟨h1, h2, h3, h4, h5⟩ := hpq refine ⟨?_, ?_, ?_, h5⟩ · exact le_trans (Int.le_ceil _) (Int.cast_le.mpr h1) · exact le_trans (Int.le_ceil _) (Int.cast_le.mpr h3) · exact sum_lt_half_of_le_floor_sixth n p q h2 h4 h5 lemma Int_Icc_ncard (a b : ℤ) : (Set.Icc a b).ncard = (b + 1 - a).toNat := by have h₁ : (Set.Icc a b : Set ℤ) = ↑(Finset.Icc a b) := by simp have h₂ : (Set.Icc a b : Set ℤ).ncard = (Finset.Icc a b : Finset ℤ).card := by rw [h₁, Set.ncard_coe_finset] have h₃ : (Finset.Icc a b : Finset ℤ).card = (b + 1 - a).toNat := by simp have h₄ : (Set.Icc a b).ncard = (b + 1 - a).toNat := by simp_all assumption lemma eta_n_plus_one_le_n_div_six (η : ℝ) (hη_pos : 0 < η) (hη_lt : η < 1 / 6) : ∃ (N₀ : ℕ), ∀ n : ℕ, N₀ ≤ n → η * (n : ℝ) + 1 ≤ (n : ℝ) / 6 := by have h_delta_pos : 0 < (1 / 6 : ℝ) - η := by simp_all set N₀ := ⌈(1 : ℝ) / ((1 / 6 : ℝ) - η)⌉₊ with hN₀_def use N₀ intro n hn have h₂ : (n : ℝ) ≥ (1 : ℝ) / ((1 / 6 : ℝ) - η) := by simp_all have h₄ : ((1 / 6 : ℝ) - η) * (n : ℝ) ≥ 1 := by have := mul_le_mul_of_nonneg_left h₂ (le_of_lt h_delta_pos) rw [mul_div_cancel₀] at this · linarith · exact ne_of_gt h_delta_pos have h₅ : η * (n : ℝ) + 1 ≤ (n : ℝ) / 6 := by nlinarith exact h₅ lemma int_expr_real_lower_bound (η : ℝ) (n : ℕ) : (n : ℝ) / 6 - η * (n : ℝ) - 1 < ((⌊(n : ℝ) / 6⌋ + 1 - ⌈η * (n : ℝ)⌉ : ℤ) : ℝ) := by have h₁ : (n : ℝ) / 6 - 1 < (⌊(n : ℝ) / 6⌋ : ℝ) := by have h₁ : (n : ℝ) / 6 - 1 < (⌊(n : ℝ) / 6⌋ : ℝ) := by have h₂ : (n : ℝ) / 6 - 1 < (⌊(n : ℝ) / 6⌋ : ℝ) := by linarith [Int.sub_one_lt_floor ((n : ℝ) / 6)] exact h₂ exact h₁ have h₂ : (⌈(η * (n : ℝ))⌉ : ℝ) < (η * (n : ℝ)) + 1 := by have h₃ : (⌈(η * (n : ℝ))⌉ : ℝ) < (η * (n : ℝ)) + 1 := by have h₄ : (⌈(η * (n : ℝ))⌉ : ℝ) < (η * (n : ℝ)) + 1 := by linarith [Int.ceil_lt_add_one (η * (n : ℝ))] exact h₄ exact h₃ have h₃ : (n : ℝ) / 6 - η * (n : ℝ) - 1 < ((⌊(n : ℝ) / 6⌋ + 1 - ⌈η * (n : ℝ)⌉ : ℤ) : ℝ) := by have h₄ : (n : ℝ) / 6 - η * (n : ℝ) - 1 < ((⌊(n : ℝ) / 6⌋ + 1 - ⌈η * (n : ℝ)⌉ : ℤ) : ℝ) := by have h₆ : ((⌊(n : ℝ) / 6⌋ + 1 - ⌈η * (n : ℝ)⌉ : ℤ) : ℝ) = (⌊(n : ℝ) / 6⌋ : ℝ) + 1 - (⌈(η * (n : ℝ))⌉ : ℝ) := by norm_cast linarith exact h₄ exact h₃ lemma ceil_le_floor_for_large_n (η : ℝ) (hη_pos : 0 < η) (hη_lt : η < 1 / 6) : ∃ (N₀ : ℕ), ∀ n : ℕ, N₀ ≤ n → (⌈η * (n : ℝ)⌉ : ℤ) ≤ (⌊(n : ℝ) / 6⌋ : ℤ) := by obtain ⟨N₀, hN₀⟩ := eta_n_plus_one_le_n_div_six η hη_pos hη_lt exact ⟨N₀, fun n hn => Int.le_floor.mpr (le_of_lt (Int.ceil_lt_add_one _) |>.trans (hN₀ n hn))⟩ lemma int_expr_nonneg_for_large_n (η : ℝ) (hη_pos : 0 < η) (hη_lt : η < 1 / 6) : ∃ N₀ : ℕ, ∀ n : ℕ, N₀ ≤ n → (0 : ℤ) ≤ (⌊(n : ℝ) / 6⌋ + 1 - ⌈η * (n : ℝ)⌉ : ℤ) := by obtain ⟨N₀, hN₀⟩ := ceil_le_floor_for_large_n η hη_pos hη_lt exact ⟨N₀, fun n hn => by linarith [hN₀ n hn]⟩ lemma half_bound_for_large_n (η : ℝ) (hη_pos : 0 < η) (hη_lt : η < 1 / 6) : ∃ N₀ : ℕ, ∀ n : ℕ, N₀ ≤ n → ((1 / 6 - η) / 2) * (n : ℝ) ≤ (1 / 6 - η) * (n : ℝ) - 1 := by have h : 0 < (1 / 6 : ℝ) - η := by simp_all have h_exists_N₀ : ∃ (N₀ : ℕ), (N₀ : ℝ) ≥ (2 : ℝ) / ((1 / 6 : ℝ) - η) := by exact ⟨⌈(2 : ℝ) / ((1 / 6 : ℝ) - η)⌉₊, by exact_mod_cast Nat.le_ceil _⟩ obtain ⟨N₀, hN₀⟩ := h_exists_N₀ use N₀ intro n hn have h₁ : (n : ℝ) ≥ (N₀ : ℝ) := by simp_all have h₂ : (n : ℝ) ≥ (2 : ℝ) / ((1 / 6 : ℝ) - η) := by nlinarith have h₃ : ((1 / 6 : ℝ) - η) * (n : ℝ) ≥ 2 := by have := mul_le_mul_of_nonneg_left h₂ (le_of_lt h) rw [mul_div_cancel₀] at this · linarith · exact ne_of_gt h have h₄ : ((1 / 6 - η) / 2) * (n : ℝ) ≤ (1 / 6 - η) * (n : ℝ) - 1 := by nlinarith assumption lemma interval_toNat_lower_bound (η : ℝ) (hη_pos : 0 < η) (hη_lt : η < 1 / 6) : ∃ N₀ : ℕ, ∀ n : ℕ, N₀ ≤ n → ((1 / 6 - η) / 2) * (n : ℝ) ≤ ((⌊(n : ℝ) / 6⌋ + 1 - ⌈η * (n : ℝ)⌉ : ℤ).toNat : ℝ) := by obtain ⟨N₁, hN₁⟩ := int_expr_nonneg_for_large_n η hη_pos hη_lt obtain ⟨N₂, hN₂⟩ := half_bound_for_large_n η hη_pos hη_lt refine ⟨max N₁ N₂, fun n hn => ?_⟩ have hn₁ := hN₁ n (le_of_max_le_left hn) have hn₂ := hN₂ n (le_of_max_le_right hn) have h_real_lb := int_expr_real_lower_bound η n have h_nonneg := hn₁ set z := (⌊(n : ℝ) / 6⌋ + 1 - ⌈η * (n : ℝ)⌉ : ℤ) with hz_def have h_cast : (z.toNat : ℝ) = (z : ℝ) := by exact_mod_cast Int.toNat_of_nonneg h_nonneg rw [h_cast] calc ((1 / 6 - η) / 2) * (n : ℝ) ≤ (1 / 6 - η) * (n : ℝ) - 1 := hn₂ _ = (n : ℝ) / 6 - η * (n : ℝ) - 1 := by ring _ ≤ ((⌊(n : ℝ) / 6⌋ + 1 - ⌈η * (n : ℝ)⌉ : ℤ) : ℝ) := le_of_lt h_real_lb theorem interval_ncard_lower_bound (η : ℝ) (hη_pos : 0 < η) (hη_lt : η < 1 / 6) : ∃ (N₀ : ℕ), ∀ n : ℕ, N₀ ≤ n → ((1 / 6 - η) / 2) * (n : ℝ) ≤ ((Set.Icc (⌈η * (n : ℝ)⌉ : ℤ) (⌊(n : ℝ) / 6⌋ : ℤ)).ncard : ℝ) := by obtain ⟨N₀, hN₀⟩ := interval_toNat_lower_bound η hη_pos hη_lt exact ⟨N₀, fun n hn => by rw [Int_Icc_ncard] exact hN₀ n hn⟩ lemma coprime_pairs_subset_product (A B : ℤ) : {pq : ℤ × ℤ | A ≤ pq.1 ∧ pq.1 ≤ B ∧ A ≤ pq.2 ∧ pq.2 ≤ B ∧ Int.gcd pq.1 pq.2 = 1} ⊆ Set.Icc A B ×ˢ Set.Icc A B := by intro ⟨a, b⟩ h simp only [Set.mem_setOf_eq, Set.mem_prod, Set.mem_Icc] at h ⊢ have h₁ : A ≤ a := h.1 have h₂ : a ≤ B := h.2.1 have h₃ : A ≤ b := h.2.2.1 have h₄ : b ≤ B := h.2.2.2.1 exact ⟨⟨h₁, h₂⟩, ⟨h₃, h₄⟩⟩ lemma coprime_pairs_finite (A B : ℤ) : {pq : ℤ × ℤ | A ≤ pq.1 ∧ pq.1 ≤ B ∧ A ≤ pq.2 ∧ pq.2 ≤ B ∧ Int.gcd pq.1 pq.2 = 1}.Finite := by have h₁ : {pq : ℤ × ℤ | A ≤ pq.1 ∧ pq.1 ≤ B ∧ A ≤ pq.2 ∧ pq.2 ≤ B ∧ Int.gcd pq.1 pq.2 = 1} ⊆ Set.Icc (A, A) (B, B) := by intro ⟨x, y⟩ h simp only [Set.mem_setOf_eq, Set.mem_Icc, Prod.le_def] at h ⊢ constructor <;> (try constructor) <;> (try simp_all [Int.le_of_lt_add_one]) have h₂ : Set.Finite (Set.Icc (A, A) (B, B)) := by apply Set.Finite.subset (Set.finite_mem_finset (Finset.Icc (A, A) (B, B))) intro ⟨x, y⟩ h simp only [Set.mem_Icc, Finset.mem_Icc, Prod.le_def] at h ⊢ aesop exact Set.Finite.subset h₂ h₁ lemma sq_add_one_le (a : ℝ) : (a + 1) ^ 2 ≤ 5 / 4 * a ^ 2 + 5 := by nlinarith [sq_nonneg (a - 4)] lemma inv_sq_le_inv_pred_mul (k : ℕ) (hk : 2 ≤ k) : (1 : ℝ) / (k : ℝ) ^ 2 ≤ 1 / ((k - 1 : ℝ) * k) := by have h₁ : (2 : ℝ) ≤ (k : ℝ) := by exact_mod_cast hk have h₃ : (0 : ℝ) < (k : ℝ) - 1 := by linarith have h₇ : (1 : ℝ) / (k : ℝ) ^ 2 ≤ 1 / ((k - 1 : ℝ) * k) := by apply one_div_le_one_div_of_le · positivity · nlinarith exact h₇ lemma telescoping_sum_eq (N : ℕ) (hN : 3 ≤ N) : ∑ k ∈ Finset.Icc 3 N, (1 : ℝ) / ((k - 1 : ℝ) * k) = 1 / 2 - 1 / N := by have h₁ : ∀ n : ℕ, 3 ≤ n → ∑ k ∈ Finset.Icc 3 n, (1 : ℝ) / ((k - 1 : ℝ) * k) = 1 / 2 - 1 / n := by intro n hn induction' hn with n hn IH · norm_num [Finset.sum_Icc_succ_top] · cases n with | zero => contradiction | succ n => cases n with | zero => contradiction | succ n => cases n with | zero => contradiction | succ n => simp_all [Finset.sum_Icc_succ_top, Nat.cast_add, Nat.cast_one, Nat.cast_zero, Nat.cast_succ] <;> field_simp [Nat.cast_add_one_ne_zero] <;> ring_nf have h₂ : ∑ k ∈ Finset.Icc 3 N, (1 : ℝ) / ((k - 1 : ℝ) * k) = 1 / 2 - 1 / N := by have h₃ := h₁ N hN exact h₃ exact h₂ lemma tail_sum_le_half (N : ℕ) : ∑ k ∈ Finset.Icc 3 N, (1 : ℝ) / (k : ℝ) ^ 2 ≤ 1 / 2 := by by_cases hN : 3 ≤ N · calc ∑ k ∈ Finset.Icc 3 N, (1 : ℝ) / (k : ℝ) ^ 2 ≤ ∑ k ∈ Finset.Icc 3 N, 1 / ((k - 1 : ℝ) * k) := by apply Finset.sum_le_sum intro k hk have hk3 : 3 ≤ k := (Finset.mem_Icc.mp hk).1 exact inv_sq_le_inv_pred_mul k (by omega) _ = 1 / 2 - 1 / N := telescoping_sum_eq N hN _ ≤ 1 / 2 := by linarith [show (0 : ℝ) ≤ 1 / (N : ℝ) from by positivity] · have : Finset.Icc 3 N = ∅ := by simp [Finset.Icc_eq_empty_iff] omega simp [this] lemma sum_Icc_split (N : ℕ) (hN : 2 ≤ N) (f : ℕ → ℝ) : ∑ k ∈ Finset.Icc 2 N, f k = f 2 + ∑ k ∈ Finset.Icc 3 N, f k := by have h_main : Finset.Icc 2 N = {2} ∪ Finset.Icc 3 N := by ext x; simp [Finset.mem_Icc, Finset.mem_union, Finset.mem_singleton]; omega have h_sum : ∑ k ∈ Finset.Icc 2 N, f k = f 2 + ∑ k ∈ Finset.Icc 3 N, f k := by simp_all assumption lemma sum_inv_sq_le_three_fourths (N : ℕ) : ∑ k ∈ Finset.Icc 2 N, (1 : ℝ) / (k : ℝ) ^ 2 ≤ 3 / 4 := by by_cases hN : 2 ≤ N · rw [sum_Icc_split N hN] have h1 : (1 : ℝ) / (2 : ℝ) ^ 2 = 1 / 4 := by norm_num have h2 : ∑ k ∈ Finset.Icc 3 N, (1 : ℝ) / (k : ℝ) ^ 2 ≤ 1 / 2 := tail_sum_le_half N linarith · have : Finset.Icc 2 N = ∅ := by push_neg at hN exact Finset.Icc_eq_empty (by omega) simp [this]; norm_num lemma multiples_finite (A B : ℤ) (m : ℕ) : {x : ℤ | A ≤ x ∧ x ≤ B ∧ (m : ℤ) ∣ x}.Finite := by have h : {x : ℤ | A ≤ x ∧ x ≤ B ∧ (m : ℤ) ∣ x} ⊆ Set.Icc A B := by intro x hx simp only [Set.mem_Icc, Set.mem_setOf_eq] at hx ⊢ exact ⟨hx.1, hx.2.1⟩ have h2 : (Set.Icc A B : Set ℤ).Finite := Set.finite_Icc A B exact Set.Finite.subset h2 h lemma toNat_inj_of_nonneg (a b : ℤ) (ha : 0 ≤ a) (hb : 0 ≤ b) (h : a.toNat = b.toNat) : a = b := by have h₁ : (a.toNat : ℤ) = a := by rw [Int.toNat_of_nonneg ha] have h₂ : (b.toNat : ℤ) = b := by rw [Int.toNat_of_nonneg hb] have h₄ : a = b := by linarith exact h₄ lemma emod_eq_of_dvd (x₁ x₂ A : ℤ) (m : ℤ) (h₁ : m ∣ x₁) (h₂ : m ∣ x₂) : (x₁ - A) % m = (x₂ - A) % m := by have h₃ : (x₁ - A) % m = ((x₁ % m) - (A % m)) % m := by rw [Int.sub_emod] have h₄ : (x₂ - A) % m = ((x₂ % m) - (A % m)) % m := by rw [Int.sub_emod] have h₅ : x₁ % m = 0 := by exact Int.emod_eq_zero_of_dvd h₁ have h₆ : x₂ % m = 0 := by exact Int.emod_eq_zero_of_dvd h₂ rw [h₃, h₄, h₅, h₆] lemma eq_of_ediv_eq_emod_eq (a b m : ℤ) (hm : m ≠ 0) (hdiv : a / m = b / m) (hmod : a % m = b % m) : a = b := by have h₁ : a % m + m * (a / m) = a := Int.emod_add_mul_ediv a m have h₂ : b % m + m * (b / m) = b := Int.emod_add_mul_ediv b m have h₅ : a = b := by simp_all assumption lemma shift_div_toNat_injOn (A B : ℤ) (m : ℕ) (hm : 0 < m) : Set.InjOn (fun x => ((x - A) / (m : ℤ)).toNat) {x : ℤ | A ≤ x ∧ x ≤ B ∧ (m : ℤ) ∣ x} := by intro x₁ hx₁ x₂ hx₂ heq simp only [Set.mem_setOf_eq] at hx₁ hx₂ have hm' : (m : ℤ) ≠ 0 := Int.natCast_ne_zero.mpr (Nat.pos_iff_ne_zero.mp hm) have hm_pos : (0 : ℤ) < m := Int.natCast_pos.mpr hm have h1_nn : 0 ≤ x₁ - A := Int.sub_nonneg.mpr hx₁.1 have h2_nn : 0 ≤ x₂ - A := Int.sub_nonneg.mpr hx₂.1 have hq1 : 0 ≤ (x₁ - A) / (m : ℤ) := Int.ediv_nonneg h1_nn (le_of_lt hm_pos) have hq2 : 0 ≤ (x₂ - A) / (m : ℤ) := Int.ediv_nonneg h2_nn (le_of_lt hm_pos) have hdiv : (x₁ - A) / (m : ℤ) = (x₂ - A) / (m : ℤ) := toNat_inj_of_nonneg _ _ hq1 hq2 heq have hmod : (x₁ - A) % (m : ℤ) = (x₂ - A) % (m : ℤ) := emod_eq_of_dvd x₁ x₂ A (m : ℤ) hx₁.2.2 hx₂.2.2 have hsub : x₁ - A = x₂ - A := eq_of_ediv_eq_emod_eq _ _ (m : ℤ) hm' hdiv hmod linarith lemma shift_div_toNat_le (A B : ℤ) (m : ℕ) (hm : 0 < m) (x : ℤ) (hxA : A ≤ x) (hxB : x ≤ B) : ((x - A) / (m : ℤ)).toNat ≤ (B + 1 - A).toNat / m := by have h₁ : 0 ≤ (x - A : ℤ) := by linarith have h₂ : (x - A : ℤ) ≤ (B + 1 - A : ℤ) := by linarith have h₃ : 0 ≤ (B + 1 - A : ℤ) := by linarith have hm_pos_int : (0 : ℤ) < m := Int.natCast_pos.mpr hm have hq : 0 ≤ (x - A) / (m : ℤ) := Int.ediv_nonneg h₁ (le_of_lt hm_pos_int) have hxa_le : (x - A) / (m : ℤ) ≤ (B + 1 - A) / (m : ℤ) := Int.ediv_le_ediv hm_pos_int h₂ have hba_q : 0 ≤ (B + 1 - A) / (m : ℤ) := Int.ediv_nonneg h₃ (le_of_lt hm_pos_int) have key1 : ((x - A) / (m : ℤ)).toNat ≤ ((B + 1 - A) / (m : ℤ)).toNat := Int.toNat_le_toNat hxa_le have key2 : ((B + 1 - A) / (m : ℤ)).toNat = (B + 1 - A).toNat / m := by have h_cast : (B + 1 - A : ℤ) = ((B + 1 - A).toNat : ℤ) := (Int.toNat_of_nonneg h₃).symm conv_lhs => rw [h_cast] rw [← Int.natCast_div, Int.toNat_natCast] omega lemma shift_div_image_subset_range (A B : ℤ) (m : ℕ) (hm : 0 < m) : (fun x => ((x - A) / (m : ℤ)).toNat) '' {x : ℤ | A ≤ x ∧ x ≤ B ∧ (m : ℤ) ∣ x} ⊆ ↑(Finset.range ((Set.Icc A B).ncard / m + 1)) := by intro y hy rw [Finset.mem_coe, Finset.mem_range] obtain ⟨x, ⟨hxA, hxB, _⟩, rfl⟩ := hy simp only have h := shift_div_toNat_le A B m hm x hxA hxB rw [Int_Icc_ncard] omega lemma ncard_multiples_le (A B : ℤ) (m : ℕ) (hm : 0 < m) : ({x : ℤ | A ≤ x ∧ x ≤ B ∧ (m : ℤ) ∣ x}).ncard ≤ (Set.Icc A B).ncard / m + 1 := by have h1 := shift_div_toNat_injOn A B m hm have h2 := shift_div_image_subset_range A B m hm have h3 := multiples_finite A B m calc ({x : ℤ | A ≤ x ∧ x ≤ B ∧ (m : ℤ) ∣ x}).ncard = ((fun x => ((x - A) / (m : ℤ)).toNat) '' {x : ℤ | A ≤ x ∧ x ≤ B ∧ (m : ℤ) ∣ x}).ncard := by rw [Set.ncard_image_of_injOn h1] _ ≤ ((Finset.range ((Set.Icc A B).ncard / m + 1) : Set ℕ)).ncard := by exact Set.ncard_le_ncard h2 (Set.toFinite _) _ = (Set.Icc A B).ncard / m + 1 := by rw [Set.ncard_coe_finset, Finset.card_range] lemma exists_prime_dvd_both (A B : ℤ) (B' : ℕ) (hB' : ∀ p : ℤ, A ≤ p → p ≤ B → ∀ ℓ : ℕ, Nat.Prime ℓ → (ℓ : ℤ) ∣ p → ℓ ≤ B') (p q : ℤ) (hAp : A ≤ p) (hpB : p ≤ B) (hAq : A ≤ q) (hqB : q ≤ B) (hgcd : Int.gcd p q ≠ 1) : ∃ ℓ : ℕ, Nat.Prime ℓ ∧ 2 ≤ ℓ ∧ ℓ ≤ B' ∧ (ℓ : ℤ) ∣ p ∧ (ℓ : ℤ) ∣ q := by obtain ⟨ℓ, hℓprime, hℓdvd⟩ := Nat.exists_prime_and_dvd hgcd have hgcd_dvd_p : (↑(Int.gcd p q) : ℤ) ∣ p := by rw [Int.coe_gcd]; exact GCDMonoid.gcd_dvd_left p q have hgcd_dvd_q : (↑(Int.gcd p q) : ℤ) ∣ q := by rw [Int.coe_gcd]; exact GCDMonoid.gcd_dvd_right p q have hℓdvd_gcd_int : (ℓ : ℤ) ∣ ↑(Int.gcd p q) := Nat.cast_dvd_cast hℓdvd have hℓdvd_p : (ℓ : ℤ) ∣ p := dvd_trans hℓdvd_gcd_int hgcd_dvd_p have hℓdvd_q : (ℓ : ℤ) ∣ q := dvd_trans hℓdvd_gcd_int hgcd_dvd_q exact ⟨ℓ, hℓprime, hℓprime.two_le, hB' p hAp hpB ℓ hℓprime hℓdvd_p, hℓdvd_p, hℓdvd_q⟩ lemma non_coprime_subset_union (A B : ℤ) (hAB : A ≤ B) (B' : ℕ) (hB' : ∀ p : ℤ, A ≤ p → p ≤ B → ∀ ℓ : ℕ, Nat.Prime ℓ → (ℓ : ℤ) ∣ p → ℓ ≤ B') : let S := Set.Icc A B ×ˢ Set.Icc A B let C := {pq : ℤ × ℤ | A ≤ pq.1 ∧ pq.1 ≤ B ∧ A ≤ pq.2 ∧ pq.2 ≤ B ∧ Int.gcd pq.1 pq.2 = 1} S \ C ⊆ ⋃ ℓ ∈ (Finset.Icc 2 B').filter Nat.Prime, ({x : ℤ | A ≤ x ∧ x ≤ B ∧ (ℓ : ℤ) ∣ x}) ×ˢ ({x : ℤ | A ≤ x ∧ x ≤ B ∧ (ℓ : ℤ) ∣ x}) := by intro S C pq hpq simp only [Set.mem_diff] at hpq obtain ⟨hS, hnotC⟩ := hpq rw [Set.mem_prod] at hS have hAp := (Set.mem_Icc.mp hS.1).1 have hpB := (Set.mem_Icc.mp hS.1).2 have hAq := (Set.mem_Icc.mp hS.2).1 have hqB := (Set.mem_Icc.mp hS.2).2 have hgcd : Int.gcd pq.1 pq.2 ≠ 1 := by intro h exact hnotC ⟨hAp, hpB, hAq, hqB, h⟩ obtain ⟨ℓ, hprime, h2le, hleB', hdvdp, hdvdq⟩ := exists_prime_dvd_both A B B' hB' pq.1 pq.2 hAp hpB hAq hqB hgcd simp only [Set.mem_iUnion, Set.mem_prod, Set.mem_setOf_eq] exact ⟨ℓ, Finset.mem_filter.mpr ⟨Finset.mem_Icc.mpr ⟨h2le, hleB'⟩, hprime⟩, ⟨hAp, hpB, hdvdp⟩, ⟨hAq, hqB, hdvdq⟩⟩ lemma ncard_multiples_prod_le (A B : ℤ) (ℓ : ℕ) (hℓ : Nat.Prime ℓ) : let L := (Set.Icc A B).ncard let Mℓ := {x : ℤ | A ≤ x ∧ x ≤ B ∧ (ℓ : ℤ) ∣ x} (Mℓ ×ˢ Mℓ).ncard ≤ (L / ℓ + 1) ^ 2 := by intro L Mℓ have hℓpos : 0 < ℓ := hℓ.pos calc (Mℓ ×ˢ Mℓ).ncard = Mℓ.ncard * Mℓ.ncard := Set.ncard_prod _ = Mℓ.ncard ^ 2 := (sq Mℓ.ncard).symm _ ≤ (L / ℓ + 1) ^ 2 := by apply pow_le_pow_left' (ncard_multiples_le A B ℓ hℓpos) lemma non_coprime_ncard_le_sum (A B : ℤ) (hAB : A ≤ B) (B' : ℕ) (hB' : ∀ p : ℤ, A ≤ p → p ≤ B → ∀ ℓ : ℕ, Nat.Prime ℓ → (ℓ : ℤ) ∣ p → ℓ ≤ B') : let L := (Set.Icc A B).ncard let S := Set.Icc A B ×ˢ Set.Icc A B let C := {pq : ℤ × ℤ | A ≤ pq.1 ∧ pq.1 ≤ B ∧ A ≤ pq.2 ∧ pq.2 ≤ B ∧ Int.gcd pq.1 pq.2 = 1} (S \ C).ncard ≤ ∑ ℓ ∈ (Finset.Icc 2 B').filter Nat.Prime, (L / ℓ + 1) ^ 2 := by intro L S C have h_sub := non_coprime_subset_union A B hAB B' hB' have h_fin_union : (⋃ ℓ ∈ (Finset.Icc 2 B').filter Nat.Prime, ({x : ℤ | A ≤ x ∧ x ≤ B ∧ (ℓ : ℤ) ∣ x}) ×ˢ ({x : ℤ | A ≤ x ∧ x ≤ B ∧ (ℓ : ℤ) ∣ x})).Finite := by apply Set.Finite.subset ((Set.finite_Icc A B).prod (Set.finite_Icc A B)) intro ⟨x, y⟩ hxy simp only [Set.mem_iUnion, Set.mem_prod, Set.mem_setOf_eq] at hxy ⊢ obtain ⟨ℓ, _, ⟨hx1, hx2, _⟩, hy1, hy2, _⟩ := hxy exact ⟨⟨hx1, hx2⟩, hy1, hy2⟩ calc (S \ C).ncard ≤ (⋃ ℓ ∈ (Finset.Icc 2 B').filter Nat.Prime, ({x : ℤ | A ≤ x ∧ x ≤ B ∧ (ℓ : ℤ) ∣ x}) ×ˢ ({x : ℤ | A ≤ x ∧ x ≤ B ∧ (ℓ : ℤ) ∣ x})).ncard := by exact Set.ncard_le_ncard h_sub h_fin_union _ ≤ ∑ ℓ ∈ (Finset.Icc 2 B').filter Nat.Prime, (({x : ℤ | A ≤ x ∧ x ≤ B ∧ (ℓ : ℤ) ∣ x}) ×ˢ ({x : ℤ | A ≤ x ∧ x ≤ B ∧ (ℓ : ℤ) ∣ x})).ncard := by exact Finset.set_ncard_biUnion_le _ _ _ ≤ ∑ ℓ ∈ (Finset.Icc 2 B').filter Nat.Prime, (L / ℓ + 1) ^ 2 := by apply Finset.sum_le_sum intro ℓ hℓ have hprime : Nat.Prime ℓ := (Finset.mem_filter.mp hℓ).2 exact ncard_multiples_prod_le A B ℓ hprime lemma card_primes_le_B' (B' : ℕ) : ((Finset.Icc 2 B').filter Nat.Prime).card ≤ B' := by calc ((Finset.Icc 2 B').filter Nat.Prime).card ≤ (Finset.Icc 2 B').card := Finset.card_filter_le _ _ _ = B' + 1 - 2 := Nat.card_Icc 2 B' _ ≤ B' := by omega lemma sum_inv_sq_primes_le (B' : ℕ) : ∑ ℓ ∈ (Finset.Icc 2 B').filter Nat.Prime, (1 : ℝ) / (ℓ : ℝ) ^ 2 ≤ 3 / 4 := by calc ∑ ℓ ∈ (Finset.Icc 2 B').filter Nat.Prime, (1 : ℝ) / (ℓ : ℝ) ^ 2 ≤ ∑ ℓ ∈ Finset.Icc 2 B', (1 : ℝ) / (ℓ : ℝ) ^ 2 := by apply Finset.sum_le_sum_of_subset_of_nonneg (Finset.filter_subset _ _) intro i _ _ positivity _ ≤ 3 / 4 := sum_inv_sq_le_three_fourths B' lemma term_sq_bound (L ℓ : ℕ) (hℓ : 2 ≤ ℓ) : ((L / ℓ + 1 : ℕ) : ℝ) ^ 2 ≤ 5 / 4 * (L : ℝ) ^ 2 / (ℓ : ℝ) ^ 2 + 5 := by have hℓpos : (0 : ℝ) < (ℓ : ℝ) := by positivity push_cast have h1 : (↑(L / ℓ) : ℝ) ≤ (↑L : ℝ) / (↑ℓ : ℝ) := Nat.cast_div_le have h2 : ((↑(L / ℓ) : ℝ) + 1) ^ 2 ≤ ((↑L : ℝ) / (↑ℓ : ℝ) + 1) ^ 2 := by apply pow_le_pow_left₀ (by positivity) linarith have h3 : ((↑L : ℝ) / (↑ℓ : ℝ) + 1) ^ 2 ≤ 5 / 4 * ((↑L : ℝ) / (↑ℓ : ℝ)) ^ 2 + 5 := sq_add_one_le _ rw [div_pow] at h3 rw [mul_div_assoc] linarith lemma sum_sq_bound_real (L B' : ℕ) : (∑ ℓ ∈ (Finset.Icc 2 B').filter Nat.Prime, ((L / ℓ + 1 : ℕ) : ℝ) ^ 2) ≤ 15 / 16 * (L : ℝ) ^ 2 + 5 * (B' : ℝ) := by set P := (Finset.Icc 2 B').filter Nat.Prime have h1 : ∀ ℓ ∈ P, ((L / ℓ + 1 : ℕ) : ℝ) ^ 2 ≤ 5 / 4 * (L : ℝ) ^ 2 / (ℓ : ℝ) ^ 2 + 5 := by intro ℓ hℓ apply term_sq_bound exact (Finset.mem_filter.mp hℓ).1 |> Finset.mem_Icc.mp |>.1 calc ∑ ℓ ∈ P, ((L / ℓ + 1 : ℕ) : ℝ) ^ 2 ≤ ∑ ℓ ∈ P, (5 / 4 * (L : ℝ) ^ 2 / (ℓ : ℝ) ^ 2 + 5) := Finset.sum_le_sum h1 _ = ∑ ℓ ∈ P, (5 / 4 * (L : ℝ) ^ 2 / (ℓ : ℝ) ^ 2) + ∑ ℓ ∈ P, (5 : ℝ) := Finset.sum_add_distrib _ = 5 / 4 * (L : ℝ) ^ 2 * (∑ ℓ ∈ P, (1 : ℝ) / (ℓ : ℝ) ^ 2) + ∑ ℓ ∈ P, (5 : ℝ) := by congr 1 rw [Finset.mul_sum] congr 1; ext ℓ; ring _ = 5 / 4 * (L : ℝ) ^ 2 * (∑ ℓ ∈ P, (1 : ℝ) / (ℓ : ℝ) ^ 2) + P.card * 5 := by congr 1 rw [Finset.sum_const, nsmul_eq_mul] _ ≤ 5 / 4 * (L : ℝ) ^ 2 * (3 / 4) + (B' : ℝ) * 5 := by gcongr · exact sum_inv_sq_primes_le B' · exact_mod_cast card_primes_le_B' B' _ = 15 / 16 * (L : ℝ) ^ 2 + 5 * (B' : ℝ) := by ring lemma non_coprime_pairs_upper_bound (A B : ℤ) (hAB : A ≤ B) (B' : ℕ) (hB' : ∀ p : ℤ, A ≤ p → p ≤ B → ∀ ℓ : ℕ, Nat.Prime ℓ → (ℓ : ℤ) ∣ p → ℓ ≤ B') : let L := (Set.Icc A B).ncard let S := Set.Icc A B ×ˢ Set.Icc A B let C := {pq : ℤ × ℤ | A ≤ pq.1 ∧ pq.1 ≤ B ∧ A ≤ pq.2 ∧ pq.2 ≤ B ∧ Int.gcd pq.1 pq.2 = 1} ((S \ C).ncard : ℝ) ≤ 15 / 16 * (L : ℝ) ^ 2 + 5 * (B' : ℝ) := by intro L S C have h1 := non_coprime_ncard_le_sum A B hAB B' hB' have h2 := sum_sq_bound_real L B' calc ((S \ C).ncard : ℝ) ≤ (∑ ℓ ∈ (Finset.Icc 2 B').filter Nat.Prime, (L / ℓ + 1) ^ 2 : ℕ) := by exact_mod_cast h1 _ = ∑ ℓ ∈ (Finset.Icc 2 B').filter Nat.Prime, ((L / ℓ + 1 : ℕ) : ℝ) ^ 2 := by push_cast; ring_nf _ ≤ 15 / 16 * (L : ℝ) ^ 2 + 5 * (B' : ℝ) := h2 lemma coprime_lower_bound_from_complement (L : ℕ) (C_card NC_card : ℕ) (B' : ℕ) (h_partition : C_card + NC_card = L * L) (h_NC_bound : (NC_card : ℝ) ≤ 15 / 16 * (L : ℝ) ^ 2 + 5 * (B' : ℝ)) : (L : ℝ) ^ 2 / 16 - 5 * (B' : ℝ) ≤ (C_card : ℝ) := by have h₁ : (C_card : ℝ) + (NC_card : ℝ) = (L : ℝ) ^ 2 := by have h₁₁ : (C_card + NC_card : ℕ) = L * L := by exact_mod_cast h_partition have h₁₂ : (C_card : ℝ) + (NC_card : ℝ) = (L : ℝ) * (L : ℝ) := by norm_cast at h₁₁ ⊢ linarith linarith lemma coprime_pairs_sieve_lower_bound (A B : ℤ) (hAB : A ≤ B) (B' : ℕ) (hB' : ∀ p : ℤ, A ≤ p → p ≤ B → ∀ ℓ : ℕ, Nat.Prime ℓ → (ℓ : ℤ) ∣ p → ℓ ≤ B') : let L := (Set.Icc A B).ncard (L : ℝ) ^ 2 / 16 - 5 * (B' : ℝ) ≤ ({pq : ℤ × ℤ | A ≤ pq.1 ∧ pq.1 ≤ B ∧ A ≤ pq.2 ∧ pq.2 ≤ B ∧ Int.gcd pq.1 pq.2 = 1}.ncard : ℝ) := by intro L set C := {pq : ℤ × ℤ | A ≤ pq.1 ∧ pq.1 ≤ B ∧ A ≤ pq.2 ∧ pq.2 ≤ B ∧ Int.gcd pq.1 pq.2 = 1} set S := Set.Icc A B ×ˢ Set.Icc A B have hC_sub : C ⊆ S := coprime_pairs_subset_product A B have hS_fin : S.Finite := (Set.finite_Icc A B).prod (Set.finite_Icc A B) have hNC := non_coprime_pairs_upper_bound A B hAB B' hB' have h_part := Set.ncard_diff_add_ncard_of_subset hC_sub hS_fin have hS_card : S.ncard = L * L := Set.ncard_prod rw [hS_card] at h_part exact coprime_lower_bound_from_complement L C.ncard (S \ C).ncard B' (by omega) (hNC) lemma quadratic_dominates_linear (δ L n B' : ℝ) (hδ : 0 < δ) (hn : 0 ≤ n) (hL : δ * n ≤ L) (hB' : 5 * B' ≤ 5 * n) (hn_large : 160 / δ ^ 2 ≤ n) : δ ^ 2 / 32 * n ^ 2 ≤ L ^ 2 / 16 - 5 * B' := by have hL_sq : δ ^ 2 * n ^ 2 ≤ L ^ 2 := by have h₁ : 0 ≤ δ * n := by positivity have h₄ : (δ * n) ^ 2 ≤ L ^ 2 := by nlinarith [sq_nonneg (L - δ * n)] linarith have h_nδ_ge : n * δ ^ 2 ≥ 160 := by have h₂ : 0 < δ ^ 2 := by positivity have h₃ : 160 ≤ n * δ ^ 2 := by calc 160 = (160 / δ ^ 2) * δ ^ 2 := by field_simp [h₂.ne'] _ ≤ n * δ ^ 2 := by nlinarith linarith have h_nδ_sq_ge : δ ^ 2 / 32 * n ^ 2 ≥ 5 * n := by have h₇ : n * (n * δ ^ 2) ≥ n * 160 := by nlinarith linarith linarith lemma ceil_eta_n_pos (η : ℝ) (hη_pos : 0 < η) (n : ℕ) (hn : 1 ≤ n) : 1 ≤ (⌈η * (n : ℝ)⌉ : ℤ) := by have h_main : 0 < (η : ℝ) * (n : ℝ) := by positivity have h_ceil_pos : 1 ≤ (⌈η * (n : ℝ)⌉ : ℤ) := by have h₂ : 1 ≤ ⌈(η * (n : ℝ))⌉ := by have h₄ : (⌈(η * (n : ℝ))⌉ : ℝ) ≥ (η * (n : ℝ)) := by exact Int.le_ceil _ have h₆ : (⌈(η * (n : ℝ))⌉ : ℤ) ≥ 1 := by by_contra h have h₇ : (⌈(η * (n : ℝ))⌉ : ℤ) ≤ 0 := by linarith have h₈ : (⌈(η * (n : ℝ))⌉ : ℝ) ≤ 0 := by exact_mod_cast h₇ nlinarith exact_mod_cast h₆ exact_mod_cast h₂ exact h_ceil_pos lemma floor_div_six_le_n (n : ℕ) : (⌊(n : ℝ) / 6⌋ : ℤ) ≤ (n : ℤ) := by have h₁ : (n : ℝ) / 6 ≤ (n : ℝ) := by nlinarith have h₂ : ((⌊(n : ℝ) / 6⌋ : ℤ) : ℝ) ≤ (n : ℝ) / 6 := Int.floor_le _ have h₃ : ((⌊(n : ℝ) / 6⌋ : ℤ) : ℝ) ≤ (n : ℝ) := by nlinarith exact_mod_cast h₃ lemma interval_ncard_le_n (η : ℝ) (hη_pos : 0 < η) (n : ℕ) (hn : ⌈1 / η⌉₊ ≤ n) : (Set.Icc (⌈η * (n : ℝ)⌉ : ℤ) (⌊(n : ℝ) / 6⌋ : ℤ)).ncard ≤ n := by rw [Int_Icc_ncard] have h1 : 1 ≤ n := by have : 0 < ⌈1 / η⌉₊ := Nat.ceil_pos.mpr (by positivity) omega have hceil := ceil_eta_n_pos η hη_pos n h1 have hfloor := floor_div_six_le_n n omega lemma interval_ncard_upper_bound (η : ℝ) (hη_pos : 0 < η) : ∃ (N₀ : ℕ), ∀ n : ℕ, N₀ ≤ n → ((Set.Icc (⌈η * (n : ℝ)⌉ : ℤ) (⌊(n : ℝ) / 6⌋ : ℤ)).ncard : ℝ) ≤ (n : ℝ) := by exact ⟨⌈1 / η⌉₊, fun n hn => by exact_mod_cast interval_ncard_le_n η hη_pos n hn⟩ lemma prime_dvd_le_of_pos (p : ℤ) (hp : 0 < p) (ℓ : ℕ) (hprime : Nat.Prime ℓ) (hdvd : (ℓ : ℤ) ∣ p) : (ℓ : ℤ) ≤ p := by have h₂ : (ℓ : ℤ) ≤ p := by have h₃ : (ℓ : ℤ) ∣ p := hdvd have h₄ : (ℓ : ℤ) ≤ p := Int.le_of_dvd hp h₃ exact h₄ exact h₂ lemma prime_divisor_bound (η : ℝ) (hη_pos : 0 < η) (n : ℕ) (hn : 1 ≤ n) : ∀ p : ℤ, (⌈η * (n : ℝ)⌉ : ℤ) ≤ p → p ≤ (⌊(n : ℝ) / 6⌋ : ℤ) → ∀ ℓ : ℕ, Nat.Prime ℓ → (ℓ : ℤ) ∣ p → ℓ ≤ n := by intro p hp_low hp_high ℓ hprime hdvd have hp_pos : 0 < p := lt_of_lt_of_le (by linarith [ceil_eta_n_pos η hη_pos n hn]) hp_low have hℓp : (ℓ : ℤ) ≤ p := prime_dvd_le_of_pos p hp_pos ℓ hprime hdvd have hpn : p ≤ (n : ℤ) := le_trans hp_high (floor_div_six_le_n n) exact_mod_cast le_trans hℓp hpn lemma rectangle_coprime_ncard_lower_bound (η : ℝ) (hη_pos : 0 < η) (hη_lt : η < 1 / 6) : ∃ (c : ℝ) (N₁ : ℕ), 0 < c ∧ ∀ n : ℕ, N₁ ≤ n → c * (n : ℝ) ^ 2 ≤ ({pq : ℤ × ℤ | (⌈η * (n : ℝ)⌉ : ℤ) ≤ pq.1 ∧ pq.1 ≤ (⌊(n : ℝ) / 6⌋ : ℤ) ∧ (⌈η * (n : ℝ)⌉ : ℤ) ≤ pq.2 ∧ pq.2 ≤ (⌊(n : ℝ) / 6⌋ : ℤ) ∧ Int.gcd pq.1 pq.2 = 1}.ncard : ℝ) := by set δ := (1 / 6 - η) / 2 with hδ_def have hδ : 0 < δ := by linarith obtain ⟨N₁, hN₁⟩ := interval_ncard_lower_bound η hη_pos hη_lt obtain ⟨N₂, hN₂⟩ := interval_ncard_upper_bound η hη_pos obtain ⟨N₃, hN₃⟩ := ceil_le_floor_for_large_n η hη_pos hη_lt refine ⟨δ ^ 2 / 32, max (max N₁ N₂) (max N₃ (⌈160 / δ ^ 2⌉₊ + 1)), ?_, ?_⟩ · positivity · intro n hn have hn₁ : N₁ ≤ n := le_of_max_le_left (le_of_max_le_left hn) have hn₂ : N₂ ≤ n := le_of_max_le_right (le_of_max_le_left hn) have hn₃ : N₃ ≤ n := le_of_max_le_left (le_of_max_le_right hn) have hL_lower := hN₁ n hn₁ have hL_upper := hN₂ n hn₂ have hAB := hN₃ n hn₃ have hn1 : 1 ≤ n := by omega set L := (Set.Icc (⌈η * (n : ℝ)⌉ : ℤ) (⌊(n : ℝ) / 6⌋ : ℤ)).ncard with hL_def have hnn : (0 : ℝ) ≤ (n : ℝ) := Nat.cast_nonneg n have hn_large : 160 / δ ^ 2 ≤ (n : ℝ) := by have h4 : (⌈160 / δ ^ 2⌉₊ + 1 : ℕ) ≤ n := le_of_max_le_right (le_of_max_le_right hn) have : (⌈160 / δ ^ 2⌉₊ : ℝ) ≤ (n : ℝ) := by calc (⌈160 / δ ^ 2⌉₊ : ℝ) ≤ (⌈160 / δ ^ 2⌉₊ + 1 : ℕ) := by exact_mod_cast Nat.le_succ _ _ ≤ (n : ℝ) := Nat.cast_le.mpr h4 linarith [Nat.le_ceil (160 / δ ^ 2)] have hprime := prime_divisor_bound η hη_pos n hn1 calc δ ^ 2 / 32 * (n : ℝ) ^ 2 ≤ (L : ℝ) ^ 2 / 16 - 5 * (n : ℝ) := quadratic_dominates_linear δ (L : ℝ) (n : ℝ) (n : ℝ) hδ hnn hL_lower (by linarith) hn_large _ ≤ ({pq : ℤ × ℤ | (⌈η * (n : ℝ)⌉ : ℤ) ≤ pq.1 ∧ pq.1 ≤ (⌊(n : ℝ) / 6⌋ : ℤ) ∧ (⌈η * (n : ℝ)⌉ : ℤ) ≤ pq.2 ∧ pq.2 ≤ (⌊(n : ℝ) / 6⌋ : ℤ) ∧ Int.gcd pq.1 pq.2 = 1}.ncard : ℝ) := coprime_pairs_sieve_lower_bound _ _ hAB n hprime lemma coprime_triangle_ncard_lower_bound (η : ℝ) (hη_pos : 0 < η) (hη_lt : η < 1 / 6) : ∃ (c : ℝ) (N₁ : ℕ), 0 < c ∧ ∀ n : ℕ, N₁ ≤ n → c * (n : ℝ) ^ 2 ≤ ({pq : ℤ × ℤ | η * (n : ℝ) ≤ (pq.1 : ℝ) ∧ η * (n : ℝ) ≤ (pq.2 : ℝ) ∧ (pq.1 : ℝ) + (pq.2 : ℝ) < (n : ℝ) / 2 ∧ Int.gcd pq.1 pq.2 = 1}.ncard : ℝ) := by obtain ⟨c, N₁, hc, hbound⟩ := rectangle_coprime_ncard_lower_bound η hη_pos hη_lt exact ⟨c, N₁, hc, fun n hn => le_trans (hbound n hn) (Nat.cast_le.mpr (Set.ncard_le_ncard (rectangle_coprime_subset_target n η) (coprime_triangle_finite n η)))⟩ lemma truncatedObtuseRegion_ncard_lower_bound (η : ℝ) (hη_pos : 0 < η) (hη_lt : η < 1 / 6) : ∃ (c : ℝ) (N₁ : ℕ), 0 < c ∧ ∀ n : ℕ, N₁ ≤ n → c * (n : ℝ) ^ 2 ≤ ((truncatedObtuseRegion n η).ncard : ℝ) := by obtain ⟨c, N₁, hc_pos, h_lower⟩ := coprime_triangle_ncard_lower_bound η hη_pos hη_lt exact ⟨c, N₁, hc_pos, fun n hn => by calc c * (n : ℝ) ^ 2 ≤ ({pq : ℤ × ℤ | η * (n : ℝ) ≤ (pq.1 : ℝ) ∧ η * (n : ℝ) ≤ (pq.2 : ℝ) ∧ (pq.1 : ℝ) + (pq.2 : ℝ) < (n : ℝ) / 2 ∧ Int.gcd pq.1 pq.2 = 1}.ncard : ℝ) := h_lower n hn _ ≤ ((truncatedObtuseRegion n η).ncard : ℝ) := by exact_mod_cast Set.ncard_le_ncard (coprime_triangle_subset_truncatedObtuseRegion n η) (truncatedObtuseRegion_finite n η)⟩ noncomputable def badPairsE (n : ℕ) (η : ℝ) : Set (ℤ × ℤ) := {pq ∈ truncatedObtuseRegion n η | Int.gcd pq.2 (largestPrimeFactor n : ℤ) = 1 ∧ (countingFunctionS n pq.1 pq.2 : ℝ) < (η ^ 2 / 2 : ℝ) * (Nat.totient n : ℝ)} noncomputable def pdivPairs (n : ℕ) (η : ℝ) : Set (ℤ × ℤ) := {pq ∈ truncatedObtuseRegion n η | Int.gcd pq.2 (largestPrimeFactor n : ℤ) = 1 ∧ (largestPrimeFactor n : ℤ) ∣ pq.1} noncomputable def residueBadPairs (n : ℕ) (η : ℝ) : Set (ℤ × ℤ) := {pq ∈ badPairsE n η | ¬((largestPrimeFactor n : ℤ) ∣ pq.1)} lemma sq_div_ceil_le_sq_div_log (n : ℕ) (hn : 2 ≤ n) : (n : ℝ) ^ 2 / ⌈Real.log (n : ℝ)⌉₊ ≤ (n : ℝ) ^ 2 / Real.log (n : ℝ) := by have h₁ : (1 : ℝ) < (n : ℝ) := by norm_cast have h₂ : 0 < Real.log (n : ℝ) := by exact Real.log_pos h₁ have h₃ : (Real.log (n : ℝ) : ℝ) ≤ ⌈Real.log (n : ℝ)⌉₊ := by exact Nat.le_ceil _ have h₄ : 0 ≤ (n : ℝ) ^ 2 := by simp have h₅ : (n : ℝ) ^ 2 / ⌈Real.log (n : ℝ)⌉₊ ≤ (n : ℝ) ^ 2 / Real.log (n : ℝ) := by exact div_le_div_of_nonneg_left h₄ h₂ h₃ assumption lemma div_toNat_mem_range (B : ℤ) (P : ℕ) (hP : 0 < P) (hB : 0 ≤ B) (x : ℤ) (hx0 : 0 ≤ x) (hxB : x ≤ B) : (x / (P : ℤ)).toNat < B.toNat / P + 1 := by have h₂ : (x / (P : ℤ)).toNat = x.toNat / P := by have : x / (P : ℤ) = ↑(x.toNat / P) := by simp_all rw [this, Int.toNat_natCast] have h₃ : x.toNat ≤ B.toNat := by omega have h₄ : x.toNat / P ≤ B.toNat / P := Nat.div_le_div_right h₃ omega lemma inj_div_toNat (B : ℤ) (P : ℕ) (hP : 0 < P) : Set.InjOn (fun x : ℤ => (x / (P : ℤ)).toNat) {x : ℤ | 0 ≤ x ∧ x ≤ B ∧ (P : ℤ) ∣ x} := by intro x hx y hy hxy have hx₁ : 0 ≤ x := hx.1 have hx₂ : x ≤ B := hx.2.1 have hx₃ : (P : ℤ) ∣ x := hx.2.2 have hy₁ : 0 ≤ y := hy.1 have hy₂ : y ≤ B := hy.2.1 have hy₃ : (P : ℤ) ∣ y := hy.2.2 have h₁ : (x / (P : ℤ)).toNat = (y / (P : ℤ)).toNat := hxy have h₂ : (P : ℤ) ≠ 0 := by norm_cast omega have h₃ : x / (P : ℤ) = y / (P : ℤ) := by have h₄ : 0 ≤ x / (P : ℤ) := by have h₇ : 0 ≤ x / (P : ℤ) := by apply Int.ediv_nonneg · exact hx₁ · exact by positivity exact h₇ have h₅ : 0 ≤ y / (P : ℤ) := by have h₈ : 0 ≤ y / (P : ℤ) := by apply Int.ediv_nonneg · exact hy₁ · exact by positivity exact h₈ have h₆ : (x / (P : ℤ)).toNat = (y / (P : ℤ)).toNat := h₁ have h₇ : x / (P : ℤ) ≥ 0 := h₄ have h₈ : y / (P : ℤ) ≥ 0 := h₅ have h₉ : (x / (P : ℤ)).toNat = (y / (P : ℤ)).toNat := h₁ have h₁₀ : x / (P : ℤ) = y / (P : ℤ) := by have h₁₁ : (x / (P : ℤ)).toNat = (y / (P : ℤ)).toNat := h₉ have h₁₂ : x / (P : ℤ) = y / (P : ℤ) := by have h₁₃ : 0 ≤ x / (P : ℤ) := h₄ have h₁₄ : 0 ≤ y / (P : ℤ) := h₅ have h₁₅ : (x / (P : ℤ)).toNat = (y / (P : ℤ)).toNat := h₁₁ have h₁₆ : x / (P : ℤ) = y / (P : ℤ) := by rw [← Int.ofNat_inj] at * simp_all exact h₁₆ exact h₁₂ exact h₁₀ have h₄ : x = y := by have h₅ : x / (P : ℤ) = y / (P : ℤ) := h₃ have h₈ : x = (x / (P : ℤ)) * (P : ℤ) := by have h₉ : (P : ℤ) ∣ x := hx₃ have h₁₀ : (x / (P : ℤ)) * (P : ℤ) = x := by have h₁₁ : (x / (P : ℤ)) * (P : ℤ) = x := by apply Int.ediv_mul_cancel h₉ exact h₁₁ linarith have h₉ : y = (y / (P : ℤ)) * (P : ℤ) := by have h₁₀ : (P : ℤ) ∣ y := hy₃ have h₁₁ : (y / (P : ℤ)) * (P : ℤ) = y := by have h₁₂ : (y / (P : ℤ)) * (P : ℤ) = y := by apply Int.ediv_mul_cancel h₁₀ exact h₁₂ linarith have h₁₀ : x = y := by rw [h₈, h₉] rw [h₅] exact h₁₀ exact h₄ lemma ncard_nonneg_multiples_le (B : ℤ) (P : ℕ) (hP : 0 < P) (hB : 0 ≤ B) : ({x : ℤ | 0 ≤ x ∧ x ≤ B ∧ (P : ℤ) ∣ x}).ncard ≤ B.toNat / P + 1 := by have h1 := inj_div_toNat B P hP calc ({x : ℤ | 0 ≤ x ∧ x ≤ B ∧ (P : ℤ) ∣ x}).ncard ≤ (↑(Finset.range (B.toNat / P + 1)) : Set ℕ).ncard := by apply Set.ncard_le_ncard_of_injOn (fun x : ℤ => (x / (P : ℤ)).toNat) (fun a ha => by simp only [Finset.coe_range, Set.mem_Iio] exact div_toNat_mem_range B P hP hB a ha.1 ha.2.1) h1 _ = B.toNat / P + 1 := by rw [Set.ncard_coe_finset, Finset.card_range] lemma nonneg_multiples_finite (B : ℤ) (P : ℕ) : {x : ℤ | 0 ≤ x ∧ x ≤ B ∧ (P : ℤ) ∣ x}.Finite := multiples_finite 0 B P lemma mul_P_mem_set (B : ℤ) (P : ℕ) (_hP : 0 < P) (hB : 0 ≤ B) (k : ℕ) (hk : k ≤ B.toNat / P) : (↑k * ↑P : ℤ) ∈ {x : ℤ | 0 ≤ x ∧ x ≤ B ∧ (P : ℤ) ∣ x} := by have h₁ : 0 ≤ (↑k * ↑P : ℤ) := by nlinarith have h₂ : (↑k * ↑P : ℤ) ≤ B := by have h₃ : (k : ℕ) ≤ B.toNat / P := hk have h₄ : (k : ℕ) * P ≤ (B.toNat / P) * P := by exact Nat.mul_le_mul_right P h₃ have h₅ : (B.toNat / P) * P ≤ B.toNat := by have h₅₁ : (B.toNat / P) * P ≤ B.toNat := by have h₅₂ : (B.toNat / P) * P ≤ B.toNat := Nat.div_mul_le_self B.toNat P exact h₅₂ exact h₅₁ have h₇ : (↑k * ↑P : ℤ) = (↑(k * P) : ℤ) := by norm_cast have h₈ : (↑(k * P) : ℤ) ≤ B := by have h₈₃ : (↑(k * P) : ℤ) ≤ B := by have h₈₅ : (B.toNat : ℤ) ≤ B := by have h₈₆ : 0 ≤ B := hB have h₈₇ : (B.toNat : ℤ) = B := by rw [Int.toNat_of_nonneg h₈₆] linarith linarith exact h₈₃ calc (↑k * ↑P : ℤ) = (↑(k * P) : ℤ) := by rw [h₇] _ ≤ B := h₈ have h₃ : (P : ℤ) ∣ (↑k * ↑P : ℤ) := by use (k : ℤ) ring_nf refine' ⟨h₁, h₂, h₃⟩ lemma ncard_nonneg_multiples_ge (B : ℤ) (P : ℕ) (hP : 0 < P) (hB : 0 ≤ B) : B.toNat / P + 1 ≤ ({x : ℤ | 0 ≤ x ∧ x ≤ B ∧ (P : ℤ) ∣ x}).ncard := by set S := {x : ℤ | 0 ≤ x ∧ x ≤ B ∧ (P : ℤ) ∣ x} set f : ℕ → ℤ := fun k => ↑k * ↑P set R := Finset.range (B.toNat / P + 1) have hfS : ∀ k ∈ R, f k ∈ S := by intro k hk have hk' : k ≤ B.toNat / P := by simp only [R, Finset.mem_range] at hk; omega exact mul_P_mem_set B P hP hB k hk' have hfinj : Set.InjOn f ↑R := by intro a _ b _ hab simp only [f] at hab have hPne : (P : ℤ) ≠ 0 := by positivity have : (a : ℤ) = (b : ℤ) := mul_right_cancel₀ hPne hab exact_mod_cast this calc B.toNat / P + 1 = R.card := (Finset.card_range _).symm _ = (f '' ↑R).ncard := by rw [Set.ncard_image_of_injOn hfinj, Set.ncard_coe_finset] _ ≤ S.ncard := by apply Set.ncard_le_ncard · intro x hx obtain ⟨k, hkR, rfl⟩ := hx exact hfS k hkR · exact nonneg_multiples_finite B P lemma real_sq_div_mono (n : ℕ) (P : ℕ) (θ : ℝ) (hn : 2 ≤ n) (_hP_pos : 0 < P) (hP : (P : ℝ) ≥ (n : ℝ) ^ θ) : (n : ℝ) ^ 2 / (P : ℝ) ≤ (n : ℝ) ^ 2 / (n : ℝ) ^ θ := by have h_n_ge_2 : (n : ℝ) ≥ 2 := by simp_all have h_n_pos : (0 : ℝ) < (n : ℝ) := by nlinarith have h_c_pos : (0 : ℝ) < (n : ℝ) ^ θ := by exact Real.rpow_pos_of_pos h_n_pos θ have h_a_nonneg : (0 : ℝ) ≤ (n : ℝ) ^ 2 := by simp exact div_le_div_of_nonneg_left h_a_nonneg h_c_pos hP lemma truncatedObtuseRegion_subset_box_rb (n : ℕ) (η : ℝ) : truncatedObtuseRegion n η ⊆ (Set.Icc (⌈η * (n : ℝ)⌉ - 1 : ℤ) (⌊(n : ℝ) / 2 - η * (n : ℝ)⌋ : ℤ)) ×ˢ (Set.Icc (⌈η * (n : ℝ)⌉ - 1 : ℤ) (⌊(n : ℝ) / 2 - η * (n : ℝ)⌋ : ℤ)) := by intro ⟨p, q⟩ h simp only [truncatedObtuseRegion, Set.mem_setOf_eq, Set.mem_prod, Set.mem_Icc] at h ⊢ have h₁ : (η * (n : ℝ) : ℝ) ≤ (p : ℝ) := h.1 have h₂ : (η * (n : ℝ) : ℝ) ≤ (q : ℝ) := h.2.1 have h₃ : (p : ℝ) + (q : ℝ) < (n : ℝ) / 2 := h.2.2.1 constructor · have h₅ : (⌈η * (n : ℝ)⌉ : ℝ) - 1 ≤ (p : ℝ) := by have h₅₂ : (⌈η * (n : ℝ)⌉ : ℝ) - 1 ≤ (η * (n : ℝ)) := by linarith [Int.ceil_lt_add_one (η * (n : ℝ))] linarith have h₆ : (p : ℝ) ≤ (⌊(n : ℝ) / 2 - η * (n : ℝ)⌋ : ℝ) := by have h₆₃ : (p : ℝ) < (n : ℝ) / 2 - η * (n : ℝ) := by linarith have h₆₇ : (p : ℝ) ≤ ⌊(n : ℝ) / 2 - η * (n : ℝ)⌋ := by have h₆₈ : (p : ℤ) ≤ ⌊(n : ℝ) / 2 - η * (n : ℝ)⌋ := by apply Int.le_floor.mpr norm_num at h₆₃ ⊢ try norm_cast at h₆₃ ⊢ try simp_all try linarith exact by exact_mod_cast h₆₈ exact_mod_cast h₆₇ have h₇ : (⌈η * (n : ℝ)⌉ - 1 : ℤ) ≤ p := by have h₇₂ : (⌈η * (n : ℝ)⌉ : ℤ) - 1 ≤ p := by have h₇₅ : (⌈η * (n : ℝ)⌉ : ℤ) - 1 ≤ p := by by_contra h₇₆ have h₇₇ : p < (⌈η * (n : ℝ)⌉ : ℤ) - 1 := by linarith have h₇₈ : (p : ℝ) < (⌈η * (n : ℝ)⌉ : ℝ) - 1 := by exact_mod_cast h₇₇ linarith [Int.le_ceil (η * (n : ℝ))] exact h₇₅ exact_mod_cast h₇₂ have h₈ : p ≤ (⌊(n : ℝ) / 2 - η * (n : ℝ)⌋ : ℤ) := by have h₈₁ : (p : ℝ) ≤ (⌊(n : ℝ) / 2 - η * (n : ℝ)⌋ : ℝ) := h₆ have h₈₂ : (p : ℤ) ≤ (⌊(n : ℝ) / 2 - η * (n : ℝ)⌋ : ℤ) := by exact_mod_cast h₈₁ exact h₈₂ exact ⟨h₇, h₈⟩ · have h₅ : (⌈η * (n : ℝ)⌉ : ℝ) - 1 ≤ (q : ℝ) := by have h₅₂ : (⌈η * (n : ℝ)⌉ : ℝ) - 1 ≤ (η * (n : ℝ)) := by linarith [Int.ceil_lt_add_one (η * (n : ℝ))] linarith have h₆ : (q : ℝ) ≤ (⌊(n : ℝ) / 2 - η * (n : ℝ)⌋ : ℝ) := by have h₆₃ : (q : ℝ) < (n : ℝ) / 2 - η * (n : ℝ) := by linarith have h₆₇ : (q : ℝ) ≤ ⌊(n : ℝ) / 2 - η * (n : ℝ)⌋ := by have h₆₈ : (q : ℤ) ≤ ⌊(n : ℝ) / 2 - η * (n : ℝ)⌋ := by apply Int.le_floor.mpr norm_num at h₆₃ ⊢ try norm_cast at h₆₃ ⊢ try simp_all try linarith exact by exact_mod_cast h₆₈ exact_mod_cast h₆₇ have h₇ : (⌈η * (n : ℝ)⌉ - 1 : ℤ) ≤ q := by have h₇₂ : (⌈η * (n : ℝ)⌉ : ℤ) - 1 ≤ q := by have h₇₅ : (⌈η * (n : ℝ)⌉ : ℤ) - 1 ≤ q := by by_contra h₇₆ have h₇₇ : q < (⌈η * (n : ℝ)⌉ : ℤ) - 1 := by linarith have h₇₈ : (q : ℝ) < (⌈η * (n : ℝ)⌉ : ℝ) - 1 := by exact_mod_cast h₇₇ linarith [Int.le_ceil (η * (n : ℝ))] exact h₇₅ exact_mod_cast h₇₂ have h₈ : q ≤ (⌊(n : ℝ) / 2 - η * (n : ℝ)⌋ : ℤ) := by have h₈₁ : (q : ℝ) ≤ (⌊(n : ℝ) / 2 - η * (n : ℝ)⌋ : ℝ) := h₆ have h₈₂ : (q : ℤ) ≤ (⌊(n : ℝ) / 2 - η * (n : ℝ)⌋ : ℤ) := by exact_mod_cast h₈₁ exact h₈₂ exact ⟨h₇, h₈⟩ lemma truncatedObtuseRegion_finite_rb (n : ℕ) (η : ℝ) : (truncatedObtuseRegion n η).Finite := ((Set.finite_Icc _ _).prod (Set.finite_Icc _ _)).subset (truncatedObtuseRegion_subset_box_rb n η) lemma residueBadPairs_finite (n : ℕ) (η : ℝ) : (residueBadPairs n η).Finite := (truncatedObtuseRegion_finite n η).subset (fun pq hpq => by obtain ⟨⟨h1, _⟩, _⟩ := hpq exact h1) set_option linter.unusedSimpArgs false set_option linter.unnecessarySeqFocus false set_option linter.unusedVariables false lemma cast_div_rearrange (n c : ℕ) (hc : 0 < c) : (3 * (n : ℝ) ^ 2) / (4 * (c : ℝ)) ≤ 3 / 4 * (n : ℝ) ^ 2 / (c : ℝ) := by have h_eq : (3 * (n : ℝ) ^ 2) / (4 * (c : ℝ)) = 3 / 4 * (n : ℝ) ^ 2 / (c : ℝ) := by ring have h_le : (3 * (n : ℝ) ^ 2) / (4 * (c : ℝ)) ≤ 3 / 4 * (n : ℝ) ^ 2 / (c : ℝ) := by simp_all assumption lemma largestPrimeFactor_pos_helper (n : ℕ) (hn : 2 ≤ n) : ∃ a : ℕ, n.primeFactors.max = ↑a ∧ 0 < a := by have h₁ : 1 < n := by assumption have h₂ : n.primeFactors.Nonempty := by simp_all have h₃ : ∃ (a : ℕ), n.primeFactors.max = ↑a := by exact Finset.max_of_nonempty h₂ obtain ⟨a, ha⟩ := h₃ have h₄ : a ∈ n.primeFactors := by exact Finset.mem_of_max ha have h₅ : 0 < a := by exact Nat.pos_of_mem_primeFactors h₄ exact ⟨a, ha, h₅⟩ lemma largestPrimeFactor_pos (n : ℕ) (hn : 2 ≤ n) : 0 < largestPrimeFactor n := by obtain ⟨a, ha_max, ha_pos⟩ := largestPrimeFactor_pos_helper n hn simp only [largestPrimeFactor, ha_max] exact ha_pos lemma fiber_empty_of_gcd_ne_one (n : ℕ) (η : ℝ) (q : ℤ) (hq : Int.gcd q (largestPrimeFactor n : ℤ) ≠ 1) : {p : ℤ | (p, q) ∈ residueBadPairs n η} = ∅ := by apply Set.eq_empty_of_forall_notMem intro p hp simp only [Set.mem_setOf_eq, residueBadPairs, badPairsE, Set.mem_setOf_eq] at hp apply hq simp_all lemma snd_lt_half_of_mem_truncatedObtuseRegion_fb (n : ℕ) (η : ℝ) (pq : ℤ × ℤ) (h : pq ∈ truncatedObtuseRegion n η) (hp_pos : 0 < pq.1) : (pq.2 : ℝ) < (n : ℝ) / 2 := by simp only [truncatedObtuseRegion] at h have h₁ : (pq.1 : ℝ) + (pq.2 : ℝ) < (n : ℝ) / 2 := by exact h.2.2.1 have h₂ : 0 < (pq.1 : ℝ) := by exact_mod_cast hp_pos have h₃ : (pq.2 : ℝ) < (n : ℝ) / 2 := by linarith exact h₃ lemma int_le_half_of_real_lt_half_fb (n : ℕ) (q : ℤ) (hq : (q : ℝ) < (n : ℝ) / 2) : q ≤ ↑n / 2 := by have h₂ : (2 : ℝ) * (q : ℝ) < (n : ℝ) := by linarith have h₃ : (2 : ℤ) * q < (n : ℤ) := by norm_cast at h₂ ⊢ have h₅ : q ≤ (n : ℤ) / 2 := by have h₅₂ : q ≤ ((n : ℤ) - 1) / 2 := by have h₅₄ : q ≤ ((n : ℤ) - 1) / 2 := by omega exact h₅₄ have h₅₃ : ((n : ℤ) - 1) / 2 ≤ (n : ℤ) / 2 := by have h₅₄ : ((n : ℤ) - 1) / 2 ≤ (n : ℤ) / 2 := by have h₅₅ : (n : ℤ) % 2 = 0 ∨ (n : ℤ) % 2 = 1 := by omega rcases h₅₅ with (h₅₅ | h₅₅) · have h₅₁₁ : ((n : ℤ) - 1) / 2 ≤ (n : ℤ) / 2 := by omega exact h₅₁₁ · have h₅₁₁ : ((n : ℤ) - 1) / 2 ≤ (n : ℤ) / 2 := by omega exact h₅₁₁ exact h₅₄ have h₅₄ : q ≤ (n : ℤ) / 2 := by linarith exact h₅₄ have h₆ : q ≤ ↑n / 2 := by simpa [Int.ediv_eq_zero_of_lt] using h₅ exact h₆ lemma pos_of_mem_truncatedObtuseRegion_fst_fb (n : ℕ) (η : ℝ) (hη_pos : 0 < η) (pq : ℤ × ℤ) (h : pq ∈ truncatedObtuseRegion n η) : 0 < pq.1 := by have h₁ : η * (n : ℝ) ≤ (pq.1 : ℝ) := h.1 have h₂ : η * (n : ℝ) ≤ (pq.2 : ℝ) := h.2.1 have h₃ : (pq.1 : ℝ) + (pq.2 : ℝ) < (n : ℝ) / 2 := h.2.2.1 by_cases hn : n = 0 · have h₅ : (n : ℝ) = 0 := by norm_cast have h₆ : η * (n : ℝ) = 0 := by rw [h₅]; ring have h₈ : (pq.1 : ℝ) > 0 := by by_contra _ linarith have h₉ : 0 < (pq.1 : ℤ) := by norm_cast at h₈ ⊢ exact h₉ · have h₇ : 0 < η * (n : ℝ) := by positivity have h₉ : (pq.1 : ℝ) > 0 := by linarith have h₁₀ : 0 < (pq.1 : ℤ) := by norm_cast at h₉ ⊢ exact h₁₀ lemma pos_of_mem_truncatedObtuseRegion_snd_fb (n : ℕ) (η : ℝ) (hη_pos : 0 < η) (pq : ℤ × ℤ) (h : pq ∈ truncatedObtuseRegion n η) : 0 < pq.2 := by have h₂ : (η * (n : ℝ) : ℝ) ≤ (pq.2 : ℝ) := by simpa [truncatedObtuseRegion] using h.2.1 have h₃ : (0 : ℝ) < η * (n : ℝ) := by by_cases hn : n = 0 · have h₆ : (n : ℝ) = 0 := by simp [hn] have h₇ : η * (n : ℝ) = 0 := by rw [h₆]; ring have h₉ : (pq.1 : ℝ) + (pq.2 : ℝ) < (n : ℝ) / 2 := by simpa [truncatedObtuseRegion] using h.2.2.1 have h₁₁ : (pq.1 : ℝ) + (pq.2 : ℝ) < 0 := by linarith have h₁₂ : (η * (n : ℝ) : ℝ) ≤ (pq.1 : ℝ) := by simpa [truncatedObtuseRegion] using h.1 linarith · have h₇ : (0 : ℝ) < η * (n : ℝ) := by positivity linarith have h₅ : 0 < pq.2 := by by_contra h₆ have h₇ : pq.2 ≤ 0 := by linarith have h₈ : (pq.2 : ℝ) ≤ 0 := by exact_mod_cast h₇ linarith exact h₅ lemma fiber_subset_range (n : ℕ) (η : ℝ) (hη_pos : 0 < η) (q : ℤ) : {p : ℤ | (p, q) ∈ residueBadPairs n η} ⊆ Set.Ico (0 : ℤ) (↑n / 2) := by intro p hp have hres : (p, q) ∈ residueBadPairs n η := hp have hbad : (p, q) ∈ badPairsE n η := hres.1 have htor : (p, q) ∈ truncatedObtuseRegion n η := hbad.1 have h_eta_p : η * (n : ℝ) ≤ (p : ℝ) := htor.1 have h_eta_q : η * (n : ℝ) ≤ (q : ℝ) := htor.2.1 have h_sum : (p : ℝ) + (q : ℝ) < (n : ℝ) / 2 := htor.2.2.1 have hp_pos : 0 < p := pos_of_mem_truncatedObtuseRegion_fst_fb n η hη_pos (p, q) htor have hq_pos : 0 < q := pos_of_mem_truncatedObtuseRegion_snd_fb n η hη_pos (p, q) htor refine Set.mem_Ico.mpr ⟨le_of_lt hp_pos, ?_⟩ have hq_ge_one : (1 : ℝ) ≤ (q : ℝ) := by exact_mod_cast hq_pos have hp1_lt : ((p + 1 : ℤ) : ℝ) < (n : ℝ) / 2 := by push_cast; linarith have hp1_le : p + 1 ≤ ↑n / 2 := int_le_half_of_real_lt_half_fb n (p + 1) hp1_lt linarith lemma fiber_finite (n : ℕ) (η : ℝ) (hη_pos : 0 < η) (q : ℤ) : {p : ℤ | (p, q) ∈ residueBadPairs n η}.Finite := (Set.finite_Ico (0 : ℤ) (↑n / 2)).subset (fiber_subset_range n η hη_pos q) lemma counting_large_implies_not_badPairsE (n : ℕ) (η : ℝ) (p q : ℤ) (h : (η ^ 2 / 2 : ℝ) * (Nat.totient n : ℝ) ≤ (countingFunctionS n p q : ℝ)) : (p, q) ∉ badPairsE n η := by intro h_in have h₁ : (countingFunctionS n p q : ℝ) < (η ^ 2 / 2 : ℝ) * (Nat.totient n : ℝ) := by simp only [Set.mem_setOf_eq, badPairsE, Set.mem_setOf_eq] at h_in have h₂ := h_in.2.2 exact h₂ have h₃ : ¬((countingFunctionS n p q : ℝ) < (η ^ 2 / 2 : ℝ) * (Nat.totient n : ℝ)) := by intro _ linarith exact h₃ h₁ lemma fiber_div_injOn (n d : ℕ) (hd_pos : 0 < d) (b : ℕ) (S : Set ℤ) (hS_sub : S ⊆ Set.Ico (0 : ℤ) (↑n / 2)) : Set.InjOn (fun x : ℤ => (x / (d : ℤ)).toNat) {x ∈ S | (x % (d : ℤ)).toNat = b} := by intro x hx y hy hxy have hxS : x ∈ S := hx.1 have hx_cond : (x % (d : ℤ)).toNat = b := hx.2 have hyS : y ∈ S := hy.1 have hy_cond : (y % (d : ℤ)).toNat = b := hy.2 have hSx : x ∈ Set.Ico (0 : ℤ) (↑n / 2) := hS_sub hxS have hSy : y ∈ Set.Ico (0 : ℤ) (↑n / 2) := hS_sub hyS have hx0 : 0 ≤ x := by exact hSx.1 have hy0 : 0 ≤ y := by exact hSy.1 have hx_div : (x / (d : ℤ)).toNat = (y / (d : ℤ)).toNat := by simpa using hxy have hx_mod : (x % (d : ℤ)).toNat = (y % (d : ℤ)).toNat := by linarith have hx_mod_inj : x % (d : ℤ) = y % (d : ℤ) := by have h₁ : 0 ≤ (x : ℤ) := by exact_mod_cast hx0 have h₂ : 0 ≤ (y : ℤ) := by exact_mod_cast hy0 have h₃ : 0 < (d : ℤ) := by exact_mod_cast hd_pos have h₄ : (x % (d : ℤ)).toNat = (y % (d : ℤ)).toNat := hx_mod have h₅ : 0 ≤ x % (d : ℤ) := by have h₅₃ : 0 ≤ x % (d : ℤ) := by apply Int.emod_nonneg; omega exact h₅₃ have h₆ : 0 ≤ y % (d : ℤ) := by have h₆₃ : 0 ≤ y % (d : ℤ) := by apply Int.emod_nonneg; omega exact h₆₃ have h₇ : x % (d : ℤ) = y % (d : ℤ) := by have h₇₁ : (x % (d : ℤ)).toNat = (y % (d : ℤ)).toNat := h₄ have h₇₂ : (x % (d : ℤ)).toNat = (y % (d : ℤ)).toNat := h₇₁ have h₇₃ : x % (d : ℤ) = y % (d : ℤ) := by rw [← Int.ofNat_inj] at * simp_all; omega exact h₇₃ exact h₇ have hx_div_inj : x / (d : ℤ) = y / (d : ℤ) := by have h₁ : 0 ≤ (x : ℤ) := by exact_mod_cast hx0 have h₂ : 0 ≤ (y : ℤ) := by exact_mod_cast hy0 have h₃ : 0 < (d : ℤ) := by exact_mod_cast hd_pos have h₄ : (x / (d : ℤ)).toNat = (y / (d : ℤ)).toNat := hx_div have h₅ : 0 ≤ x / (d : ℤ) := by have h₅₁ : 0 ≤ x := hx0 have h₅₃ : 0 ≤ x / (d : ℤ) := by apply Int.ediv_nonneg <;> omega exact h₅₃ have h₆ : 0 ≤ y / (d : ℤ) := by have h₆₁ : 0 ≤ y := hy0 have h₆₃ : 0 ≤ y / (d : ℤ) := by apply Int.ediv_nonneg <;> omega exact h₆₃ have h₇ : x / (d : ℤ) = y / (d : ℤ) := by have h₇₁ : (x / (d : ℤ)).toNat = (y / (d : ℤ)).toNat := hx_div have h₇₂ : (x / (d : ℤ)).toNat = (y / (d : ℤ)).toNat := h₇₁ have h₇₃ : x / (d : ℤ) = y / (d : ℤ) := by rw [← Int.ofNat_inj] at * simp_all [Int.toNat_of_nonneg h₅, Int.toNat_of_nonneg h₆] exact h₇₃ exact h₇ have hxy_eq : x = y := by have h₁ : x / (d : ℤ) = y / (d : ℤ) := hx_div_inj have h₂ : x % (d : ℤ) = y % (d : ℤ) := hx_mod_inj have h₄ : x = y := by have h₅ : x = (d : ℤ) * (x / (d : ℤ)) + (x % (d : ℤ)) := by have h₅₁ : (d : ℤ) * (x / (d : ℤ)) + (x % (d : ℤ)) = x := by have h₅₂ := Int.mul_ediv_add_emod x (d : ℤ) linarith linarith have h₆ : y = (d : ℤ) * (y / (d : ℤ)) + (y % (d : ℤ)) := by have h₆₁ : (d : ℤ) * (y / (d : ℤ)) + (y % (d : ℤ)) = y := by have h₆₂ := Int.mul_ediv_add_emod y (d : ℤ) linarith linarith rw [h₅, h₆] simp [h₁, h₂] exact h₄ exact hxy_eq lemma int_ediv_eq_natCast_div (n : ℤ) (m : ℕ) (_hm : 0 < m) (hn : 0 ≤ n) : n / (m : ℤ) = ↑(n.toNat / m) := by simp_all lemma int_toNat_ediv_eq (n : ℤ) (m : ℕ) (hm : 0 < m) (hn : 0 ≤ n) : (n / (m : ℤ)).toNat = n.toNat / m := by rw [int_ediv_eq_natCast_div n m hm hn, Int.toNat_natCast] lemma int_ediv_toNat_le (a b : ℤ) (m : ℕ) (hm : 0 < m) (ha : 0 ≤ a) (hab : a ≤ b) : (a / (m : ℤ)).toNat ≤ (b / (m : ℤ)).toNat := by have h₁ : ∀ (a : ℤ), 0 ≤ a → (a / (m : ℤ)).toNat = a.toNat / m := by grind have h₄ : a.toNat ≤ b.toNat := by simp_all have h₅ : 0 ≤ b := by nlinarith have h₆ : a.toNat / m ≤ b.toNat / m := by exact Nat.div_le_div_right h₄ have h₇ : (a / (m : ℤ)).toNat ≤ (b / (m : ℤ)).toNat := by simp_all assumption lemma div_toNat_le_half_div (n d : ℕ) (hd_pos : 0 < d) (x : ℤ) (hx0 : 0 ≤ x) (hx_lt : x < (↑n : ℤ) / 2) : (x / (↑d : ℤ)).toNat ≤ n / (2 * d) := by have hx_le : x ≤ (↑n : ℤ) / 2 := le_of_lt hx_lt calc (x / (↑d : ℤ)).toNat ≤ ((↑n : ℤ) / 2 / (↑d : ℤ)).toNat := int_ediv_toNat_le x (↑n / 2) d hd_pos hx0 hx_le _ = ((↑n : ℤ) / 2).toNat / d := int_toNat_ediv_eq (↑n / 2) d hd_pos (Int.ediv_nonneg (Int.natCast_nonneg n) (by norm_num)) _ = n / 2 / d := by have : ((↑n : ℤ) / 2).toNat = n / 2 := int_toNat_ediv_eq (↑n : ℤ) 2 (by norm_num) (Int.natCast_nonneg n) rw [this] _ = n / (2 * d) := Nat.div_div_eq_div_mul n 2 d lemma fiber_div_mem_range (n d : ℕ) (hd_pos : 0 < d) (b : ℕ) (S : Set ℤ) (hS_sub : S ⊆ Set.Ico (0 : ℤ) (↑n / 2)) (x : ℤ) (hx : x ∈ {x ∈ S | (x % (d : ℤ)).toNat = b}) : (x / (d : ℤ)).toNat ∈ Finset.range (n / (2 * d) + 1) := by rw [Finset.mem_range] have hxS : x ∈ S := hx.1 have hxIco := hS_sub hxS rw [Set.mem_Ico] at hxIco exact Nat.lt_add_one_of_le (div_toNat_le_half_div n d hd_pos x hxIco.1 hxIco.2) lemma product_ge_eta_sq_n_sq (η : ℝ) (hη_pos : 0 < η) (n : ℕ) (hn : 2 ≤ n) (p q : ℤ) (hp : η * (n : ℝ) ≤ (p : ℝ)) (hq : η * (n : ℝ) ≤ (q : ℝ)) : (η * (n : ℝ)) ^ 2 ≤ (2 * (p : ℝ) - 1) * (2 * (q : ℝ) - 1) := by have h₂ : 0 < η * (n : ℝ) := by positivity by_cases h₃ : η * (n : ℝ) ≥ 1 · have h₆ : (2 * (p : ℝ) - 1) * (2 * (q : ℝ) - 1) ≥ (η * (n : ℝ)) * (η * (n : ℝ)) := by nlinarith nlinarith · have h₅ : p ≥ 1 := by by_contra h₅₁ have h₅₂ : p ≤ 0 := by linarith have h₅₃ : (p : ℝ) ≤ 0 := by exact_mod_cast h₅₂ linarith have h₆ : q ≥ 1 := by by_contra h₆₁ have h₆₂ : q ≤ 0 := by linarith have h₆₃ : (q : ℝ) ≤ 0 := by exact_mod_cast h₆₂ linarith have h₇ : (p : ℝ) ≥ 1 := by exact_mod_cast h₅ have h₈ : (q : ℝ) ≥ 1 := by exact_mod_cast h₆ have h₁₁ : (2 * (p : ℝ) - 1) * (2 * (q : ℝ) - 1) ≥ 1 := by nlinarith have h₁₂ : (η * (n : ℝ)) ^ 2 < 1 := by nlinarith nlinarith lemma rearrange_ineq (η : ℝ) (n : ℕ) (hn : 2 ≤ n) (p q : ℤ) (h : (η * (n : ℝ)) ^ 2 ≤ (2 * (p : ℝ) - 1) * (2 * (q : ℝ) - 1)) : η ^ 2 * (Nat.totient n : ℝ) ≤ (2 * (p : ℝ) - 1) * (2 * (q : ℝ) - 1) * (Nat.totient n : ℝ) / (n : ℝ) ^ 2 := by have h₂ : 0 < (n : ℝ) ^ 2 := by positivity have h₃ : (η : ℝ) ^ 2 * (n : ℝ) ^ 2 ≤ (2 * (p : ℝ) - 1) * (2 * (q : ℝ) - 1) := by have h₄ : (η * (n : ℝ)) ^ 2 ≤ (2 * (p : ℝ) - 1) * (2 * (q : ℝ) - 1) := h calc (η : ℝ) ^ 2 * (n : ℝ) ^ 2 = (η * (n : ℝ)) ^ 2 := by ring _ ≤ (2 * (p : ℝ) - 1) * (2 * (q : ℝ) - 1) := h₄ have h₄ : (η : ℝ) ^ 2 * (Nat.totient n : ℝ) ≤ (2 * (p : ℝ) - 1) * (2 * (q : ℝ) - 1) * (Nat.totient n : ℝ) / (n : ℝ) ^ 2 := by have h₇ : (η : ℝ) ^ 2 * (Nat.totient n : ℝ) ≤ (2 * (p : ℝ) - 1) * (2 * (q : ℝ) - 1) * (Nat.totient n : ℝ) / (n : ℝ) ^ 2 := by calc (η : ℝ) ^ 2 * (Nat.totient n : ℝ) = ((η : ℝ) ^ 2 * (n : ℝ) ^ 2) * ((Nat.totient n : ℝ) / (n : ℝ) ^ 2) := by field_simp [h₂.ne'] _ ≤ ((2 * (p : ℝ) - 1) * (2 * (q : ℝ) - 1)) * ((Nat.totient n : ℝ) / (n : ℝ) ^ 2) := by gcongr _ = (2 * (p : ℝ) - 1) * (2 * (q : ℝ) - 1) * (Nat.totient n : ℝ) / (n : ℝ) ^ 2 := by ring_nf exact h₇ exact h₄ lemma main_term_lower_bound (η : ℝ) (hη_pos : 0 < η) (n : ℕ) (hn : 2 ≤ n) (p q : ℤ) (hpq : (p, q) ∈ truncatedObtuseRegion n η) : η ^ 2 * (Nat.totient n : ℝ) ≤ (2 * ↑p - 1) * (2 * ↑q - 1) * (Nat.totient n : ℝ) / (n : ℝ) ^ 2 := by obtain ⟨hp, hq, _, _⟩ := hpq exact rearrange_ineq η n hn p q (product_ge_eta_sq_n_sq η hη_pos n hn p q hp hq) noncomputable def intervalIndicator (n : ℕ) (m : ℕ) : ZMod n → ℂ := (intervalSet n m).indicator (fun _ => 1) noncomputable def normalizedDFT (n : ℕ) [NeZero n] (f : ZMod n → ℂ) (k : ZMod n) : ℂ := ((n : ℂ)⁻¹) * ZMod.dft f k noncomputable def ramanujanSum (n : ℕ) [NeZero n] (t : ℤ) : ℂ := ∑ a : (ZMod n)ˣ, ZMod.stdAddChar (a.val * (t : ZMod n)) lemma toNat_two_mul_sub_one (p : ℤ) (hp : 1 ≤ p) : ((2 * p - 1).toNat : ℝ) = 2 * (p : ℝ) - 1 := by have h₁ : 0 ≤ 2 * p - 1 := by omega have h₂ : (2 * p - 1).toNat = 2 * p - 1 := by norm_cast simp_all omega norm_cast at h₂ ⊢ set_option linter.unusedSimpArgs false in lemma indicator_product_eq_ite (n : ℕ) (mp mq : ℕ) (x y : ZMod n) : intervalIndicator n mp x * intervalIndicator n mq y = if (x ∈ intervalSet n mp ∧ y ∈ intervalSet n mq) then (1 : ℂ) else 0 := by have h_main : intervalIndicator n mp x * intervalIndicator n mq y = if (x ∈ intervalSet n mp ∧ y ∈ intervalSet n mq) then (1 : ℂ) else 0 := by dsimp [intervalIndicator] by_cases hx : x ∈ intervalSet n mp · by_cases hy : y ∈ intervalSet n mq · simp [hx, hy, Set.indicator_apply] · simp [hx, hy, Set.indicator_apply] · by_cases hy : y ∈ intervalSet n mq · simp [hx, hy, Set.indicator_apply] · simp [hx, hy, Set.indicator_apply] exact h_main lemma counting_as_indicator_product (n : ℕ) (p q : ℤ) (hn : 2 ≤ n) (_hp : 1 ≤ p) (_hq : 1 ≤ q) (_hpq : (p : ℝ) + (q : ℝ) < (n : ℝ) / 2) : haveI : NeZero n := ⟨by omega⟩ (countingFunctionS n p q : ℂ) = ∑ a : (ZMod n)ˣ, intervalIndicator n (2 * p - 1).toNat (a.val * (p : ZMod n)) * intervalIndicator n (2 * q - 1).toNat (a.val * (q : ZMod n)) := by haveI : NeZero n := ⟨by omega⟩ simp only [countingFunctionS, dif_neg (by omega : ¬n = 0)] rw [← Finset.sum_boole] congr 1 ext a exact (indicator_product_eq_ite n _ _ _ _).symm lemma fourier_inversion (n : ℕ) [NeZero n] (f : ZMod n → ℂ) (x : ZMod n) : f x = ∑ k : ZMod n, normalizedDFT n f k * ZMod.stdAddChar (k * x) := by have h₁ : (ZMod.dft.symm : (ZMod n → ℂ) ≃ₗ[ℂ] (ZMod n → ℂ)) (ZMod.dft f) = f := by apply LinearEquiv.symm_apply_apply have h₂ : (ZMod.dft.symm : (ZMod n → ℂ) ≃ₗ[ℂ] (ZMod n → ℂ)) (ZMod.dft f) = (fun x => (↑(n : ℕ) : ℂ)⁻¹ • (∑ (k : ZMod n), ZMod.stdAddChar (k * x) • (ZMod.dft f) k)) := by ext x simp [ZMod.invDFT_apply] have h₃ : f x = (∑ k : ZMod n, normalizedDFT n f k * ZMod.stdAddChar (k * x)) := by calc f x = (ZMod.dft.symm (ZMod.dft f)) x := by rw [h₁] _ = (↑(n : ℕ) : ℂ)⁻¹ • (∑ (k : ZMod n), ZMod.stdAddChar (k * x) • (ZMod.dft f) k) := by rw [h₂] _ = ∑ (k : ZMod n), ((↑(n : ℕ) : ℂ)⁻¹ • (ZMod.dft f) k) * ZMod.stdAddChar (k * x) := by simp [smul_eq_mul, Finset.mul_sum, mul_comm, mul_left_comm] _ = ∑ (k : ZMod n), normalizedDFT n f k * ZMod.stdAddChar (k * x) := by apply Finset.sum_congr rfl intro k _ simp [normalizedDFT] exact h₃ set_option linter.unusedVariables false in lemma three_sum_comm {α : Type*} {β : Type*} {γ : Type*} {R : Type*} [Fintype α] [Fintype β] [Fintype γ] [AddCommMonoid R] (f : α → β → γ → R) : (∑ a : α, ∑ b : β, ∑ c : γ, f a b c) = (∑ b : β, ∑ c : γ, ∑ a : α, f a b c) := by rw [Finset.sum_comm]; congr 1; ext b; rw [Finset.sum_comm] lemma sum_product_interchange_units (n : ℕ) [NeZero n] (c : ZMod n → ℂ) (d : ZMod n → ℂ) (f : ZMod n → (ZMod n)ˣ → ℂ) (g : ZMod n → (ZMod n)ˣ → ℂ) : (∑ a : (ZMod n)ˣ, (∑ k : ZMod n, c k * f k a) * (∑ l : ZMod n, d l * g l a)) = ∑ k : ZMod n, ∑ l : ZMod n, c k * d l * (∑ a : (ZMod n)ˣ, f k a * g l a) := by simp_rw [Fintype.sum_mul_sum] simp_rw [show ∀ (k : ZMod n) (l : ZMod n) (a : (ZMod n)ˣ), c k * f k a * (d l * g l a) = c k * d l * (f k a * g l a) by intros; ring] rw [three_sum_comm] simp_rw [show ∀ (k : ZMod n) (l : ZMod n), (∑ a : (ZMod n)ˣ, c k * d l * (f k a * g l a)) = c k * d l * (∑ a : (ZMod n)ˣ, f k a * g l a) by intros k l rw [← Finset.mul_sum]] set_option linter.unusedVariables false in lemma interchange_and_factor (n : ℕ) (p q : ℤ) (hn : 2 ≤ n) (_ : 1 ≤ p) (_ : 1 ≤ q) (_ : (p : ℝ) + (q : ℝ) < (n : ℝ) / 2) : haveI : NeZero n := ⟨by omega⟩ (∑ a : (ZMod n)ˣ, intervalIndicator n (2 * p - 1).toNat (a.val * (p : ZMod n)) * intervalIndicator n (2 * q - 1).toNat (a.val * (q : ZMod n)) : ℂ) = ∑ k : ZMod n, ∑ l : ZMod n, normalizedDFT n (intervalIndicator n (2 * p - 1).toNat) k * normalizedDFT n (intervalIndicator n (2 * q - 1).toNat) l * (∑ a : (ZMod n)ˣ, ZMod.stdAddChar (k * (a.val * (p : ZMod n))) * ZMod.stdAddChar (l * (a.val * (q : ZMod n))) : ℂ) := by haveI : NeZero n := ⟨by omega⟩ simp_rw [fourier_inversion n (intervalIndicator n (2 * p - 1).toNat), fourier_inversion n (intervalIndicator n (2 * q - 1).toNat)] exact sum_product_interchange_units n (fun k => normalizedDFT n (intervalIndicator n (2 * p - 1).toNat) k) (fun l => normalizedDFT n (intervalIndicator n (2 * q - 1).toNat) l) (fun k a => ZMod.stdAddChar (k * (a.val * (p : ZMod n)))) (fun l a => ZMod.stdAddChar (l * (a.val * (q : ZMod n)))) set_option linter.unusedSimpArgs false in lemma character_product_simplify (n : ℕ) [NeZero n] (k l : ZMod n) (p q : ℤ) : (∑ a : (ZMod n)ˣ, ZMod.stdAddChar (k * (a.val * (p : ZMod n))) * ZMod.stdAddChar (l * (a.val * (q : ZMod n))) : ℂ) = ramanujanSum n (ZMod.val k * p + ZMod.val l * q) := by have h₁ : (∑ a : (ZMod n)ˣ, ZMod.stdAddChar (k * (a.val * (p : ZMod n))) * ZMod.stdAddChar (l * (a.val * (q : ZMod n))) : ℂ) = (∑ a : (ZMod n)ˣ, ZMod.stdAddChar ( (k * (a.val * (p : ZMod n)) + l * (a.val * (q : ZMod n)) : ZMod n) ) : ℂ) := by congr 1; ext a; exact (ZMod.stdAddChar.map_add_eq_mul _ _).symm have h₂ : (∑ a : (ZMod n)ˣ, ZMod.stdAddChar ( (k * (a.val * (p : ZMod n)) + l * (a.val * (q : ZMod n)) : ZMod n) ) : ℂ) = (∑ a : (ZMod n)ˣ, ZMod.stdAddChar ( ( (a : ZMod n) * (k * (p : ZMod n) + l * (q : ZMod n)) : ZMod n) ) : ℂ) := by group have h₃ : (∑ a : (ZMod n)ˣ, ZMod.stdAddChar ( ( (a : ZMod n) * (k * (p : ZMod n) + l * (q : ZMod n)) : ZMod n) ) : ℂ) = (∑ a : (ZMod n)ˣ, ZMod.stdAddChar ( ( (a.val : ZMod n) * (k * (p : ZMod n) + l * (q : ZMod n)) : ZMod n) ) : ℂ) := by rfl have h₄ : (∑ a : (ZMod n)ˣ, ZMod.stdAddChar ( ( (a.val : ZMod n) * (k * (p : ZMod n) + l * (q : ZMod n)) : ZMod n) ) : ℂ) = (∑ a : (ZMod n)ˣ, ZMod.stdAddChar ( (a.val * ( (ZMod.val k * p + ZMod.val l * q : ℤ) : ZMod n)) : ZMod n) ) := by simp have h₅ : (∑ a : (ZMod n)ˣ, ZMod.stdAddChar ( (a.val * ( (ZMod.val k * p + ZMod.val l * q : ℤ) : ZMod n)) : ZMod n) ) = ramanujanSum n (ZMod.val k * p + ZMod.val l * q) := by rfl calc (∑ a : (ZMod n)ˣ, ZMod.stdAddChar (k * (a.val * (p : ZMod n))) * ZMod.stdAddChar (l * (a.val * (q : ZMod n))) : ℂ) = (∑ a : (ZMod n)ˣ, ZMod.stdAddChar ( (k * (a.val * (p : ZMod n)) + l * (a.val * (q : ZMod n)) : ZMod n) ) : ℂ) := by rw [h₁] _ = (∑ a : (ZMod n)ˣ, ZMod.stdAddChar ( ( (a : ZMod n) * (k * (p : ZMod n) + l * (q : ZMod n)) : ZMod n) ) : ℂ) := by rw [h₂] _ = (∑ a : (ZMod n)ˣ, ZMod.stdAddChar ( ( (a.val : ZMod n) * (k * (p : ZMod n) + l * (q : ZMod n)) : ZMod n) ) : ℂ) := by rw [h₃] _ = (∑ a : (ZMod n)ˣ, ZMod.stdAddChar ( (a.val * ( (ZMod.val k * p + ZMod.val l * q : ℤ) : ZMod n)) : ZMod n) ) := by rw [h₄] _ = ramanujanSum n (ZMod.val k * p + ZMod.val l * q) := by rw [h₅] lemma counting_eq_fourier_ramanujan_sum (n : ℕ) (hn : 2 ≤ n) (p q : ℤ) (hp : 1 ≤ p) (hq : 1 ≤ q) (hpq : (p : ℝ) + (q : ℝ) < (n : ℝ) / 2) : haveI : NeZero n := ⟨by omega⟩ (countingFunctionS n p q : ℂ) = ∑ k : ZMod n, ∑ l : ZMod n, normalizedDFT n (intervalIndicator n (2 * p - 1).toNat) k * normalizedDFT n (intervalIndicator n (2 * q - 1).toNat) l * ramanujanSum n (ZMod.val k * p + ZMod.val l * q) := by haveI : NeZero n := ⟨by omega⟩ rw [counting_as_indicator_product n p q hn hp hq hpq] rw [interchange_and_factor n p q hn hp hq hpq] simp_rw [character_product_simplify n] lemma largestPrimeFactor_pos_helper_fb (n : ℕ) (hn : 2 ≤ n) : ∃ a : ℕ, n.primeFactors.max = ↑a ∧ 0 < a := by have h₁ : 1 < n := by omega have h₂ : n.primeFactors.Nonempty := Nat.nonempty_primeFactors.mpr h₁ obtain ⟨a, ha⟩ := Finset.max_of_nonempty h₂ exact ⟨a, ha, Nat.pos_of_mem_primeFactors (Finset.mem_of_max ha)⟩ lemma largestPrimeFactor_ge_two (n : ℕ) (hn : 2 ≤ n) : 2 ≤ largestPrimeFactor n := by obtain ⟨a, ha_max, _ha_pos⟩ := largestPrimeFactor_pos_helper_fb n hn have ha_mem : a ∈ n.primeFactors := Finset.mem_of_max ha_max have ha_prime : Nat.Prime a := Nat.prime_of_mem_primeFactors ha_mem have ha_two_le : 2 ≤ a := ha_prime.two_le show 2 ≤ largestPrimeFactor n unfold largestPrimeFactor rw [ha_max] exact ha_two_le lemma ceil_log_ge_one (n : ℕ) (hn : 2 ≤ n) : 1 ≤ ⌈Real.log (n : ℝ)⌉₊ := by have h₁ : (1 : ℝ) < (n : ℝ) := by norm_cast have h₂ : 0 < Real.log (n : ℝ) := Real.log_pos h₁ have h₃ : 1 ≤ ⌈Real.log (n : ℝ)⌉₊ := by have h₅ : 1 ≤ ⌈Real.log (n : ℝ)⌉₊ := by by_contra h have h₆ : ⌈Real.log (n : ℝ)⌉₊ = 0 := by have h₉ : ⌈Real.log (n : ℝ)⌉₊ = 0 := by omega exact h₉ have h₁₀ : (⌈Real.log (n : ℝ)⌉₊ : ℝ) = 0 := by norm_cast have h₁₁ : Real.log (n : ℝ) ≤ 0 := by have h₁₂ : Real.log (n : ℝ) ≤ ⌈Real.log (n : ℝ)⌉₊ := Nat.le_ceil _ linarith linarith exact h₅ exact h₃ lemma bound_first_term (P R A : ℝ) (hP : 2 ≤ P) (hR : 1 ≤ R) (hA : 0 ≤ A) : A / (P - 1) ≤ 2 * R * A / P := by have hP0 : (0 : ℝ) < P := by linarith have hP1 : (0 : ℝ) < P - 1 := by linarith rw [div_le_div_iff₀ hP1 hP0] nlinarith [mul_nonneg hA (by linarith : (0 : ℝ) ≤ P - 1), mul_nonneg hA (by linarith : (0 : ℝ) ≤ R - 1), mul_nonneg (by linarith : (0 : ℝ) ≤ R - 1) (mul_nonneg hA (by linarith : (0 : ℝ) ≤ P - 1))] lemma combine_error_terms_real (P R A : ℝ) (hP : 2 ≤ P) (hR : 1 ≤ R) (hA : 0 ≤ A) : A / (P - 1) + 7 * R * A / P ≤ 9 * R * A / P := by have hP0 : (0 : ℝ) < P := by linarith have h := bound_first_term P R A hP hR hA have h2 : 2 * R * A / P + 7 * R * A / P = 9 * R * A / P := by ring linarith noncomputable def errorTermEP0 (n : ℕ) [NeZero n] (p q : ℤ) : ℂ := let P := largestPrimeFactor n let alpha := n.factorization P let P0 := P ^ (alpha - 1) let d := P ^ alpha let fp := intervalIndicator n (2 * p - 1).toNat let fq := intervalIndicator n (2 * q - 1).toNat ∑ k : ZMod n, ∑ l : ZMod n, if (k, l) ≠ (0, 0) ∧ (P0 : ℤ) ∣ (ZMod.val k * p + ZMod.val l * q) ∧ ¬((d : ℤ) ∣ (ZMod.val k * p + ZMod.val l * q)) then normalizedDFT n fp k * normalizedDFT n fq l * ramanujanSum n (ZMod.val k * p + ZMod.val l * q) else 0 noncomputable def errorTermEPalpha (n : ℕ) [NeZero n] (p q : ℤ) : ℂ := let P := largestPrimeFactor n let alpha := n.factorization P let d := P ^ alpha let fp := intervalIndicator n (2 * p - 1).toNat let fq := intervalIndicator n (2 * q - 1).toNat ∑ k : ZMod n, ∑ l : ZMod n, if (k, l) ≠ (0, 0) ∧ (d : ℤ) ∣ (ZMod.val k * p + ZMod.val l * q) then normalizedDFT n fp k * normalizedDFT n fq l * ramanujanSum n (ZMod.val k * p + ZMod.val l * q) else 0 set_option linter.unusedVariables false set_option linter.unnecessarySeqFocus false set_option linter.unusedSimpArgs false set_option linter.unnecessarySimpa false lemma zmod_mul_as_cast (n : ℕ) [NeZero n] (k : ZMod n) (p : ℤ) : k * (p : ZMod n) = ((ZMod.val k * p : ℤ) : ZMod n) := by have h₅ : (k : ZMod n) * (p : ZMod n) = ((ZMod.val k * p : ℤ) : ZMod n) := by simp assumption lemma factor_and_combine_chars (n : ℕ) [NeZero n] (k l : ZMod n) (a : (ZMod n)ˣ) (p q : ℤ) : ZMod.stdAddChar (k * (a.val * (p : ZMod n))) * ZMod.stdAddChar (l * (a.val * (q : ZMod n))) = ZMod.stdAddChar (a.val * (k * (p : ZMod n) + l * (q : ZMod n))) := by have h_main : (k * (a.val * (p : ZMod n)) + l * (a.val * (q : ZMod n)) : ZMod n) = (a.val * (k * (p : ZMod n) + l * (q : ZMod n)) : ZMod n) := by ring have h_char_prod : ZMod.stdAddChar (k * (a.val * (p : ZMod n))) * ZMod.stdAddChar (l * (a.val * (q : ZMod n))) = ZMod.stdAddChar (k * (a.val * (p : ZMod n)) + l * (a.val * (q : ZMod n))) := by exact (ZMod.stdAddChar.map_add_eq_mul _ _).symm have h_final : ZMod.stdAddChar (k * (a.val * (p : ZMod n))) * ZMod.stdAddChar (l * (a.val * (q : ZMod n))) = ZMod.stdAddChar (a.val * (k * (p : ZMod n) + l * (q : ZMod n))) := by simp_all assumption lemma ramanujanSum_zero (n : ℕ) [NeZero n] : ramanujanSum n 0 = (Nat.totient n : ℂ) := by have h1 : ramanujanSum n 0 = ∑ _ : (ZMod n)ˣ, (1 : ℂ) := by calc ramanujanSum n 0 = ∑ a : (ZMod n)ˣ, ZMod.stdAddChar (a.val * (0 : ZMod n)) := by simp [ramanujanSum] _ = ∑ _ : (ZMod n)ˣ, (1 : ℂ) := by apply Finset.sum_congr rfl intro a _ have h₂ : (a.val : ZMod n) * (0 : ZMod n) = 0 := by simp [mul_zero] have h₃ : ZMod.stdAddChar (a.val * (0 : ZMod n)) = (1 : ℂ) := by rw [h₂] simp [ZMod.stdAddChar] rw [h₃] have h2 : (∑ _ : (ZMod n)ˣ, (1 : ℂ)) = (Fintype.card (ZMod n)ˣ : ℂ) := by simp [Finset.sum_const, nsmul_eq_mul] have h3 : (Fintype.card (ZMod n)ˣ : ℂ) = (Nat.totient n : ℂ) := by have h₄ : Fintype.card (ZMod n)ˣ = Nat.totient n := by apply ZMod.card_units_eq_totient rw [h₄] calc ramanujanSum n 0 = ∑ _ : (ZMod n)ˣ, (1 : ℂ) := h1 _ = (Fintype.card (ZMod n)ˣ : ℂ) := h2 _ = (Nat.totient n : ℂ) := h3 lemma card_intervalSet_filter (n : ℕ) [NeZero n] (m : ℕ) (hm2 : m < n) : (Finset.univ.filter (fun j : ZMod n => 1 ≤ ZMod.val j ∧ ZMod.val j ≤ m)).card = m := by have h := Finset.card_bij' (i := fun (t : ℕ) (_ : t ∈ Finset.Icc 1 m) => (t : ZMod n)) (j := fun (j : ZMod n) (_ : j ∈ Finset.univ.filter (fun j : ZMod n => 1 ≤ ZMod.val j ∧ ZMod.val j ≤ m)) => ZMod.val j) (hi := fun t ht => by simp only [Finset.mem_filter, Finset.mem_univ, true_and] have htm := Finset.mem_Icc.mp ht constructor · rw [ZMod.val_natCast_of_lt (by omega)] exact htm.1 · rw [ZMod.val_natCast_of_lt (by omega)] exact htm.2) (hj := fun j hj => by simp only [Finset.mem_filter, Finset.mem_univ, true_and] at hj exact Finset.mem_Icc.mpr hj) (left_inv := fun t ht => by have htm := Finset.mem_Icc.mp ht exact ZMod.val_natCast_of_lt (by omega)) (right_inv := fun j _ => ZMod.natCast_zmod_val j) rw [Nat.card_Icc] at h omega lemma sum_intervalIndicator_eq (n : ℕ) [NeZero n] (m : ℕ) (_hm1 : 1 ≤ m) (hm2 : m < n) : ∑ x : ZMod n, intervalIndicator n m x = (m : ℂ) := by simp only [intervalIndicator, intervalSet, Set.indicator_apply, Set.mem_setOf_eq, Finset.sum_boole] exact_mod_cast card_intervalSet_filter n m hm2 lemma normalizedDFT_intervalIndicator_zero (n : ℕ) [NeZero n] (m : ℕ) (hm1 : 1 ≤ m) (hm2 : m < n) : normalizedDFT n (intervalIndicator n m) 0 = (m : ℂ) / (n : ℂ) := by simp only [normalizedDFT, ZMod.dft_apply_zero] rw [sum_intervalIndicator_eq n m hm1 hm2] ring lemma mp_lower_bound (p : ℤ) (hp : 1 ≤ p) : 1 ≤ (2 * p - 1).toNat := by have h₃ : 1 ≤ (2 * p - 1).toNat := by have h₇ : (2 * p - 1).toNat ≥ 1 := by have h₉ : (2 * p - 1).toNat ≥ 1 := by have h₁₂ : (2 * p - 1).toNat ≥ 1 := by have h₁₃ : (2 * p - 1 : ℤ) ≥ 1 := by linarith have h₁₄ : (2 * p - 1).toNat ≥ 1 := by norm_cast at h₁₃ ⊢ <;> omega exact h₁₄ exact h₁₂ exact h₉ exact h₇ exact h₃ lemma mp_upper_bound (n : ℕ) (hn : 2 ≤ n) (p q : ℤ) (hp : 1 ≤ p) (hq : 1 ≤ q) (hpq : (p : ℝ) + (q : ℝ) < (n : ℝ) / 2) : (2 * p - 1).toNat < n := by have h₁ : 2 * p - 1 < n := by have h₃ : (q : ℝ) ≥ 1 := by exact_mod_cast hq have h₉ : (2 : ℝ) * (p : ℝ) - 1 < (n : ℝ) := by linarith have h₁₀ : (2 : ℤ) * p - 1 < (n : ℤ) := by have h₁₀₁ : (2 : ℝ) * (p : ℝ) - 1 < (n : ℝ) := h₉ have h₁₀₂ : (2 : ℝ) * (p : ℝ) - 1 = ((2 : ℤ) * p - 1 : ℝ) := by norm_cast have h₁₀₃ : ((2 : ℤ) * p - 1 : ℝ) < (n : ℝ) := by rw [h₁₀₂] at h₁₀₁ exact h₁₀₁ have h₁₀₄ : ((2 : ℤ) * p - 1 : ℤ) < (n : ℤ) := by norm_cast at h₁₀₃ ⊢ exact_mod_cast h₁₀₄ exact_mod_cast h₁₀ have h₃ : (2 * p - 1).toNat < n := by have h₄ : (2 * p - 1 : ℤ) < n := by exact_mod_cast h₁ have h₆ : (2 * p - 1).toNat < n := by rw [Int.toNat_lt (by linarith)] <;> norm_cast at h₄ ⊢ exact h₆ exact h₃ lemma mp_valid (n : ℕ) (hn : 2 ≤ n) (p q : ℤ) (hp : 1 ≤ p) (hq : 1 ≤ q) (hpq : (p : ℝ) + (q : ℝ) < (n : ℝ) / 2) : 1 ≤ (2 * p - 1).toNat ∧ (2 * p - 1).toNat < n := by exact ⟨mp_lower_bound p hp, mp_upper_bound n hn p q hp hq hpq⟩ lemma mq_valid (n : ℕ) (hn : 2 ≤ n) (p q : ℤ) (hp : 1 ≤ p) (hq : 1 ≤ q) (hpq : (p : ℝ) + (q : ℝ) < (n : ℝ) / 2) : 1 ≤ (2 * q - 1).toNat ∧ (2 * q - 1).toNat < n := by have h₁ : (2 * q - 1 : ℤ) ≥ 1 := by have : (q : ℤ) ≥ 1 := by exact_mod_cast hq linarith have h₂ : (2 * q - 1 : ℤ) < (n : ℤ) := by have h₄ : (q : ℝ) < (n : ℝ) / 2 := by have : (p : ℝ) ≥ 1 := by exact_mod_cast hp linarith have h₅ : (q : ℝ) * 2 < (n : ℝ) := by linarith have h₆ : (q : ℤ) * 2 < (n : ℤ) := by norm_cast at h₅ ⊢ have h₇ : (2 * q - 1 : ℤ) < (n : ℤ) := by have : (2 : ℤ) * q = q * 2 := by ring rw [this] at * linarith exact h₇ have h₃ : 1 ≤ (2 * q - 1).toNat := by have h₆ : (2 * q - 1).toNat = (2 * q - 1 : ℤ).toNat := rfl rw [h₆] norm_cast <;> (try omega) have h₄ : (2 * q - 1).toNat < n := by have h₆ : (2 * q - 1 : ℤ) ≥ 0 := by have : (2 * q - 1 : ℤ) ≥ 1 := h₁ linarith have h₇ : (2 * q - 1).toNat = (2 * q - 1 : ℤ).toNat := rfl rw [h₇] have h₈ : ((2 * q - 1 : ℤ).toNat : ℤ) = (2 * q - 1 : ℤ) := by rw [Int.toNat_of_nonneg h₆] have h₉ : ((2 * q - 1 : ℤ).toNat : ℤ) < (n : ℤ) := by linarith norm_cast at h₉ ⊢ exact ⟨h₃, h₄⟩ lemma zero_zero_term_eq_main (n : ℕ) [NeZero n] (hn : 2 ≤ n) (p q : ℤ) (hp : 1 ≤ p) (hq : 1 ≤ q) (hpq : (p : ℝ) + (q : ℝ) < (n : ℝ) / 2) : normalizedDFT n (intervalIndicator n (2 * p - 1).toNat) 0 * normalizedDFT n (intervalIndicator n (2 * q - 1).toNat) 0 * ramanujanSum n (↑(ZMod.val (0 : ZMod n)) * p + ↑(ZMod.val (0 : ZMod n)) * q) = ((2 * p - 1).toNat : ℂ) * ((2 * q - 1).toNat : ℂ) * (Nat.totient n : ℂ) / (n : ℂ) ^ 2 := by have hmp := mp_valid n hn p q hp hq hpq have hmq := mq_valid n hn p q hp hq hpq simp only [ZMod.val_zero, Nat.cast_zero, zero_mul, zero_add] rw [ramanujanSum_zero] rw [normalizedDFT_intervalIndicator_zero n _ hmp.1 hmp.2] rw [normalizedDFT_intervalIndicator_zero n _ hmq.1 hmq.2] have hn_ne : (n : ℂ) ≠ 0 := Nat.cast_ne_zero.mpr (by omega) field_simp lemma full_sum_split_zero_nonzero (n : ℕ) [NeZero n] (F : ZMod n → ZMod n → ℂ) : ∑ k : ZMod n, ∑ l : ZMod n, F k l = F 0 0 + ∑ k : ZMod n, ∑ l : ZMod n, if ¬(k = 0 ∧ l = 0) then F k l else 0 := by have h₁ : (∑ k : ZMod n, ∑ l : ZMod n, F k l) = F 0 0 + ∑ k : ZMod n, ∑ l : ZMod n, if (¬(k = 0 ∧ l = 0)) then F k l else 0 := by calc (∑ k : ZMod n, ∑ l : ZMod n, F k l) = ∑ k : ZMod n, ∑ l : ZMod n, (if (k = 0 ∧ l = 0) then F k l else F k l) := by apply Finset.sum_congr rfl intro k _ apply Finset.sum_congr rfl intro l _ by_cases h : k = 0 ∧ l = 0 <;> simp [h] _ = ∑ k : ZMod n, ∑ l : ZMod n, ((if (k = 0 ∧ l = 0) then (F 0 0) else 0) + (if (¬(k = 0 ∧ l = 0)) then F k l else 0)) := by apply Finset.sum_congr rfl intro k _ apply Finset.sum_congr rfl intro l _ by_cases h : k = 0 ∧ l = 0 <;> simp [h] _ = ∑ k : ZMod n, ∑ l : ZMod n, ((if (k = 0 ∧ l = 0) then (F 0 0) else 0) + (if (¬(k = 0 ∧ l = 0)) then F k l else 0)) := by rfl _ = (∑ k : ZMod n, ∑ l : ZMod n, (if (k = 0 ∧ l = 0) then (F 0 0) else 0)) + ∑ k : ZMod n, ∑ l : ZMod n, (if (¬(k = 0 ∧ l = 0)) then F k l else 0) := by have h₂ : (∑ k : ZMod n, ∑ l : ZMod n, ((if (k = 0 ∧ l = 0) then (F 0 0) else 0) + (if (¬(k = 0 ∧ l = 0)) then F k l else 0))) = (∑ k : ZMod n, ∑ l : ZMod n, (if (k = 0 ∧ l = 0) then (F 0 0) else 0)) + ∑ k : ZMod n, ∑ l : ZMod n, (if (¬(k = 0 ∧ l = 0)) then F k l else 0) := by simp [Finset.sum_add_distrib] rw [h₂] _ = F 0 0 + ∑ k : ZMod n, ∑ l : ZMod n, (if (¬(k = 0 ∧ l = 0)) then F k l else 0) := by have h₃ : (∑ k : ZMod n, ∑ l : ZMod n, (if (k = 0 ∧ l = 0) then (F 0 0) else 0)) = F 0 0 := by calc (∑ k : ZMod n, ∑ l : ZMod n, (if (k = 0 ∧ l = 0) then (F 0 0) else 0)) = ∑ k : ZMod n, ∑ l : ZMod n, if (k = 0 ∧ l = 0) then (F 0 0) else 0 := by rfl _ = F 0 0 := by calc (∑ k : ZMod n, ∑ l : ZMod n, if (k = 0 ∧ l = 0) then (F 0 0) else 0) = ∑ k : ZMod n, (∑ l : ZMod n, if (k = 0 ∧ l = 0) then (F 0 0) else 0) := by simp [Finset.sum_sigma'] _ = ∑ k : ZMod n, if (k = 0) then (F 0 0) else 0 := by apply Finset.sum_congr rfl intro k _ calc (∑ l : ZMod n, if (k = 0 ∧ l = 0) then (F 0 0) else 0) = ∑ l : ZMod n, if (k = 0 ∧ l = 0) then (F 0 0) else 0 := by rfl _ = if (k = 0) then (F 0 0) else 0 := by by_cases hk : k = 0 · simp [hk] · simp [hk] _ = F 0 0 := by calc (∑ k : ZMod n, if (k = 0) then (F 0 0) else 0) = ∑ k : ZMod n, if (k = 0) then (F 0 0) else 0 := by rfl _ = F 0 0 := by calc (∑ k : ZMod n, if (k = 0) then (F 0 0) else 0) = ∑ k : ZMod n, if (k = 0) then (F 0 0) else 0 := by rfl _ = F 0 0 := by have h₄ : (∑ k : ZMod n, if (k = 0) then (F 0 0) else 0) = F 0 0 := by calc (∑ k : ZMod n, if (k = 0) then (F 0 0) else 0) = ∑ k : ZMod n, if (k = 0) then (F 0 0) else 0 := by rfl _ = F 0 0 := by have h₅ : (∑ k : ZMod n, if (k = 0) then (F 0 0) else 0) = F 0 0 := by calc (∑ k : ZMod n, if (k = 0) then (F 0 0) else 0) = (if ((0 : ZMod n) = 0) then (F 0 0) else 0) := by have h₆ : (∑ k : ZMod n, if (k = 0) then (F 0 0) else 0) = (if ((0 : ZMod n) = 0) then (F 0 0) else 0) := by simp [Finset.sum_ite, Finset.filter_eq'] rw [h₆] _ = F 0 0 := by simp rw [h₅] rw [h₄] rw [h₃] rw [h₁] lemma sum_stdAddChar_mul_eq (n : ℕ) [NeZero n] (t : ℤ) : ∑ a : ZMod n, ZMod.stdAddChar (a * (t : ZMod n)) = if (n : ℤ) ∣ t then (n : ℂ) else 0 := by have h1 : ∑ a : ZMod n, ZMod.stdAddChar (a * (t : ZMod n)) = ∑ a : ZMod n, ZMod.stdAddChar (a * (t : ZMod n)) := rfl rw [h1] have h2 : ∑ a : ZMod n, ZMod.stdAddChar (a * (t : ZMod n)) = (if (t : ZMod n) = 0 then (n : ℂ) else 0) := by have h3 : ∑ a : ZMod n, ZMod.stdAddChar (a * (t : ZMod n)) = (if (t : ZMod n) = 0 then (n : ℂ) else 0) := by have h4 : ∑ a : ZMod n, ZMod.stdAddChar (a * (t : ZMod n)) = (if (t : ZMod n) = 0 then (n : ℂ) else 0) := by have h5 : ∑ a : ZMod n, ZMod.stdAddChar (a * (t : ZMod n)) = ∑ a : ZMod n, ZMod.stdAddChar (a * (t : ZMod n)) := rfl rw [h5] have h7 : ∑ a : ZMod n, ZMod.stdAddChar (a * (t : ZMod n)) = (if (t : ZMod n) = 0 then (n : ℂ) else 0) := by have h8 : ∑ a : ZMod n, ZMod.stdAddChar (a * (t : ZMod n)) = (if (t : ZMod n) = 0 then (Fintype.card (ZMod n) : ℂ) else 0) := by have h9 : ∑ a : ZMod n, ZMod.stdAddChar (a * (t : ZMod n)) = (if (t : ZMod n) = 0 then (Fintype.card (ZMod n) : ℂ) else 0) := by simp_all [AddChar.sum_mulShift, ZMod.isPrimitive_stdAddChar, Fintype.card_fin] exact h9 have h10 : (Fintype.card (ZMod n) : ℂ) = (n : ℂ) := by simp [ZMod.card] rw [h8] simp_all [h10] exact h7 exact h4 exact h3 rw [h2] have h3 : (t : ZMod n) = 0 ↔ (n : ℤ) ∣ t := by constructor · intro h have h4 : (t : ZMod n) = 0 := h have h5 : (n : ℤ) ∣ t := by have h6 : (t : ZMod n) = 0 := h4 have h7 : (t : ZMod n) = 0 := h6 rw [ZMod.intCast_zmod_eq_zero_iff_dvd] at h7 <;> simpa using h7 exact h5 · intro h have h4 : (n : ℤ) ∣ t := h have h5 : (t : ZMod n) = 0 := by have h6 : (n : ℤ) ∣ t := h4 have h7 : (t : ZMod n) = 0 := by rw [ZMod.intCast_zmod_eq_zero_iff_dvd] <;> simpa using h6 exact h7 exact h5 split_ifs at * <;> simp_all [h3] lemma sum_filter_units_eq_sum_units (n : ℕ) [NeZero n] (f : ZMod n → ℂ) : ∑ a ∈ Finset.univ.filter (fun a : ZMod n => IsUnit a), f a = ∑ u : (ZMod n)ˣ, f u.val := by rw [← Finset.sum_subtype_eq_sum_filter, Finset.subtype_univ] exact Fintype.sum_equiv { toFun := fun x => x.prop.unit invFun := fun u => ⟨u.val, Units.isUnit u⟩ left_inv := fun x => by ext; exact IsUnit.unit_spec x.prop right_inv := fun u => IsUnit.unit_of_val_units (Units.isUnit u) } _ _ (fun x => by simp) lemma sum_eq_ramanujanSum_add_sum_nonunits (n : ℕ) [NeZero n] (t : ℤ) : (∑ a : ZMod n, ZMod.stdAddChar (a * (t : ZMod n))) = ramanujanSum n t + ∑ a ∈ Finset.univ.filter (fun a : ZMod n => ¬ IsUnit a), ZMod.stdAddChar (a * (t : ZMod n)) := by rw [← Finset.sum_filter_add_sum_filter_not Finset.univ (fun a : ZMod n => IsUnit a) (fun a => ZMod.stdAddChar (a * (t : ZMod n))), show ∑ a ∈ Finset.univ.filter (fun a : ZMod n => IsUnit a), ZMod.stdAddChar (a * (t : ZMod n)) = ramanujanSum n t from sum_filter_units_eq_sum_units n _] lemma p_mul_pow_pred {p k : ℕ} (hk : 0 < k) : p * p ^ (k - 1) = p ^ k := by cases k with | zero => omega | succ n => simp [pow_succ, mul_comm] noncomputable def nonunitFwd {p k : ℕ} (b : ZMod (p ^ (k - 1))) : ZMod (p ^ k) := (p : ZMod (p ^ k)) * (b.val : ZMod (p ^ k)) noncomputable def nonunitBwd {p k : ℕ} (a : ZMod (p ^ k)) : ZMod (p ^ (k - 1)) := (a.val / p : ℕ) lemma val_nonunitFwd {p : ℕ} [hp : Fact (Nat.Prime p)] {k : ℕ} (hk : 0 < k) (b : ZMod (p ^ (k - 1))) : (nonunitFwd (p := p) (k := k) b).val = p * b.val := by unfold nonunitFwd rw [ZMod.val_mul, ZMod.val_natCast, ZMod.val_natCast, ← Nat.mul_mod, Nat.mod_eq_of_lt] nlinarith [ZMod.val_lt b, hp.out.pos, p_mul_pow_pred hk (p := p)] lemma nonunitFwd_not_isUnit {p : ℕ} [hp : Fact (Nat.Prime p)] {k : ℕ} (hk : 0 < k) (b : ZMod (p ^ (k - 1))) : ¬ IsUnit (nonunitFwd b) := by intro ⟨u, hu⟩ have hcop := ZMod.val_coe_unit_coprime u rw [hu, val_nonunitFwd hk b] at hcop exact (hp.out.coprime_iff_not_dvd.mp (hcop.of_dvd_left (dvd_mul_right p b.val))) (dvd_pow_self p (by omega)) lemma nonunitBwd_nonunitFwd {p : ℕ} [hp : Fact (Nat.Prime p)] {k : ℕ} (hk : 0 < k) (b : ZMod (p ^ (k - 1))) : nonunitBwd (nonunitFwd (p := p) (k := k) b) = b := by simp [nonunitBwd, val_nonunitFwd hk b, Nat.mul_div_cancel_left _ hp.out.pos, ZMod.natCast_val, ZMod.cast_id] lemma p_dvd_val_of_not_isUnit {p : ℕ} [hp : Fact (Nat.Prime p)] {k : ℕ} (a : ZMod (p ^ k)) (ha : ¬ IsUnit a) : p ∣ a.val := by by_contra h haveI := Fact.mk hp.1 have h₁ : IsUnit (a : ZMod (p ^ k)) ↔ Nat.Coprime a.val (p ^ k) := by simpa [← ZMod.isUnit_iff_coprime] using ZMod.isUnit_iff_coprime a have h₂ : ¬Nat.Coprime a.val (p ^ k) := by intro h₃ have h₄ : IsUnit (a : ZMod (p ^ k)) := by rw [h₁] at * exact h₃ exact ha h₄ have h₃ : Nat.Coprime (p : ℕ) a.val := by have h₄ : Nat.Prime p := hp.1 have h₅ : ¬p ∣ a.val := h have h₆ : Nat.Coprime p a.val := by rw [h₄.coprime_iff_not_dvd] exact h₅ exact h₆ have h₄ : Nat.Coprime (p ^ k) a.val := by have h₅ : Nat.Coprime (p : ℕ) a.val := h₃ have h₆ : Nat.Coprime (p ^ k) a.val := by apply Nat.Coprime.pow_left exact h₅ exact h₆ have h₅ : Nat.Coprime a.val (p ^ k) := by rw [Nat.coprime_comm] at h₄ exact h₄ exact h₂ h₅ lemma val_div_p_lt {p : ℕ} [hp : Fact (Nat.Prime p)] {k : ℕ} (hk : 0 < k) (a : ZMod (p ^ k)) : a.val / p < p ^ (k - 1) := by have h₁ : a.val < p ^ k := by exact ZMod.val_lt a have h₂ : a.val / p < p ^ (k - 1) := by have h₃ : a.val < p ^ k := h₁ have h₅ : a.val / p < p ^ (k - 1) := by have h₆ : a.val / p * p ≤ a.val := Nat.div_mul_le_self a.val p have h₇ : a.val < p ^ k := h₃ have h₈ : a.val / p * p < p ^ k := by calc a.val / p * p ≤ a.val := h₆ _ < p ^ k := h₇ have h₉ : a.val / p < p ^ (k - 1) := by have h₁₀ : p ^ (k - 1) * p = p ^ k := by cases k with | zero => contradiction | succ k' => simp [pow_succ, mul_comm] have h₁₁ : a.val / p < p ^ (k - 1) := by by_contra h have h₁₂ : a.val / p ≥ p ^ (k - 1) := by omega have h₁₃ : a.val / p * p ≥ p ^ (k - 1) * p := by exact Nat.mul_le_mul_right p h₁₂ omega exact h₁₁ exact h₉ exact h₅ exact h₂ lemma nonunitFwd_nonunitBwd {p : ℕ} [hp : Fact (Nat.Prime p)] {k : ℕ} (hk : 0 < k) (a : ZMod (p ^ k)) (ha : a ∈ Finset.univ.filter (fun a : ZMod (p ^ k) => ¬ IsUnit a)) : nonunitFwd (nonunitBwd (p := p) a) = a := by simp only [Finset.mem_filter, Finset.mem_univ, true_and] at ha simp only [nonunitFwd, nonunitBwd] rw [ZMod.val_natCast_of_lt (val_div_p_lt hk a), ← Nat.cast_mul, Nat.mul_div_cancel' (p_dvd_val_of_not_isUnit a ha), ZMod.natCast_zmod_val] lemma lhs_cast_eq {p : ℕ} [hp : Fact (Nat.Prime p)] {k : ℕ} (hk : 0 < k) (b : ZMod (p ^ (k - 1))) (t : ℤ) : (nonunitFwd (p := p) (k := k) b * (t : ZMod (p ^ k)) : ZMod (p ^ k)) = ((↑p * ↑b.val * t : ℤ) : ZMod (p ^ k)) := by show (p : ZMod (p ^ k)) * (b.val : ZMod (p ^ k)) * (t : ZMod (p ^ k)) = _ push_cast ring lemma rhs_cast_eq {p : ℕ} [hp : Fact (Nat.Prime p)] {k : ℕ} (hk : 0 < k) (b : ZMod (p ^ (k - 1))) (t : ℤ) : (b * (t : ZMod (p ^ (k - 1))) : ZMod (p ^ (k - 1))) = ((↑b.val * t : ℤ) : ZMod (p ^ (k - 1))) := by haveI : NeZero (p ^ (k - 1)) := ⟨pow_ne_zero _ hp.out.ne_zero⟩ exact zmod_mul_as_cast (p ^ (k - 1)) b t lemma exponent_eq {p : ℕ} [hp : Fact (Nat.Prime p)] {k : ℕ} (hk : 0 < k) (b : ZMod (p ^ (k - 1))) (t : ℤ) : 2 * ↑Real.pi * Complex.I * (↑(↑p * ↑b.val * t : ℤ) : ℂ) / (↑(p ^ k) : ℂ) = 2 * ↑Real.pi * Complex.I * (↑(↑b.val * t : ℤ) : ℂ) / (↑(p ^ (k - 1)) : ℂ) := by rw [show (p : ℕ) ^ k = p * p ^ (k - 1) from (p_mul_pow_pred hk).symm] push_cast field_simp [Nat.cast_ne_zero.mpr hp.out.ne_zero, show (↑(p ^ (k - 1) : ℕ) : ℂ) ≠ 0 by exact_mod_cast pow_ne_zero _ hp.out.ne_zero] lemma stdAddChar_nonunitFwd_eq {p : ℕ} [hp : Fact (Nat.Prime p)] {k : ℕ} (hk : 0 < k) (b : ZMod (p ^ (k - 1))) (t : ℤ) : ZMod.stdAddChar (nonunitFwd (p := p) (k := k) b * (t : ZMod (p ^ k))) = ZMod.stdAddChar (b * (t : ZMod (p ^ (k - 1)))) := by rw [lhs_cast_eq hk b t, rhs_cast_eq hk b t, ZMod.stdAddChar_coe, ZMod.stdAddChar_coe] congr 1 exact exponent_eq hk b t lemma sum_nonunits_eq_sum_lower {p : ℕ} [hp : Fact (Nat.Prime p)] {k : ℕ} (hk : 0 < k) (t : ℤ) : (∑ a ∈ Finset.univ.filter (fun a : ZMod (p ^ k) => ¬ IsUnit a), ZMod.stdAddChar (a * (t : ZMod (p ^ k)))) = ∑ b : ZMod (p ^ (k - 1)), ZMod.stdAddChar (b * (t : ZMod (p ^ (k - 1)))) := by symm exact Finset.sum_nbij' (nonunitFwd (p := p) (k := k)) (nonunitBwd (p := p) (k := k)) (fun b _ => Finset.mem_filter.mpr ⟨Finset.mem_univ _, nonunitFwd_not_isUnit hk b⟩) (fun _ _ => Finset.mem_univ _) (fun b _ => nonunitBwd_nonunitFwd hk b) (fun a ha => nonunitFwd_nonunitBwd hk a ha) (fun b _ => (stdAddChar_nonunitFwd_eq hk b t).symm) lemma ramanujanSum_prime_pow_decomp {p : ℕ} [hp : Fact (Nat.Prime p)] {k : ℕ} (hk : 0 < k) (t : ℤ) : @ramanujanSum (p ^ k) ⟨pow_ne_zero k hp.out.ne_zero⟩ t = (∑ a : ZMod (p ^ k), ZMod.stdAddChar (a * (t : ZMod (p ^ k)))) - (∑ b : ZMod (p ^ (k - 1)), ZMod.stdAddChar (b * (t : ZMod (p ^ (k - 1))))) := by rw [show (∑ a : ZMod (p ^ k), ZMod.stdAddChar (a * (t : ZMod (p ^ k)))) = ramanujanSum (p ^ k) t + _ from sum_eq_ramanujanSum_add_sum_nonunits (p ^ k) t, @sum_nonunits_eq_sum_lower p hp k hk t, add_sub_cancel_right] theorem ramanujanSum_prime_pow_eq_zero {p : ℕ} [hp : Fact (Nat.Prime p)] {k : ℕ} (hk : 0 < k) {t : ℤ} (ht : ¬ ((p : ℤ) ^ (k - 1) ∣ t)) : @ramanujanSum (p ^ k) ⟨pow_ne_zero k hp.out.ne_zero⟩ t = 0 := by rw [ramanujanSum_prime_pow_decomp hk t, sum_stdAddChar_mul_eq, sum_stdAddChar_mul_eq] simp only [Nat.cast_pow] at ht ⊢ have hk_not : ¬ ((p : ℤ) ^ k ∣ t) := fun h => ht (dvd_trans (pow_dvd_pow _ (Nat.sub_le k 1)) h) simp [hk_not, ht] lemma ramanujanSum_unit_shift (n : ℕ) [NeZero n] (u : (ZMod n)ˣ) (s : ZMod n) : ∑ a : (ZMod n)ˣ, ZMod.stdAddChar (a.val * (u.val * s)) = ∑ a : (ZMod n)ˣ, ZMod.stdAddChar (a.val * s) := Fintype.sum_equiv (Equiv.mulRight u) (fun a => ZMod.stdAddChar (a.val * (u.val * s))) (fun a => ZMod.stdAddChar (a.val * s)) (fun a => by simp only [Equiv.coe_mulRight, Units.val_mul, mul_assoc]) lemma dvd_sub_mul_crt_val {n₁ n₂ : ℕ} [NeZero n₁] [NeZero n₂] (h : Nat.Coprime n₁ n₂) (j : ℤ) : (n₁ : ℤ) ∣ j - ↑n₂ * ↑((j : ZMod n₁) * (↑n₂ : ZMod n₁)⁻¹).val := by rw [← ZMod.intCast_zmod_eq_zero_iff_dvd] push_cast rw [sub_eq_zero, ZMod.natCast_zmod_val, mul_comm (↑n₂ : ZMod n₁), mul_assoc, ZMod.inv_mul_of_unit _ (by rwa [ZMod.isUnit_iff_coprime, Nat.coprime_comm]), mul_one] lemma crt_exponent_eq {n₁ n₂ : ℕ} [hn₁ : NeZero n₁] [hn₂ : NeZero n₂] (h : Nat.Coprime n₁ n₂) (j : ℤ) : ∃ m : ℤ, 2 * ↑Real.pi * Complex.I * ↑j / ↑(n₁ * n₂) = (2 * ↑Real.pi * Complex.I * ↑((j : ZMod n₁) * (↑n₂ : ZMod n₁)⁻¹).val / ↑n₁ + 2 * ↑Real.pi * Complex.I * ↑((j : ZMod n₂) * (↑n₁ : ZMod n₂)⁻¹).val / ↑n₂) + ↑m * (2 * ↑Real.pi * Complex.I) := by set v₁ := ((j : ZMod n₁) * (↑n₂ : ZMod n₁)⁻¹).val set v₂ := ((j : ZMod n₂) * (↑n₁ : ZMod n₂)⁻¹).val have h1 : (n₁ : ℤ) ∣ j - ↑n₂ * ↑v₁ := dvd_sub_mul_crt_val h j have h2 : (n₂ : ℤ) ∣ j - ↑n₁ * ↑v₂ := dvd_sub_mul_crt_val h.symm j obtain ⟨m, hm⟩ := h.isCoprime.mul_dvd (dvd_sub h1 (dvd_mul_right _ _)) (show (n₂ : ℤ) ∣ j - ↑n₂ * ↑v₁ - ↑n₁ * ↑v₂ by rw [show j - ↑n₂ * ↑v₁ - ↑n₁ * ↑v₂ = j - ↑n₁ * ↑v₂ - ↑n₂ * ↑v₁ by ring] exact dvd_sub h2 (dvd_mul_right _ _)) have hint : j = ↑n₂ * ↑v₁ + ↑n₁ * ↑v₂ + m * (↑n₁ * ↑n₂) := by linarith exact ⟨m, by rw [Nat.cast_mul, show (↑j : ℂ) = ↑n₂ * ↑v₁ + ↑n₁ * ↑v₂ + ↑m * (↑n₁ * ↑n₂) by exact_mod_cast hint] field_simp [Nat.cast_ne_zero.mpr (NeZero.ne n₁), Nat.cast_ne_zero.mpr (NeZero.ne n₂)]⟩ lemma stdAddChar_crt_split {n₁ n₂ : ℕ} [hn₁ : NeZero n₁] [hn₂ : NeZero n₂] (h : Nat.Coprime n₁ n₂) (x : ZMod (n₁ * n₂)) : @ZMod.stdAddChar (n₁ * n₂) ⟨Nat.mul_ne_zero hn₁.ne hn₂.ne⟩ x = ZMod.stdAddChar ((ZMod.chineseRemainder h x).1 * (n₂ : ZMod n₁)⁻¹) * ZMod.stdAddChar ((ZMod.chineseRemainder h x).2 * (n₁ : ZMod n₂)⁻¹) := by obtain ⟨j, rfl⟩ := ZMod.intCast_surjective (n := n₁ * n₂) x rw [show (ZMod.chineseRemainder h (j : ZMod (n₁ * n₂))).1 = (j : ZMod n₁) by simp, show (ZMod.chineseRemainder h (j : ZMod (n₁ * n₂))).2 = (j : ZMod n₂) by simp, @ZMod.stdAddChar_coe (n₁ * n₂) ⟨Nat.mul_ne_zero hn₁.ne hn₂.ne⟩] simp only [ZMod.stdAddChar_apply, ← Circle.coe_mul] rw [Circle.coe_mul, ZMod.toCircle_apply, ZMod.toCircle_apply, ← Complex.exp_add, Complex.exp_eq_exp_iff_exists_int] exact crt_exponent_eq h j lemma crt_proj_fst {n₁ n₂ : ℕ} [hn₁ : NeZero n₁] [hn₂ : NeZero n₂] (h : Nat.Coprime n₁ n₂) (a₁ : (ZMod n₁)ˣ) (a₂ : (ZMod n₂)ˣ) (t : ℤ) : let e := (Units.mapEquiv (ZMod.chineseRemainder h).toMulEquiv).toEquiv.trans MulEquiv.prodUnits.toEquiv (ZMod.chineseRemainder h ((e.symm (a₁, a₂)).val * (t : ZMod (n₁ * n₂)))).1 = a₁.val * (t : ZMod n₁) := by intro e have h_e_val : ZMod.chineseRemainder h ((e.symm (a₁, a₂)).val) = (a₁.val, a₂.val) := by simp [e, Equiv.trans, Units.mapEquiv, MulEquiv.toEquiv, MulEquiv.prodUnits] have h_main : (ZMod.chineseRemainder h ((e.symm (a₁, a₂)).val * (t : ZMod (n₁ * n₂)))).1 = a₁.val * (t : ZMod n₁) := by simp_all assumption lemma crt_proj_snd {n₁ n₂ : ℕ} [hn₁ : NeZero n₁] [hn₂ : NeZero n₂] (h : Nat.Coprime n₁ n₂) (a₁ : (ZMod n₁)ˣ) (a₂ : (ZMod n₂)ˣ) (t : ℤ) : let e := (Units.mapEquiv (ZMod.chineseRemainder h).toMulEquiv).toEquiv.trans MulEquiv.prodUnits.toEquiv (ZMod.chineseRemainder h ((e.symm (a₁, a₂)).val * (t : ZMod (n₁ * n₂)))).2 = a₂.val * (t : ZMod n₂) := by intro e have h₂ : (ZMod.chineseRemainder h ((e.symm (a₁, a₂)).val)) = (a₁.val, a₂.val) := by simp [e, Equiv.trans, Units.mapEquiv, MulEquiv.toEquiv, MulEquiv.prodUnits] have h₃ : (ZMod.chineseRemainder h ((e.symm (a₁, a₂)).val * (t : ZMod (n₁ * n₂)))).2 = a₂.val * (t : ZMod n₂) := by simp_all assumption lemma ramanujanSum_crt_decomp {n₁ n₂ : ℕ} [hn₁ : NeZero n₁] [hn₂ : NeZero n₂] (h : Nat.Coprime n₁ n₂) (t : ℤ) : ∑ a : (ZMod (n₁ * n₂))ˣ, @ZMod.stdAddChar (n₁ * n₂) ⟨Nat.mul_ne_zero hn₁.ne hn₂.ne⟩ (a.val * (t : ZMod (n₁ * n₂))) = ∑ ab : (ZMod n₁)ˣ × (ZMod n₂)ˣ, ZMod.stdAddChar (ab.1.val * ((n₂ : ZMod n₁)⁻¹ * (t : ZMod n₁))) * ZMod.stdAddChar (ab.2.val * ((n₁ : ZMod n₂)⁻¹ * (t : ZMod n₂))) := by let e : (ZMod (n₁ * n₂))ˣ ≃ (ZMod n₁)ˣ × (ZMod n₂)ˣ := (Units.mapEquiv (ZMod.chineseRemainder h).toMulEquiv).toEquiv.trans MulEquiv.prodUnits.toEquiv rw [show (∑ a : (ZMod (n₁ * n₂))ˣ, @ZMod.stdAddChar (n₁ * n₂) ⟨Nat.mul_ne_zero hn₁.ne hn₂.ne⟩ (a.val * (t : ZMod (n₁ * n₂)))) = ∑ ab : (ZMod n₁)ˣ × (ZMod n₂)ˣ, @ZMod.stdAddChar (n₁ * n₂) ⟨Nat.mul_ne_zero hn₁.ne hn₂.ne⟩ ((e.symm ab).val * (t : ZMod (n₁ * n₂))) from Fintype.sum_equiv e _ _ (fun a => by simp [e])] congr 1 ext ⟨a₁, a₂⟩ rw [stdAddChar_crt_split h, crt_proj_fst h a₁ a₂ t, crt_proj_snd h a₁ a₂ t] congr 1 <;> congr 1 <;> ring lemma ramanujanSum_absorb_inv {n m : ℕ} [NeZero n] (hc : Nat.Coprime m n) (s : ZMod n) : ∑ a : (ZMod n)ˣ, ZMod.stdAddChar (a.val * ((m : ZMod n)⁻¹ * s)) = ∑ a : (ZMod n)ˣ, ZMod.stdAddChar (a.val * s) := by let u := ZMod.unitOfCoprime m hc rw [show (m : ZMod n)⁻¹ = (u⁻¹ : (ZMod n)ˣ).val by rw [← ZMod.coe_unitOfCoprime m hc, ZMod.inv_coe_unit u]] exact ramanujanSum_unit_shift n u⁻¹ s lemma sum_prod_factor {n₁ n₂ : ℕ} [NeZero n₁] [NeZero n₂] (s₁ : ZMod n₁) (s₂ : ZMod n₂) : ∑ ab : (ZMod n₁)ˣ × (ZMod n₂)ˣ, ZMod.stdAddChar (ab.1.val * s₁) * ZMod.stdAddChar (ab.2.val * s₂) = (∑ a : (ZMod n₁)ˣ, ZMod.stdAddChar (a.val * s₁)) * (∑ a : (ZMod n₂)ˣ, ZMod.stdAddChar (a.val * s₂)) := by simp_rw [Fintype.sum_prod_type, Fintype.sum_mul_sum] theorem ramanujanSum_multiplicative {n₁ n₂ : ℕ} [hn₁ : NeZero n₁] [hn₂ : NeZero n₂] (h : Nat.Coprime n₁ n₂) (t : ℤ) : @ramanujanSum (n₁ * n₂) ⟨Nat.mul_ne_zero hn₁.ne hn₂.ne⟩ t = ramanujanSum n₁ t * ramanujanSum n₂ t := by unfold ramanujanSum rw [ramanujanSum_crt_decomp h t, sum_prod_factor, ramanujanSum_absorb_inv h.symm (t : ZMod n₁), ramanujanSum_absorb_inv h (t : ZMod n₂)] lemma largestPrimeFactor_mem_primeFactors (n : ℕ) (hn : 2 ≤ n) : largestPrimeFactor n ∈ n.primeFactors := by obtain ⟨a, ha_max, _⟩ := largestPrimeFactor_pos_helper_fb n hn have hmem : a ∈ n.primeFactors := Finset.mem_of_max ha_max have : largestPrimeFactor n = a := by unfold largestPrimeFactor rw [ha_max] rfl rw [this] exact hmem theorem largest_prime_factor_multiplicity_pos (n : ℕ) (hn : 2 ≤ n) : n.factorization (largestPrimeFactor n) ≥ 1 := by have hmem := largestPrimeFactor_mem_primeFactors n hn rw [← Nat.support_factorization] at hmem exact Nat.one_le_iff_ne_zero.mpr (Finsupp.mem_support_iff.mp hmem) lemma largest_prime_factor_prime (n : ℕ) (hn : 2 ≤ n) : Nat.Prime (largestPrimeFactor n) := by exact Nat.prime_of_mem_primeFactors (largestPrimeFactor_mem_primeFactors n hn) lemma decompose_largest_prime (n : ℕ) (hn : 2 ≤ n) : let P := largestPrimeFactor n let α := n.factorization P let m := n / (P ^ α) P ^ α * m = n ∧ Nat.Coprime (P ^ α) m ∧ 0 < m := by intro P α m have hn_ne_zero : n ≠ 0 := by omega have P_mem := largestPrimeFactor_mem_primeFactors n hn have P_prime := Nat.prime_of_mem_primeFactors P_mem have α_pos := Nat.Prime.factorization_pos_of_dvd P_prime hn_ne_zero (Nat.dvd_of_mem_primeFactors P_mem) have mul_eq := Nat.ordProj_mul_ordCompl_eq_self n P have p_coprime_m := Nat.coprime_ordCompl P_prime hn_ne_zero have coprime := (Nat.coprime_pow_left_iff α_pos _ _).mpr p_coprime_m have dvd := Nat.ordProj_dvd n P have hPα_pos : 0 < P ^ α := Nat.pos_of_ne_zero (pow_ne_zero _ P_prime.ne_zero) have m_pos := Nat.div_pos (Nat.le_of_dvd (by omega) dvd) hPα_pos exact ⟨mul_eq, coprime, m_pos⟩ lemma ramanujan_vanish_low_valuation (n : ℕ) [NeZero n] (hn : 2 ≤ n) (t : ℤ) (ht : ¬((largestPrimeFactor n ^ (n.factorization (largestPrimeFactor n) - 1) : ℤ) ∣ t)) : ramanujanSum n t = 0 := by set P := largestPrimeFactor n set α := n.factorization P have hα_pos : 0 < α := largest_prime_factor_multiplicity_pos n hn have hP_prime : Nat.Prime P := largest_prime_factor_prime n hn have ⟨hdecomp, hcoprime, hm_pos⟩ := decompose_largest_prime n hn set m := n / (P ^ α) haveI hPα_ne : NeZero (P ^ α) := ⟨pow_ne_zero α (Nat.Prime.ne_zero hP_prime)⟩ haveI hm_ne : NeZero m := ⟨Nat.pos_iff_ne_zero.mp hm_pos⟩ have decomp_eq : n = P ^ α * m := hdecomp.symm conv_lhs => arg 1 rw [decomp_eq] rw [ramanujanSum_multiplicative hcoprime t] haveI : Fact (Nat.Prime P) := ⟨hP_prime⟩ have vanish_comp : ramanujanSum (P ^ α) t = 0 := ramanujanSum_prime_pow_eq_zero hα_pos ht rw [vanish_comp] ring lemma summand_eq_EP0_plus_EPalpha (n : ℕ) [NeZero n] (hn : 2 ≤ n) (p q : ℤ) (hp : 1 ≤ p) (hq : 1 ≤ q) (hpq : (p : ℝ) + (q : ℝ) < (n : ℝ) / 2) (k l : ZMod n) : (if ¬(k = 0 ∧ l = 0) then normalizedDFT n (intervalIndicator n (2 * p - 1).toNat) k * normalizedDFT n (intervalIndicator n (2 * q - 1).toNat) l * ramanujanSum n (ZMod.val k * p + ZMod.val l * q) else 0 : ℂ) = (let P := largestPrimeFactor n let alpha := n.factorization P let P0 := P ^ (alpha - 1) let d := P ^ alpha let fp := intervalIndicator n (2 * p - 1).toNat let fq := intervalIndicator n (2 * q - 1).toNat (if (k, l) ≠ (0, 0) ∧ (P0 : ℤ) ∣ (ZMod.val k * p + ZMod.val l * q) ∧ ¬((d : ℤ) ∣ (ZMod.val k * p + ZMod.val l * q)) then normalizedDFT n fp k * normalizedDFT n fq l * ramanujanSum n (ZMod.val k * p + ZMod.val l * q) else 0) + (if (k, l) ≠ (0, 0) ∧ (d : ℤ) ∣ (ZMod.val k * p + ZMod.val l * q) then normalizedDFT n fp k * normalizedDFT n fq l * ramanujanSum n (ZMod.val k * p + ZMod.val l * q) else 0)) := by simp only [] set t := (↑(ZMod.val k) * p + ↑(ZMod.val l) * q : ℤ) set P := largestPrimeFactor n set α := n.factorization P set V := normalizedDFT n (intervalIndicator n (2 * p - 1).toNat) k * normalizedDFT n (intervalIndicator n (2 * q - 1).toNat) l * ramanujanSum n t have hiff : ¬(k = 0 ∧ l = 0) ↔ (k, l) ≠ (0, 0) := by constructor · intro h hprod; exact h ⟨(Prod.mk.inj hprod).1, (Prod.mk.inj hprod).2⟩ · intro h ⟨hk, hl⟩; exact h (Prod.mk.injEq k l 0 0 |>.mpr ⟨hk, hl⟩) by_cases hkl : (k, l) = (0, 0) · have hkl' : ¬¬(k = 0 ∧ l = 0) := not_not.mpr ⟨(Prod.mk.inj hkl).1, (Prod.mk.inj hkl).2⟩ rw [if_neg hkl', if_neg (show ¬((k, l) ≠ (0, 0) ∧ _) from fun ⟨h, _⟩ => h hkl), if_neg (show ¬((k, l) ≠ (0, 0) ∧ _) from fun ⟨h, _⟩ => h hkl)] ring · have hkl' : ¬(k = 0 ∧ l = 0) := hiff.mpr hkl rw [if_pos hkl'] by_cases hP0 : (↑(P ^ (α - 1)) : ℤ) ∣ t · by_cases hd : (↑(P ^ α) : ℤ) ∣ t · rw [if_neg (show ¬((_ ≠ _) ∧ _ ∧ ¬_) from by push_neg; exact fun _ _ => hd), if_pos ⟨hkl, hd⟩] ring · rw [if_pos ⟨hkl, hP0, hd⟩, if_neg (show ¬((_ ≠ _) ∧ _) from by push_neg; exact fun _ => hd)] ring · have hnotd : ¬((↑(P ^ α) : ℤ) ∣ t) := fun hd => hP0 (dvd_trans (by exact_mod_cast pow_dvd_pow P (Nat.sub_le α 1)) hd) have hvanish : ramanujanSum n t = 0 := ramanujan_vanish_low_valuation n hn t hP0 rw [if_neg (show ¬((_ ≠ _) ∧ _ ∧ _) from by push_neg; exact fun _ h => absurd h hP0), if_neg (show ¬((_ ≠ _) ∧ _) from by push_neg; exact fun _ => hnotd)] simp [V, hvanish] lemma nonzero_sum_eq_EP0_plus_EPalpha (n : ℕ) [NeZero n] (hn : 2 ≤ n) (p q : ℤ) (hp : 1 ≤ p) (hq : 1 ≤ q) (hpq : (p : ℝ) + (q : ℝ) < (n : ℝ) / 2) : (∑ k : ZMod n, ∑ l : ZMod n, if ¬(k = 0 ∧ l = 0) then normalizedDFT n (intervalIndicator n (2 * p - 1).toNat) k * normalizedDFT n (intervalIndicator n (2 * q - 1).toNat) l * ramanujanSum n (ZMod.val k * p + ZMod.val l * q) else 0 : ℂ) = errorTermEP0 n p q + errorTermEPalpha n p q := by simp only [errorTermEP0, errorTermEPalpha] rw [← Finset.sum_add_distrib] congr 1 ext k rw [← Finset.sum_add_distrib] congr 1 ext l exact summand_eq_EP0_plus_EPalpha n hn p q hp hq hpq k l lemma fourier_sum_split_into_main_and_errors (n : ℕ) (hn : 2 ≤ n) (p q : ℤ) (hp : 1 ≤ p) (hq : 1 ≤ q) (hpq : (p : ℝ) + (q : ℝ) < (n : ℝ) / 2) : haveI : NeZero n := ⟨by omega⟩ (∑ k : ZMod n, ∑ l : ZMod n, normalizedDFT n (intervalIndicator n (2 * p - 1).toNat) k * normalizedDFT n (intervalIndicator n (2 * q - 1).toNat) l * ramanujanSum n (ZMod.val k * p + ZMod.val l * q) : ℂ) - ((2 * p - 1).toNat : ℂ) * ((2 * q - 1).toNat : ℂ) * (Nat.totient n : ℂ) / (n : ℂ) ^ 2 = errorTermEP0 n p q + errorTermEPalpha n p q := by haveI : NeZero n := ⟨by omega⟩ rw [full_sum_split_zero_nonzero n (fun k l => normalizedDFT n (intervalIndicator n (2 * p - 1).toNat) k * normalizedDFT n (intervalIndicator n (2 * q - 1).toNat) l * ramanujanSum n (ZMod.val k * p + ZMod.val l * q))] rw [zero_zero_term_eq_main n hn p q hp hq hpq] rw [nonzero_sum_eq_EP0_plus_EPalpha n hn p q hp hq hpq] ring lemma re_complex_lhs_eq_real_lhs (n : ℕ) (hn : 2 ≤ n) (p q : ℤ) (hp : 1 ≤ p) (hq : 1 ≤ q) (hpq : (p : ℝ) + (q : ℝ) < (n : ℝ) / 2) : ((countingFunctionS n p q : ℂ) - ((2 * p - 1).toNat : ℂ) * ((2 * q - 1).toNat : ℂ) * (Nat.totient n : ℂ) / (n : ℂ) ^ 2).re = (countingFunctionS n p q : ℝ) - ((2 * p - 1).toNat : ℝ) * ((2 * q - 1).toNat : ℝ) * (Nat.totient n : ℝ) / (n : ℝ) ^ 2 := by have h₁ : ((countingFunctionS n p q : ℂ) - ((2 * p - 1).toNat : ℂ) * ((2 * q - 1).toNat : ℂ) * (Nat.totient n : ℂ) / (n : ℂ) ^ 2).re = (countingFunctionS n p q : ℝ) - ((2 * p - 1).toNat : ℝ) * ((2 * q - 1).toNat : ℝ) * (Nat.totient n : ℝ) / (n : ℝ) ^ 2 := by simp [Complex.ext_iff, pow_two, Complex.mul_re, Complex.mul_im, Complex.ofReal_mul, Complex.ofReal_add, Complex.ofReal_sub, Complex.ofReal_div, Complex.ofReal_one, Complex.ofReal_zero] <;> norm_cast <;> (try ring_nf) <;> (try norm_num) <;> (try field_simp) <;> (try norm_cast) <;> (try simp_all [Complex.ext_iff, pow_two, Complex.mul_re, Complex.mul_im, Complex.ofReal_mul, Complex.ofReal_add, Complex.ofReal_sub, Complex.ofReal_div, Complex.ofReal_one, Complex.ofReal_zero]) exact h₁ lemma error_decomposition_from_complex (n : ℕ) (hn : 2 ≤ n) (p q : ℤ) (hp : 1 ≤ p) (hq : 1 ≤ q) (hpq : (p : ℝ) + (q : ℝ) < (n : ℝ) / 2) (h_complex : haveI : NeZero n := ⟨by omega⟩ (countingFunctionS n p q : ℂ) - ((2 * p - 1).toNat : ℂ) * ((2 * q - 1).toNat : ℂ) * (Nat.totient n : ℂ) / (n : ℂ) ^ 2 = errorTermEP0 n p q + errorTermEPalpha n p q) : haveI : NeZero n := ⟨by omega⟩ (countingFunctionS n p q : ℝ) - ((2 * p - 1).toNat : ℝ) * ((2 * q - 1).toNat : ℝ) * (Nat.totient n : ℝ) / (n : ℝ) ^ 2 = (errorTermEP0 n p q).re + (errorTermEPalpha n p q).re := by have hre := congr_arg Complex.re h_complex rw [Complex.add_re] at hre rw [← hre] exact (re_complex_lhs_eq_real_lhs n hn p q hp hq hpq).symm lemma error_decomposition (n : ℕ) (hn : 2 ≤ n) (p q : ℤ) (hp : 1 ≤ p) (hq : 1 ≤ q) (hpq : (p : ℝ) + (q : ℝ) < (n : ℝ) / 2) : haveI : NeZero n := ⟨by omega⟩ (countingFunctionS n p q : ℝ) - ((2 * p - 1).toNat : ℝ) * ((2 * q - 1).toNat : ℝ) * (Nat.totient n : ℝ) / (n : ℝ) ^ 2 = (errorTermEP0 n p q).re + (errorTermEPalpha n p q).re := by haveI : NeZero n := ⟨by omega⟩ have h_repr := counting_eq_fourier_ramanujan_sum n hn p q hp hq hpq have h_split := fourier_sum_split_into_main_and_errors n hn p q hp hq hpq have h_complex : (countingFunctionS n p q : ℂ) - ((2 * p - 1).toNat : ℂ) * ((2 * q - 1).toNat : ℂ) * (Nat.totient n : ℂ) / (n : ℂ) ^ 2 = errorTermEP0 n p q + errorTermEPalpha n p q := by rw [h_repr]; exact h_split exact error_decomposition_from_complex n hn p q hp hq hpq h_complex lemma double_sum_norms_eq_product (n : ℕ) [NeZero n] (f g : ZMod n → ℂ) : ∑ k : ZMod n, ∑ l : ZMod n, ‖f k‖ * ‖g l‖ = (∑ k : ZMod n, ‖f k‖) * (∑ l : ZMod n, ‖g l‖) := (Fintype.sum_mul_sum (fun k => ‖f k‖) (fun l => ‖g l‖)).symm lemma ramanujanSum_norm_le_totient (n : ℕ) [NeZero n] (t : ℤ) : ‖ramanujanSum n t‖ ≤ (Nat.totient n : ℝ) := by have h1 : ‖ramanujanSum n t‖ ≤ Fintype.card (ZMod n)ˣ := by calc ‖ramanujanSum n t‖ = ‖∑ a : (ZMod n)ˣ, ZMod.stdAddChar (a.val * (t : ZMod n))‖ := rfl _ ≤ ∑ a : (ZMod n)ˣ, ‖ZMod.stdAddChar (a.val * (t : ZMod n))‖ := norm_sum_le _ _ _ = ∑ _ : (ZMod n)ˣ, (1 : ℝ) := by apply Finset.sum_congr rfl intro a _ have h : ‖ZMod.stdAddChar (a.val * (t : ZMod n))‖ = 1 := by simpa using ZMod.stdAddChar.isometric.map_norm (1 : ℂ) simp [h] _ = (Fintype.card (ZMod n)ˣ : ℝ) := by simp [Finset.sum_const, nsmul_eq_mul] have h2 : (Fintype.card (ZMod n)ˣ : ℝ) = (Nat.totient n : ℝ) := by norm_cast <;> simp [ZMod.card_units_eq_totient] calc ‖ramanujanSum n t‖ ≤ Fintype.card (ZMod n)ˣ := h1 _ = (Nat.totient n : ℝ) := by rw [h2] lemma ramanujanSum_prime_pow_eq_neg {p : ℕ} [hp : Fact (Nat.Prime p)] {k : ℕ} (hk : 0 < k) {t : ℤ} (ht1 : (p : ℤ) ^ (k - 1) ∣ t) (ht2 : ¬ ((p : ℤ) ^ k ∣ t)) : @ramanujanSum (p ^ k) ⟨pow_ne_zero k hp.out.ne_zero⟩ t = -(p : ℂ) ^ (k - 1) := by rw [ramanujanSum_prime_pow_decomp hk t, sum_stdAddChar_mul_eq, sum_stdAddChar_mul_eq] simp only [Nat.cast_pow] at ht1 ht2 ⊢ simp [ht1, ht2] lemma norm_ramanujanSum_prime_pow_eq_neg {p : ℕ} [hp : Fact (Nat.Prime p)] {k : ℕ} (hk : 0 < k) {t : ℤ} (ht1 : (p : ℤ) ^ (k - 1) ∣ t) (ht2 : ¬ ((p : ℤ) ^ k ∣ t)) : ‖@ramanujanSum (p ^ k) ⟨pow_ne_zero k hp.out.ne_zero⟩ t‖ = (p : ℝ) ^ (k - 1) := by rw [ramanujanSum_prime_pow_eq_neg hk ht1 ht2, norm_neg, Complex.norm_pow, Complex.norm_natCast] lemma totient_div_prime_minus_one (n P α m : ℕ) (hP : Nat.Prime P) (hα : 0 < α) (hcop : Nat.Coprime (P ^ α) m) (hn : P ^ α * m = n) : (P : ℝ) ^ (α - 1) * (Nat.totient m : ℝ) = (Nat.totient n : ℝ) / ((P : ℝ) - 1) := by have hP_ge_two : P ≥ 2 := by exact hP.two_le have hP_pos : (0 : ℕ) < P := by nlinarith have hP_sub_one_pos : (P : ℝ) - 1 > 0 := by linarith [show (1 : ℝ) < (P : ℝ) from by exact_mod_cast hP.one_lt] have htotient_mul : Nat.totient (P ^ α * m) = Nat.totient (P ^ α) * Nat.totient m := by exact Nat.totient_mul hcop have htotient_prime_pow : Nat.totient (P ^ α) = P ^ (α - 1) * (P - 1) := by exact Nat.totient_prime_pow hP (by omega : 0 < α) have htotient_n : (Nat.totient n : ℝ) = (P : ℝ) ^ (α - 1) * ((P : ℝ) - 1) * (Nat.totient m : ℝ) := by simp_all have hmain : (P : ℝ) ^ (α - 1) * (Nat.totient m : ℝ) = (Nat.totient n : ℝ) / ((P : ℝ) - 1) := by field_simp; rw [htotient_n]; ring assumption lemma ramanujanSum_EP0_norm_bound (n : ℕ) [NeZero n] (hn : 2 ≤ n) (t : ℤ) (hP0 : (↑(largestPrimeFactor n ^ (n.factorization (largestPrimeFactor n) - 1)) : ℤ) ∣ t) (hd : ¬ ((↑(largestPrimeFactor n ^ n.factorization (largestPrimeFactor n)) : ℤ) ∣ t)) : ‖ramanujanSum n t‖ ≤ (Nat.totient n : ℝ) / ((largestPrimeFactor n : ℝ) - 1) := by set P := largestPrimeFactor n set α := n.factorization P set m := n / (P ^ α) have hPprime : Nat.Prime P := largest_prime_factor_prime n hn have hαge : α ≥ 1 := largest_prime_factor_multiplicity_pos n hn have hαpos : 0 < α := by linarith obtain ⟨hdecomp, hcop, hm_pos⟩ := decompose_largest_prime n hn haveI hne_Pα : NeZero (P ^ α) := ⟨pow_ne_zero α (Nat.Prime.ne_zero hPprime)⟩ haveI hne_m : NeZero m := ⟨Nat.pos_iff_ne_zero.mp hm_pos⟩ haveI : Fact (Nat.Prime P) := ⟨hPprime⟩ have ht1 : (P : ℤ) ^ (α - 1) ∣ t := by exact_mod_cast hP0 have ht2 : ¬ ((P : ℤ) ^ α ∣ t) := by exact_mod_cast hd have h_norm_Palpha : ‖@ramanujanSum (P ^ α) hne_Pα t‖ = (P : ℝ) ^ (α - 1) := norm_ramanujanSum_prime_pow_eq_neg hαpos ht1 ht2 have h_norm_m : ‖@ramanujanSum m hne_m t‖ ≤ (Nat.totient m : ℝ) := ramanujanSum_norm_le_totient m t have hPαm_ne : P ^ α * m ≠ 0 := Nat.pos_iff_ne_zero.mp (Nat.mul_pos (Nat.pos_of_ne_zero hne_Pα.ne) hm_pos) have h_mult : @ramanujanSum (P ^ α * m) ⟨hPαm_ne⟩ t = @ramanujanSum (P ^ α) hne_Pα t * @ramanujanSum m hne_m t := ramanujanSum_multiplicative hcop t have hn_rw : ‖@ramanujanSum n _ t‖ = ‖@ramanujanSum (P ^ α * m) ⟨hPαm_ne⟩ t‖ := by congr 2 exact hdecomp.symm calc ‖@ramanujanSum n _ t‖ = ‖@ramanujanSum (P ^ α * m) ⟨hPαm_ne⟩ t‖ := hn_rw _ = ‖@ramanujanSum (P ^ α) hne_Pα t * @ramanujanSum m hne_m t‖ := by rw [h_mult] _ = ‖@ramanujanSum (P ^ α) hne_Pα t‖ * ‖@ramanujanSum m hne_m t‖ := norm_mul _ _ _ = (P : ℝ) ^ (α - 1) * ‖@ramanujanSum m hne_m t‖ := by rw [h_norm_Palpha] _ ≤ (P : ℝ) ^ (α - 1) * (Nat.totient m : ℝ) := by apply mul_le_mul_of_nonneg_left h_norm_m exact pow_nonneg (Nat.cast_nonneg _) _ _ = (Nat.totient n : ℝ) / ((P : ℝ) - 1) := totient_div_prime_minus_one n P α m hPprime hαpos hcop hdecomp lemma sum_split_zero (n : ℕ) [NeZero n] (f : ZMod n → ℝ) : ∑ k : ZMod n, f k = f 0 + ∑ k ∈ (Finset.univ : Finset (ZMod n)).filter (· ≠ 0), f k := by conv_lhs => rw [show (∑ k : ZMod n, f k : ℝ) = ∑ k ∈ Finset.univ, f k from by simp] rw [← Finset.sum_filter_add_sum_filter_not Finset.univ (· = (0 : ZMod n))] simp [show Finset.univ.filter (· = (0 : ZMod n)) = {0} from by ext x; simp] lemma indicator_formula (n : ℕ) [NeZero n] (m : ℕ) (j : ZMod n) (k : ZMod n) : ZMod.stdAddChar (-(j * k)) • intervalIndicator n m j = if j ∈ intervalSet n m then ZMod.stdAddChar (-(j * k)) else 0 := by simp [intervalIndicator, Set.indicator_apply] lemma summand_reindex (n : ℕ) [NeZero n] (m : ℕ) (hm2 : m < n) (k : ZMod n) : ∑ j : ZMod n, (if j ∈ intervalSet n m then ZMod.stdAddChar (-(j * k)) else 0) = ∑ t ∈ Finset.range m, ZMod.stdAddChar (-((t + 1 : ZMod n) * k)) := by rw [← Finset.sum_filter] apply Finset.sum_nbij' (fun j => ZMod.val j - 1) (fun t => ((t + 1 : ℕ) : ZMod n)) · intro j hj simp only [Finset.mem_filter, Finset.mem_univ, true_and, intervalSet, Set.mem_setOf_eq] at hj exact Finset.mem_range.mpr (by omega) · intro t ht have htm : t < m := Finset.mem_range.mp ht simp only [Finset.mem_filter, Finset.mem_univ, true_and, intervalSet, Set.mem_setOf_eq] rw [ZMod.val_natCast_of_lt (by omega : t + 1 < n)] exact ⟨by omega, by omega⟩ · intro j hj simp only [Finset.mem_filter, Finset.mem_univ, true_and, intervalSet, Set.mem_setOf_eq] at hj rw [show ZMod.val j - 1 + 1 = ZMod.val j from by omega] exact ZMod.natCast_zmod_val j · intro t ht have htm : t < m := Finset.mem_range.mp ht rw [ZMod.val_natCast_of_lt (by omega : t + 1 < n)] omega · intro j hj simp only [Finset.mem_filter, Finset.mem_univ, true_and, intervalSet, Set.mem_setOf_eq] at hj have hv : ZMod.val j - 1 + 1 = ZMod.val j := by omega have : (↑(ZMod.val j - 1 + 1 : ℕ) : ZMod n) = j := by rw [hv]; exact ZMod.natCast_zmod_val j simp only [Nat.cast_add, Nat.cast_one] at this rw [show (↑(ZMod.val j - 1) + 1 : ZMod n) = j from this] lemma character_multiplication_simplify (n : ℕ) [NeZero n] (t : ℕ) (k : ZMod n) : ZMod.stdAddChar (-((t + 1 : ZMod n) * k)) = (ZMod.stdAddChar (-k)) ^ (t + 1) := by have h1 : (-((t + 1 : ZMod n) * k) : ZMod n) = (t + 1 : ℕ) • (-k : ZMod n) := by simp [add_smul, one_smul, neg_mul, mul_comm] <;> (try ring_nf) rw [h1] have h2 : ZMod.stdAddChar ((t + 1 : ℕ) • (-k : ZMod n)) = (ZMod.stdAddChar (-k)) ^ (t + 1) := by rw [ZMod.stdAddChar.map_nsmul_eq_pow] rw [h2] lemma dft_intervalIndicator_eq_geom_sum (n : ℕ) [NeZero n] (m : ℕ) (hm2 : m < n) (k : ZMod n) : ZMod.dft (intervalIndicator n m) k = ∑ t ∈ Finset.range m, (ZMod.stdAddChar (-k)) ^ (t + 1) := by rw [ZMod.dft_apply] simp only [indicator_formula] rw [summand_reindex n m hm2 k] exact Finset.sum_congr rfl fun t _ => character_multiplication_simplify n t k lemma exponent_algebra (n : ℕ) [NeZero n] (k : ZMod n) : (2 : ℂ) * ↑Real.pi * Complex.I * ↑(-(↑(ZMod.val k) : ℤ)) / ↑(n : ℕ) = Complex.I * ↑(-2 * Real.pi * (ZMod.val k : ℝ) / (n : ℝ)) := by have h₁ : (2 : ℂ) * ↑Real.pi * Complex.I * ↑(-(↑(ZMod.val k) : ℤ)) / ↑(n : ℕ) = Complex.I * ((-2 : ℝ) * Real.pi * (ZMod.val k : ℝ) / (n : ℝ)) := by field_simp [Complex.ext_iff, pow_one, Complex.ofReal_mul, Complex.ofReal_add, Complex.ofReal_sub, Complex.ofReal_neg, Complex.ofReal_ofNat, Complex.ext_iff, pow_one, Complex.ofReal_mul, Complex.ofReal_add, Complex.ofReal_sub, Complex.ofReal_neg, Complex.ofReal_ofNat] <;> norm_cast <;> ring_nf at * <;> simp_all [Complex.ext_iff, pow_one, Complex.ofReal_mul, Complex.ofReal_add, Complex.ofReal_sub, Complex.ofReal_neg, Complex.ofReal_ofNat] rw [h₁] <;> simp [Complex.ext_iff, pow_one, Complex.ofReal_mul, Complex.ofReal_add, Complex.ofReal_sub, Complex.ofReal_neg, Complex.ofReal_ofNat] lemma stdAddChar_neg_eq_exp (n : ℕ) [NeZero n] (k : ZMod n) : (ZMod.stdAddChar (-k) : ℂ) = Complex.exp (Complex.I * ↑(-2 * Real.pi * (ZMod.val k : ℝ) / (n : ℝ))) := by rw [show -k = (↑(-(↑(ZMod.val k) : ℤ)) : ZMod n) from by simp, ZMod.stdAddChar_coe] congr 1 exact exponent_algebra n k lemma norm_one_sub_stdAddChar_eq (n : ℕ) [NeZero n] (k : ZMod n) : ‖(1 : ℂ) - ZMod.stdAddChar (-k)‖ = 2 * |Real.sin (Real.pi * (ZMod.val k : ℝ) / n)| := by rw [stdAddChar_neg_eq_exp, norm_sub_rev, Complex.norm_exp_I_mul_ofReal_sub_one, show (-2 * Real.pi * (ZMod.val k : ℝ) / (n : ℝ)) / 2 = -(Real.pi * (ZMod.val k : ℝ) / (n : ℝ)) from by ring, Real.sin_neg, mul_neg, Real.norm_eq_abs, abs_neg, abs_mul, abs_of_pos (by positivity : (2 : ℝ) > 0)] lemma abs_bound_helper (n : ℕ) (v : ℝ) (hn : 0 < (n : ℝ)) (hvn : v ≤ n / 2) : Real.pi * v / n ≤ Real.pi / 2 := by have h₁ : (Real.pi : ℝ) * v / n ≤ Real.pi / 2 := by have h₃ : 0 < (n : ℝ) := hn have h₅ : (Real.pi : ℝ) * v / n ≤ (Real.pi : ℝ) * ((n : ℝ) / 2) / n := by calc (Real.pi : ℝ) * v / n = (Real.pi : ℝ) / n * v := by ring _ ≤ (Real.pi : ℝ) / n * ((n : ℝ) / 2) := by gcongr _ = (Real.pi : ℝ) * ((n : ℝ) / 2) / n := by ring have h₆ : (Real.pi : ℝ) * ((n : ℝ) / 2) / n = Real.pi / 2 := by field_simp [h₃.ne'] linarith exact h₁ lemma two_v_div_n_le_abs_sin (n : ℕ) (v : ℝ) (hn : 0 < (n : ℝ)) (hv : 0 < v) (hvn : v ≤ n / 2) : 2 * v / n ≤ |Real.sin (Real.pi * v / n)| := by have h1 : 0 ≤ Real.pi * v / n := by positivity have h2 : |Real.pi * v / n| ≤ Real.pi / 2 := by rw [abs_of_nonneg h1] exact abs_bound_helper n v hn hvn calc 2 * v / n = 2 / Real.pi * |Real.pi * v / n| := by rw [abs_of_nonneg h1]; field_simp [Real.pi_pos.ne', hn.ne'] _ ≤ |Real.sin (Real.pi * v / n)| := Real.mul_abs_le_abs_sin h2 lemma abs_sin_val_eq_abs_sin_complement (n : ℕ) [NeZero n] (k : ZMod n) : |Real.sin (Real.pi * (ZMod.val k : ℝ) / n)| = |Real.sin (Real.pi * ((n : ℝ) - ZMod.val k) / n)| := by have h_angle : Real.pi * ((n : ℝ) - ZMod.val k) / n = Real.pi - Real.pi * (ZMod.val k : ℝ) / n := by have h₁ : (n : ℝ) ≠ 0 := by norm_cast <;> exact_mod_cast NeZero.ne n have h₂ : Real.pi * ((n : ℝ) - ZMod.val k) / n = (Real.pi * (n : ℝ) - Real.pi * (ZMod.val k : ℝ)) / n := by ring_nf rw [h₂] have h₃ : (Real.pi * (n : ℝ) - Real.pi * (ZMod.val k : ℝ)) / n = Real.pi - Real.pi * (ZMod.val k : ℝ) / n := by field_simp [h₁] rw [h₃] have h_sin_eq : Real.sin (Real.pi * ((n : ℝ) - ZMod.val k) / n) = Real.sin (Real.pi * (ZMod.val k : ℝ) / n) := by have h₂ : Real.sin (Real.pi * ((n : ℝ) - ZMod.val k) / n) = Real.sin (Real.pi - Real.pi * (ZMod.val k : ℝ) / n) := by rw [h_angle] rw [h₂] have h₃ : Real.sin (Real.pi - Real.pi * (ZMod.val k : ℝ) / n) = Real.sin (Real.pi * (ZMod.val k : ℝ) / n) := by rw [Real.sin_pi_sub] rw [h₃] have h_abs_eq : |Real.sin (Real.pi * (ZMod.val k : ℝ) / n)| = |Real.sin (Real.pi * ((n : ℝ) - ZMod.val k) / n)| := by rw [h_sin_eq] rw [h_abs_eq] lemma abs_sin_ge_two_min_div (n : ℕ) [NeZero n] (k : ZMod n) (hk : k ≠ 0) : 2 * min (ZMod.val k : ℝ) ((n : ℝ) - ZMod.val k) / n ≤ |Real.sin (Real.pi * (ZMod.val k : ℝ) / n)| := by have hval_pos : 0 < ZMod.val k := Nat.pos_of_ne_zero ((ZMod.val_ne_zero k).mpr hk) have hn_pos : (0 : ℝ) < n := Nat.cast_pos.mpr (NeZero.pos n) have hval_lt : (ZMod.val k : ℝ) < (n : ℝ) := by exact_mod_cast ZMod.val_lt k by_cases hle : 2 * ZMod.val k ≤ n · have hle' : (ZMod.val k : ℝ) ≤ (n : ℝ) - (ZMod.val k : ℝ) := by have : (2 * ZMod.val k : ℝ) ≤ (n : ℝ) := by exact_mod_cast hle linarith rw [min_eq_left hle'] exact two_v_div_n_le_abs_sin n _ hn_pos (by exact_mod_cast hval_pos) (by linarith) · have hgt : (n : ℝ) < 2 * (ZMod.val k : ℝ) := by exact_mod_cast (by omega : n < 2 * ZMod.val k) have hle' : (n : ℝ) - (ZMod.val k : ℝ) ≤ (ZMod.val k : ℝ) := by linarith rw [min_eq_right hle'] rw [abs_sin_val_eq_abs_sin_complement] exact two_v_div_n_le_abs_sin n _ hn_pos (by linarith) (by linarith) lemma geom_sum_shift_eq (r : ℂ) (hr_ne : r ≠ 1) (m : ℕ) : ∑ t ∈ Finset.range m, r ^ (t + 1) = r * (r ^ m - 1) / (r - 1) := by simp_rw [pow_succ'] rw [← Finset.mul_sum, geom_sum_eq hr_ne, mul_div_assoc] lemma norm_pow_sub_one_le_two (r : ℂ) (hr_norm : ‖r‖ = 1) (m : ℕ) : ‖r ^ m - 1‖ ≤ 2 := by have h1 : ‖r ^ m‖ = 1 := by simp_all have h2 : ‖(1 : ℂ)‖ = 1 := by simp have h3 : ‖r ^ m - 1‖ ≤ ‖r ^ m‖ + ‖(1 : ℂ)‖ := by exact norm_sub_le _ _ have h4 : ‖r ^ m - 1‖ ≤ 2 := by nlinarith assumption lemma norm_geom_sum_le (r : ℂ) (hr_ne : r ≠ 1) (hr_norm : ‖r‖ = 1) (m : ℕ) : ‖∑ t ∈ Finset.range m, r ^ (t + 1)‖ ≤ 2 / ‖1 - r‖ := by rw [show ‖1 - r‖ = ‖r - 1‖ by rw [norm_sub_rev]] rw [geom_sum_shift_eq r hr_ne m] rw [norm_div, norm_mul, hr_norm, one_mul] exact div_le_div_of_nonneg_right (norm_pow_sub_one_le_two r hr_norm m) (norm_nonneg _) lemma norm_one_sub_stdAddChar_lower_bound (n : ℕ) [NeZero n] (k : ZMod n) (hk : k ≠ 0) : (4 : ℝ) * min (ZMod.val k : ℝ) ((n : ℝ) - ZMod.val k) / n ≤ ‖(1 : ℂ) - ZMod.stdAddChar (-k)‖ := by rw [norm_one_sub_stdAddChar_eq, show (4 : ℝ) * min (ZMod.val k : ℝ) ((n : ℝ) - ZMod.val k) / n = 2 * (2 * min (ZMod.val k : ℝ) ((n : ℝ) - ZMod.val k) / n) from by ring] exact mul_le_mul_of_nonneg_left (abs_sin_ge_two_min_div n k hk) (by norm_num) lemma stdAddChar_ne_one (n : ℕ) [NeZero n] (k : ZMod n) (hk : k ≠ 0) : ZMod.stdAddChar (-k) ≠ 1 := by have h_neg_k_ne_zero : -k ≠ 0 := by simp_all have h_primitive : (ZMod.stdAddChar : AddChar (ZMod n) ℂ).IsPrimitive := by exact ZMod.isPrimitive_stdAddChar n exact fun h_eq => h_neg_k_ne_zero ((h_primitive.zmod_char_eq_one_iff n (-k)).mp h_eq) lemma norm_stdAddChar_eq_one (n : ℕ) [NeZero n] (k : ZMod n) : ‖ZMod.stdAddChar (-k : ZMod n)‖ = 1 := by have h_main : ‖ZMod.stdAddChar (-k : ZMod n)‖ = 1 := by simp assumption lemma normalizedDFT_intervalIndicator_nonzero_bound (n : ℕ) [NeZero n] (m : ℕ) (_hm1 : 1 ≤ m) (hm2 : m < n) (k : ZMod n) (hk : k ≠ 0) : ‖normalizedDFT n (intervalIndicator n m) k‖ ≤ 1 / (2 * (min (ZMod.val k) (n - ZMod.val k) : ℝ)) := by unfold normalizedDFT rw [norm_mul, norm_inv, Complex.norm_natCast] rw [dft_intervalIndicator_eq_geom_sum n m hm2 k] have h_geom := norm_geom_sum_le (ZMod.stdAddChar (-k)) (stdAddChar_ne_one n k hk) (norm_stdAddChar_eq_one n k) m have h_lower := norm_one_sub_stdAddChar_lower_bound n k hk have h_pos : (0 : ℝ) < ‖(1 : ℂ) - ZMod.stdAddChar (-k)‖ := by have h_ne : (1 : ℂ) - ZMod.stdAddChar (-k) ≠ 0 := by intro h rw [sub_eq_zero] at h exact stdAddChar_ne_one n k hk h.symm exact norm_pos_iff.mpr h_ne have hn_pos : (0 : ℝ) < n := Nat.cast_pos.mpr (Nat.pos_of_ne_zero (NeZero.ne n)) have h_min_pos : (0 : ℝ) < min (ZMod.val k : ℝ) ((n : ℝ) - ZMod.val k) := lt_min (by exact_mod_cast Nat.pos_of_ne_zero ((ZMod.val_ne_zero k).mpr hk)) (sub_pos.mpr (Nat.cast_lt.mpr (ZMod.val_lt k))) calc (n : ℝ)⁻¹ * ‖∑ t ∈ Finset.range m, ZMod.stdAddChar (-k) ^ (t + 1)‖ ≤ (n : ℝ)⁻¹ * (2 / ‖(1 : ℂ) - ZMod.stdAddChar (-k)‖) := by nlinarith [inv_pos.mpr hn_pos, h_geom] _ = 2 / ((n : ℝ) * ‖(1 : ℂ) - ZMod.stdAddChar (-k)‖) := by field_simp [hn_pos.ne', h_pos.ne'] _ ≤ 1 / (2 * min (ZMod.val k : ℝ) ((n : ℝ) - ZMod.val k)) := by rw [div_le_div_iff₀ (by positivity) (by positivity)] nlinarith [show 4 * min (ZMod.val k : ℝ) ((n : ℝ) - ZMod.val k) / (n : ℝ) * (n : ℝ) = 4 * min (ZMod.val k : ℝ) ((n : ℝ) - ZMod.val k) from by field_simp [hn_pos.ne']] lemma sum_nonzero_reindex (n : ℕ) [NeZero n] (hn : 2 ≤ n) : ∑ k ∈ (Finset.univ : Finset (ZMod n)).filter (· ≠ 0), (1 : ℝ) / (2 * min (ZMod.val k : ℝ) ((n : ℝ) - ZMod.val k)) = ∑ t ∈ Finset.Icc 1 (n - 1), (1 : ℝ) / (2 * min (t : ℝ) ((n : ℝ) - t)) := by apply Finset.sum_nbij ZMod.val · intro k hk have hk' := (Finset.mem_filter.mp hk).2 have h1 := ZMod.val_lt k have h2 : ZMod.val k ≠ 0 := (ZMod.val_ne_zero k).mpr hk' exact Finset.mem_Icc.mpr ⟨by omega, by omega⟩ · exact fun _ _ _ _ h => ZMod.val_injective n h · intro y hy simp only [Finset.coe_Icc, Set.mem_Icc] at hy have h1 : y < n := by omega refine ⟨(y : ZMod n), ?_, ZMod.val_cast_of_lt (by omega)⟩ simp only [Finset.coe_filter, Finset.mem_univ, true_and, Set.mem_setOf_eq] intro h have hvy : ZMod.val (y : ZMod n) = y := ZMod.val_cast_of_lt (by omega) rw [h, ZMod.val_zero] at hvy omega · intros; rfl lemma first_half_eq (N : ℕ) (hN : 1 ≤ N) : ∑ t ∈ Finset.Icc 1 N, (1 : ℝ) / (2 * min (t : ℝ) ((2 * N + 1 : ℝ) - t)) = ∑ t ∈ Finset.Icc 1 N, (1 : ℝ) / (2 * t) := by have h₁ : ∀ (t : ℕ), t ∈ Finset.Icc 1 N → (t : ℝ) ≤ (2 * N + 1 : ℝ) - (t : ℝ) := by intro t ht have h₃ : t ≤ N := by simp [Finset.mem_Icc] at ht linarith have h₄ : (t : ℝ) ≤ (N : ℝ) := by exact_mod_cast h₃ have h₆ : (t : ℝ) ≤ (2 * N + 1 : ℝ) - (t : ℝ) := by nlinarith exact h₆ have h₂ : ∀ (t : ℕ), t ∈ Finset.Icc 1 N → min ((t : ℝ)) ((2 * N + 1 : ℝ) - (t : ℝ)) = (t : ℝ) := by intro t ht have h₃ : (t : ℝ) ≤ (2 * N + 1 : ℝ) - (t : ℝ) := h₁ t ht have h₄ : min ((t : ℝ)) ((2 * N + 1 : ℝ) - (t : ℝ)) = (t : ℝ) := by rw [min_eq_left] <;> (try linarith) exact h₄ calc ∑ t ∈ Finset.Icc 1 N, (1 : ℝ) / (2 * min (t : ℝ) ((2 * N + 1 : ℝ) - t)) = ∑ t ∈ Finset.Icc 1 N, (1 : ℝ) / (2 * (t : ℝ)) := by apply Finset.sum_congr rfl intro t ht have h₃ : min ((t : ℝ)) ((2 * N + 1 : ℝ) - (t : ℝ)) = (t : ℝ) := h₂ t ht rw [h₃] _ = ∑ t ∈ Finset.Icc 1 N, (1 : ℝ) / (2 * t) := by simp [mul_comm] lemma summand_min_eq (N : ℕ) (hN : 1 ≤ N) (t : ℕ) (ht : t ∈ Finset.Icc (N + 1) (2 * N)) : (1 : ℝ) / (2 * min (t : ℝ) ((2 * N + 1 : ℝ) - t)) = (1 : ℝ) / (2 * ((2 * N + 1 : ℝ) - t)) := by have h₁ : (N + 1 : ℕ) ≤ t := by simp [Finset.mem_Icc] at ht exact ht.1 have h₃ : (2 * N + 1 : ℝ) - t ≤ (t : ℝ) := by have h₄ : (t : ℝ) ≥ (N + 1 : ℝ) := by norm_cast linarith have h₄ : min (t : ℝ) ((2 * N + 1 : ℝ) - t) = (2 * N + 1 : ℝ) - t := by apply min_eq_right linarith rw [h₄] lemma second_half_min_simplify (N : ℕ) (hN : 1 ≤ N) : ∑ t ∈ Finset.Icc (N + 1) (2 * N), (1 : ℝ) / (2 * min (t : ℝ) ((2 * N + 1 : ℝ) - t)) = ∑ t ∈ Finset.Icc (N + 1) (2 * N), (1 : ℝ) / (2 * ((2 * N + 1 : ℝ) - t)) := by exact Finset.sum_congr rfl fun t ht => summand_min_eq N hN t ht lemma second_half_reindex (N : ℕ) (hN : 1 ≤ N) : ∑ t ∈ Finset.Icc (N + 1) (2 * N), (1 : ℝ) / (2 * ((2 * N + 1 : ℝ) - t)) = ∑ u ∈ Finset.Icc 1 N, (1 : ℝ) / (2 * u) := by exact Finset.sum_nbij' (fun t => 2 * N + 1 - t) (fun u => 2 * N + 1 - u) (by simp only [Finset.mem_Icc]; omega) (by simp only [Finset.mem_Icc]; omega) (by simp only [Finset.mem_Icc]; omega) (by simp only [Finset.mem_Icc]; omega) (fun t ht => by congr 2 push_cast [Nat.cast_sub (by simp only [Finset.mem_Icc] at ht; omega : t ≤ 2 * N + 1)] ring) lemma second_half_eq (N : ℕ) (hN : 1 ≤ N) : ∑ t ∈ Finset.Icc (N + 1) (2 * N), (1 : ℝ) / (2 * min (t : ℝ) ((2 * N + 1 : ℝ) - t)) = ∑ u ∈ Finset.Icc 1 N, (1 : ℝ) / (2 * u) := by rw [second_half_min_simplify N hN] exact second_half_reindex N hN lemma combine_halves (N : ℕ) : ∑ u ∈ Finset.Icc 1 N, (1 : ℝ) / (2 * u) + ∑ u ∈ Finset.Icc 1 N, (1 : ℝ) / (2 * u) = ∑ u ∈ Finset.Icc 1 N, (u : ℝ)⁻¹ := by have h₁ : ∑ u ∈ Finset.Icc 1 N, (1 : ℝ) / (2 * u) + ∑ u ∈ Finset.Icc 1 N, (1 : ℝ) / (2 * u) = 2 * ∑ u ∈ Finset.Icc 1 N, (1 : ℝ) / (2 * u) := by have h₁₁ : ∑ u ∈ Finset.Icc 1 N, (1 : ℝ) / (2 * u) + ∑ u ∈ Finset.Icc 1 N, (1 : ℝ) / (2 * u) = 2 * ∑ u ∈ Finset.Icc 1 N, (1 : ℝ) / (2 * u) := by ring rw [h₁₁] have h₂ : 2 * ∑ u ∈ Finset.Icc 1 N, (1 : ℝ) / (2 * u) = ∑ u ∈ Finset.Icc 1 N, (u : ℝ)⁻¹ := by have h₂₁ : 2 * ∑ u ∈ Finset.Icc 1 N, (1 : ℝ) / (2 * u) = ∑ u ∈ Finset.Icc 1 N, (2 : ℝ) * ((1 : ℝ) / (2 * u)) := by rw [Finset.mul_sum] rw [h₂₁] have h₂₂ : ∑ u ∈ Finset.Icc 1 N, (2 : ℝ) * ((1 : ℝ) / (2 * u)) = ∑ u ∈ Finset.Icc 1 N, (1 : ℝ) / u := by apply Finset.sum_congr rfl intro u hu have h₂₂₁ : (u : ℕ) ∈ Finset.Icc 1 N := by simpa using hu have h₂₂₂ : 1 ≤ u := by simp only [Finset.mem_Icc] at h₂₂₁ linarith have h₂₂₃ : (u : ℝ) ≠ 0 := by have h₂₂₄ : (u : ℕ) ≥ 1 := by simp only [Finset.mem_Icc] at h₂₂₁ linarith have h₂₂₅ : (u : ℝ) ≥ 1 := by norm_cast linarith field_simp [h₂₂₃] rw [h₂₂] have h₂₃ : ∑ u ∈ Finset.Icc 1 N, (1 : ℝ) / u = ∑ u ∈ Finset.Icc 1 N, (u : ℝ)⁻¹ := by apply Finset.sum_congr rfl intro u hu have h₂₃₁ : (u : ℕ) ∈ Finset.Icc 1 N := by simpa using hu have h₂₃₂ : 1 ≤ u := by simp only [Finset.mem_Icc] at h₂₃₁ linarith have h₂₃₃ : (u : ℝ) ≠ 0 := by have h₂₃₄ : (u : ℕ) ≥ 1 := by simp only [Finset.mem_Icc] at h₂₃₁ linarith have h₂₃₅ : (u : ℝ) ≥ 1 := by norm_cast linarith field_simp [h₂₃₃] rw [h₂₃] rw [h₁] rw [h₂] lemma symmetric_sum_odd (N : ℕ) (hN : 1 ≤ N) : ∑ t ∈ Finset.Icc 1 (2 * N), (1 : ℝ) / (2 * min (t : ℝ) ((2 * N + 1 : ℝ) - t)) = ∑ u ∈ Finset.Icc 1 N, (u : ℝ)⁻¹ := by rw [show Finset.Icc 1 (2 * N) = Finset.Icc 1 N ∪ Finset.Icc (N + 1) (2 * N) from by ext x; simp only [Finset.mem_union, Finset.mem_Icc]; omega] rw [Finset.sum_union (by simp only [Finset.disjoint_left, Finset.mem_Icc]; omega)] rw [first_half_eq N hN, second_half_eq N hN] exact combine_halves N lemma Icc_split_three (N : ℕ) (hN : 2 ≤ N) : Finset.Icc 1 (2 * N - 1) = Finset.Icc 1 (N - 1) ∪ {N} ∪ Finset.Icc (N + 1) (2 * N - 1) := by have h₂ : Finset.Icc 1 (N - 1) ∪ {N} ∪ Finset.Icc (N + 1) (2 * N - 1) ⊆ Finset.Icc 1 (2 * N - 1) := by intro x hx; simp only [Finset.mem_union, Finset.mem_Icc, Finset.mem_singleton] at hx ⊢; omega have h_main : Finset.Icc 1 (2 * N - 1) = Finset.Icc 1 (N - 1) ∪ {N} ∪ Finset.Icc (N + 1) (2 * N - 1) := by ext x; simp only [Finset.mem_union, Finset.mem_Icc, Finset.mem_singleton]; omega exact h_main lemma Icc_disjoint_high (N : ℕ) (hN : 2 ≤ N) : Disjoint (Finset.Icc 1 (N - 1) ∪ {N}) (Finset.Icc (N + 1) (2 * N - 1)) := by have h₁ : Disjoint (Finset.Icc 1 (N - 1)) (Finset.Icc (N + 1) (2 * N - 1)) := by apply Finset.disjoint_left.mpr intro x hx₁ hx₂ simp only [Finset.mem_Icc] at hx₁ hx₂ have h₇ : N - 1 < N + 1 := by have h₉ : N - 1 < N := by have h₁₀ : N - 1 < N := by omega exact h₁₀ omega omega have h₂ : Disjoint ({N} : Finset ℕ) (Finset.Icc (N + 1) (2 * N - 1)) := by apply Finset.disjoint_left.mpr intro x hx₁ hx₂ simp only [Finset.mem_singleton, Finset.mem_Icc] at hx₁ hx₂ omega have h₃ : Disjoint (Finset.Icc 1 (N - 1) ∪ {N}) (Finset.Icc (N + 1) (2 * N - 1)) := by apply Finset.disjoint_union_left.mpr constructor · exact h₁ · exact h₂ exact h₃ lemma Icc_disjoint_mid (N : ℕ) (hN : 2 ≤ N) : Disjoint (Finset.Icc 1 (N - 1)) ({N} : Finset ℕ) := by have h₁ : ∀ x ∈ Finset.Icc 1 (N - 1), x ≠ N := by intro x hx have h₃ : x ≤ N - 1 := Finset.mem_Icc.mp hx |>.2 have h₄ : x < N := by have h₆ : N - 1 < N := by omega omega omega apply Finset.disjoint_left.mpr intro x hx₁ hx₂ have h₂ : x = N := by simp_all [Finset.mem_singleton] have h₃ : x ∈ Finset.Icc 1 (N - 1) := hx₁ have h₄ : x ≠ N := h₁ x h₃ contradiction lemma sum_region_A (N : ℕ) (hN : 2 ≤ N) : ∑ t ∈ Finset.Icc 1 (N - 1), (1 : ℝ) / (2 * min (t : ℝ) ((2 * N : ℝ) - t)) = ∑ t ∈ Finset.Icc 1 (N - 1), (1 : ℝ) / (2 * (t : ℝ)) := by have h_main : ∀ (t : ℕ), t ∈ Finset.Icc 1 (N - 1) → (1 : ℝ) / (2 * min (t : ℝ) ((2 * N : ℝ) - t)) = (1 : ℝ) / (2 * (t : ℝ)) := by intro t ht have h₁ : 1 ≤ t ∧ t ≤ N - 1 := Finset.mem_Icc.mp ht have h₄ : (t : ℕ) < N := by have h₆ : N - 1 < N := by omega omega have h₅ : (t : ℝ) ≤ (2 * N : ℝ) - t := by have h₆ : (t : ℝ) ≤ (N : ℝ) := by exact_mod_cast (by omega) linarith have h₆ : min (t : ℝ) ((2 * N : ℝ) - t) = (t : ℝ) := by rw [min_eq_left h₅] rw [h₆] calc ∑ t ∈ Finset.Icc 1 (N - 1), (1 : ℝ) / (2 * min (t : ℝ) ((2 * N : ℝ) - t)) = ∑ t ∈ Finset.Icc 1 (N - 1), (1 : ℝ) / (2 * (t : ℝ)) := by apply Finset.sum_congr rfl intro t ht rw [h_main t ht] _ = ∑ t ∈ Finset.Icc 1 (N - 1), (1 : ℝ) / (2 * (t : ℝ)) := by rfl lemma min_midpoint (N : ℕ) : min (N : ℝ) ((2 * N : ℝ) - N) = (N : ℝ) := by have h₁ : (2 * (N : ℝ) - N : ℝ) = (N : ℝ) := by ring_nf rw [h₁] <;> simp [min_eq_left] lemma min_eq_complement_in_region_C (N : ℕ) (t : ℕ) (ht : t ∈ Finset.Icc (N + 1) (2 * N - 1)) : min (t : ℝ) ((2 * N : ℝ) - t) = (2 * N : ℝ) - t := by have h₂ : (t : ℕ) ≥ N + 1 := by simp [Finset.mem_Icc] at ht exact ht.1 have h₅ : ((2 * N : ℝ) - (t : ℝ)) ≤ (t : ℝ) := by have h₅₁ : (t : ℝ) ≥ (N : ℝ) + 1 := by exact_mod_cast (by omega) have h₅₂ : ((2 : ℝ) * N - (t : ℝ)) ≤ (t : ℝ) := by have h₅₃ : (2 : ℝ) * N - (t : ℝ) ≤ (t : ℝ) := by nlinarith exact h₅₃ exact h₅₂ have h₆ : min (t : ℝ) ((2 * N : ℝ) - (t : ℝ)) = (2 * N : ℝ) - (t : ℝ) := by apply min_eq_right <;> simp_all [h₅] simpa using h₆ lemma sum_region_C (N : ℕ) (hN : 2 ≤ N) : ∑ t ∈ Finset.Icc (N + 1) (2 * N - 1), (1 : ℝ) / (2 * min (t : ℝ) ((2 * N : ℝ) - t)) = ∑ u ∈ Finset.Icc 1 (N - 1), (1 : ℝ) / (2 * (u : ℝ)) := by have step1 : ∑ t ∈ Finset.Icc (N + 1) (2 * N - 1), (1 : ℝ) / (2 * min (t : ℝ) ((2 * N : ℝ) - t)) = ∑ t ∈ Finset.Icc (N + 1) (2 * N - 1), (1 : ℝ) / (2 * ((2 * N : ℝ) - t)) := Finset.sum_congr rfl fun t ht => by rw [min_eq_complement_in_region_C N t ht] rw [step1] exact Finset.sum_nbij' (fun t => 2 * N - t) (fun u => 2 * N - u) (by simp only [Finset.mem_Icc]; omega) (by simp only [Finset.mem_Icc]; omega) (by simp only [Finset.mem_Icc]; omega) (by simp only [Finset.mem_Icc]; omega) (fun t ht => by congr 2 push_cast [Nat.cast_sub (by simp only [Finset.mem_Icc] at ht; omega : t ≤ 2 * N)] ring) lemma symmetric_sum_even (N : ℕ) (hN : 1 ≤ N) : ∑ t ∈ Finset.Icc 1 (2 * N - 1), (1 : ℝ) / (2 * min (t : ℝ) ((2 * N : ℝ) - t)) = (∑ u ∈ Finset.Icc 1 (N - 1), (u : ℝ)⁻¹) + 1 / (2 * N) := by obtain rfl | hN2 := eq_or_lt_of_le hN · norm_num · rw [Icc_split_three N hN2, Finset.sum_union (Icc_disjoint_high N hN2), Finset.sum_union (Icc_disjoint_mid N hN2), Finset.sum_singleton, min_midpoint N, sum_region_A N hN2, sum_region_C N hN2] linarith [combine_halves (N - 1)] lemma ratio_rewrite (u : ℕ) (hu : 1 ≤ u) : (2 * (u : ℝ) + 1) / (2 * u - 1) = 1 + 2 / (2 * u - 1) := by have h₁ : (u : ℝ) ≥ 1 := by exact_mod_cast hu have h₂ : (2 : ℝ) * u - 1 > 0 := by linarith have h₃ : (2 : ℝ) * (u : ℝ) + 1 = 1 * ((2 : ℝ) * u - 1) + 2 := by ring_nf have h₄ : (2 * (u : ℝ) + 1) / (2 * u - 1) = 1 + 2 / (2 * u - 1) := by have h₅ : (2 * (u : ℝ) + 1) / (2 * u - 1) = (1 * ((2 : ℝ) * u - 1) + 2) / (2 * u - 1) := by rw [h₃] rw [h₅] have h₆ : (1 * ((2 : ℝ) * u - 1) + 2) / (2 * u - 1) = 1 + 2 / (2 * u - 1) := by have h₇ : (2 * u - 1 : ℝ) ≠ 0 := by linarith field_simp [h₇] rw [h₆] exact h₄ lemma pade_algebraic_identity (u : ℕ) (hu : 1 ≤ u) : 2 * (2 / (2 * (u : ℝ) - 1)) / (2 / (2 * u - 1) + 2) = (u : ℝ)⁻¹ := by have h₁ : (u : ℝ) ≥ 1 := by simp_all have h₂ : (2 : ℝ) * (u : ℝ) - 1 ≠ 0 := by nlinarith have h₃ : 2 * (2 / (2 * (u : ℝ) - 1)) / (2 / (2 * (u : ℝ) - 1) + 2) = (u : ℝ)⁻¹ := by field_simp; ring assumption lemma inv_le_log_ratio (u : ℕ) (hu : 1 ≤ u) : (u : ℝ)⁻¹ ≤ Real.log ((2 * u + 1) / (2 * u - 1)) := by have h1 : (2 : ℝ) * u - 1 > 0 := by have : (1 : ℝ) ≤ (u : ℝ) := Nat.one_le_cast.mpr hu linarith rw [ratio_rewrite u hu, ← pade_algebraic_identity u hu] exact le_of_lt (Real.lt_log_one_add_of_pos (by positivity : (0 : ℝ) < 2 / (2 * u - 1))) lemma telescoping_log_sum (N : ℕ) (hN : 1 ≤ N) : ∑ u ∈ Finset.Icc 1 N, Real.log ((2 * (u : ℝ) + 1) / (2 * u - 1)) = Real.log (2 * N + 1) := by have h : ∀ (n : ℕ), 1 ≤ n → ∑ u ∈ Finset.Icc 1 n, Real.log ((2 * (u : ℝ) + 1) / (2 * u - 1)) = Real.log (2 * n + 1) := by intro n hn induction' hn with n hn IH · norm_num [Finset.sum_Icc_succ_top] · rw [Finset.sum_Icc_succ_top (by omega : 1 ≤ n.succ)] rw [IH] have h₁ : (n : ℝ) ≥ 1 := by exact_mod_cast hn have h₂ : (2 * (n : ℝ) + 1 : ℝ) > 0 := by linarith have h₃ : (2 * (n : ℝ) - 1 : ℝ) > 0 := by linarith have h₄ : (2 * (n.succ : ℝ) + 1 : ℝ) > 0 := by positivity have h₅ : (2 * (n.succ : ℝ) - 1 : ℝ) > 0 := by have h₆ : (n : ℝ) ≥ 1 := by exact_mod_cast hn norm_num [Nat.cast_add, Nat.cast_one] at h₆ ⊢ <;> linarith have h₆ : Real.log ((2 * (n.succ : ℝ) + 1) / (2 * (n.succ : ℝ) - 1)) = Real.log (2 * (n.succ : ℝ) + 1) - Real.log (2 * (n : ℝ) + 1) := by have h₇ : (2 * (n.succ : ℝ) + 1 : ℝ) = (2 * (n : ℝ) + 3 : ℝ) := by norm_num [Nat.cast_add, Nat.cast_one] <;> ring_nf have h₈ : (2 * (n.succ : ℝ) - 1 : ℝ) = (2 * (n : ℝ) + 1 : ℝ) := by norm_num [Nat.cast_add, Nat.cast_one] <;> ring_nf rw [h₇, h₈] have h₉ : Real.log ((2 * (n : ℝ) + 3 : ℝ) / (2 * (n : ℝ) + 1 : ℝ)) = Real.log (2 * (n : ℝ) + 3) - Real.log (2 * (n : ℝ) + 1) := by have h₁₂ : Real.log ((2 * (n : ℝ) + 3 : ℝ) / (2 * (n : ℝ) + 1 : ℝ)) = Real.log (2 * (n : ℝ) + 3) - Real.log (2 * (n : ℝ) + 1) := by rw [Real.log_div (by linarith) (by linarith)] rw [h₁₂] have h₁₀ : Real.log (2 * (n : ℝ) + 3) = Real.log (2 * (n.succ : ℝ) + 1) := by norm_num [Nat.cast_add, Nat.cast_one] at * <;> ring_nf at * rw [h₉, h₁₀] have h₇ : Real.log (2 * (n : ℝ) + 1) + Real.log ((2 * (n.succ : ℝ) + 1) / (2 * (n.succ : ℝ) - 1)) = Real.log (2 * (n.succ : ℝ) + 1) := by rw [h₆] linarith rw [h₇] have h₁ : ∑ u ∈ Finset.Icc 1 N, Real.log ((2 * (u : ℝ) + 1) / (2 * u - 1)) = Real.log (2 * N + 1) := by exact h N hN exact h₁ lemma harmonic_Icc_le_log_odd (N : ℕ) (hN : 1 ≤ N) : ∑ u ∈ Finset.Icc 1 N, (u : ℝ)⁻¹ ≤ Real.log (2 * N + 1) := by calc ∑ u ∈ Finset.Icc 1 N, (u : ℝ)⁻¹ ≤ ∑ u ∈ Finset.Icc 1 N, Real.log ((2 * (u : ℝ) + 1) / (2 * u - 1)) := Finset.sum_le_sum fun u hu => inv_le_log_ratio u (Finset.mem_Icc.mp hu).1 _ = Real.log (2 * N + 1) := telescoping_log_sum N hN lemma one_sub_inv_ratio_eq (N : ℕ) (hN : 1 ≤ N) : 1 - (2 * (N : ℝ) / (2 * N - 1))⁻¹ = 1 / (2 * N) := by have h₁ : (2 : ℝ) * (N : ℝ) - 1 > 0 := by have h₁ : (N : ℝ) ≥ 1 := by exact_mod_cast hN linarith have h₂ : (2 : ℝ) * (N : ℝ) > 0 := by linarith have h₃ : (2 * (N : ℝ) / (2 * N - 1))⁻¹ = (2 * N - 1 : ℝ) / (2 * N : ℝ) := by have h₃ : (2 * (N : ℝ) / (2 * N - 1))⁻¹ = (2 * N - 1 : ℝ) / (2 * N : ℝ) := by field_simp [h₁.ne', h₂.ne'] rw [h₃] calc 1 - (2 * (N : ℝ) / (2 * N - 1))⁻¹ = 1 - ((2 * N - 1 : ℝ) / (2 * N : ℝ)) := by rw [h₃] _ = 1 / (2 * N : ℝ) := by have h₄ : (2 * N : ℝ) ≠ 0 := by positivity have h₅ : (2 * N - 1 : ℝ) / (2 * N : ℝ) = 1 - 1 / (2 * N : ℝ) := by field_simp [h₄] rw [h₅] <;> ring_nf lemma inv_two_N_le_log_ratio (N : ℕ) (hN : 1 ≤ N) : 1 / (2 * (N : ℝ)) ≤ Real.log (2 * N / (2 * N - 1)) := by rw [← one_sub_inv_ratio_eq N hN] apply Real.one_sub_inv_le_log_of_pos have hN' : (1 : ℝ) ≤ (N : ℝ) := Nat.one_le_cast.mpr hN have h2N1 : (0 : ℝ) < 2 * N - 1 := by linarith exact div_pos (by linarith) h2N1 lemma half_le_log_two : (1 : ℝ) / 2 ≤ Real.log 2 := by have := Real.log_two_gt_d9 norm_num at this ⊢ <;> linarith lemma harmonic_Icc_plus_remainder_le_log_even (N : ℕ) (hN : 1 ≤ N) : (∑ u ∈ Finset.Icc 1 (N - 1), (u : ℝ)⁻¹) + 1 / (2 * N) ≤ Real.log (2 * N) := by rcases eq_or_lt_of_le hN with rfl | hN2 · simp have := half_le_log_two linarith · calc (∑ u ∈ Finset.Icc 1 (N - 1), (u : ℝ)⁻¹) + 1 / (2 * N) ≤ Real.log (2 * ↑(N - 1) + 1) + Real.log (2 * N / (2 * N - 1)) := by gcongr · exact harmonic_Icc_le_log_odd (N - 1) (by omega) · exact inv_two_N_le_log_ratio N (by omega) _ = Real.log (2 * N) := by rw [show (2 : ℝ) * ↑(N - 1) + 1 = 2 * ↑N - 1 from by push_cast [Nat.cast_sub (by omega : 1 ≤ N)] ring] have hpos : (2 : ℝ) * N - 1 > 0 := by linarith [show (2 : ℝ) ≤ (N : ℝ) from by exact_mod_cast hN2] rw [← Real.log_mul (by linarith) (by positivity)] congr 1 field_simp lemma symmetric_harmonic_sum_le_log (n : ℕ) (hn : 2 ≤ n) : ∑ t ∈ Finset.Icc 1 (n - 1), (1 : ℝ) / (2 * min (t : ℝ) ((n : ℝ) - t)) ≤ Real.log n := by obtain ⟨N, hN | hN⟩ := Nat.even_or_odd' n · have hN1 : 1 ≤ N := by omega subst hN simp only [Nat.cast_mul, Nat.cast_ofNat] calc ∑ t ∈ Finset.Icc 1 (2 * N - 1), (1 : ℝ) / (2 * min (t : ℝ) (2 * ↑N - t)) = (∑ u ∈ Finset.Icc 1 (N - 1), (u : ℝ)⁻¹) + 1 / (2 * N) := symmetric_sum_even N hN1 _ ≤ Real.log (2 * N) := harmonic_Icc_plus_remainder_le_log_even N hN1 · have hN1 : 1 ≤ N := by omega subst hN simp only [Nat.cast_add, Nat.cast_mul, Nat.cast_ofNat, Nat.cast_one] rw [show 2 * N + 1 - 1 = 2 * N from by omega] calc ∑ t ∈ Finset.Icc 1 (2 * N), (1 : ℝ) / (2 * min (t : ℝ) (2 * ↑N + 1 - t)) _ = ∑ u ∈ Finset.Icc 1 N, (u : ℝ)⁻¹ := symmetric_sum_odd N hN1 _ ≤ Real.log (2 * N + 1) := harmonic_Icc_le_log_odd N hN1 lemma fourier_intervalIndicator_l1_bound (n : ℕ) [NeZero n] (hn : 2 ≤ n) (m : ℕ) (hm1 : 1 ≤ m) (hm2 : m < n) : ∑ k : ZMod n, ‖normalizedDFT n (intervalIndicator n m) k‖ ≤ 1 + Real.log (n : ℝ) := by rw [sum_split_zero] have h0 : ‖normalizedDFT n (intervalIndicator n m) 0‖ ≤ 1 := by rw [normalizedDFT_intervalIndicator_zero n m hm1 hm2, Complex.norm_div, Complex.norm_natCast, Complex.norm_natCast, div_le_one (by exact_mod_cast Nat.pos_of_ne_zero (NeZero.ne n))] exact_mod_cast hm2.le have h_nonzero : ∑ k ∈ (Finset.univ : Finset (ZMod n)).filter (· ≠ 0), ‖normalizedDFT n (intervalIndicator n m) k‖ ≤ ∑ k ∈ (Finset.univ : Finset (ZMod n)).filter (· ≠ 0), (1 : ℝ) / (2 * min (ZMod.val k : ℝ) ((n : ℝ) - ZMod.val k)) := by apply Finset.sum_le_sum intro k hk exact normalizedDFT_intervalIndicator_nonzero_bound n m hm1 hm2 k (by simpa using hk) linarith [sum_nonzero_reindex n hn, symmetric_harmonic_sum_le_log n hn] lemma summand_norm_bound (n : ℕ) [NeZero n] (hn : 2 ≤ n) (p q : ℤ) (k l : ZMod n) : ‖(if (k, l) ≠ (0, 0) ∧ (↑(largestPrimeFactor n ^ (n.factorization (largestPrimeFactor n) - 1)) : ℤ) ∣ (↑(ZMod.val k) * p + ↑(ZMod.val l) * q) ∧ ¬((↑(largestPrimeFactor n ^ n.factorization (largestPrimeFactor n)) : ℤ) ∣ (↑(ZMod.val k) * p + ↑(ZMod.val l) * q)) then normalizedDFT n (intervalIndicator n (2 * p - 1).toNat) k * normalizedDFT n (intervalIndicator n (2 * q - 1).toNat) l * ramanujanSum n (↑(ZMod.val k) * p + ↑(ZMod.val l) * q) else 0 : ℂ)‖ ≤ (Nat.totient n : ℝ) / ((largestPrimeFactor n : ℝ) - 1) * (‖normalizedDFT n (intervalIndicator n (2 * p - 1).toNat) k‖ * ‖normalizedDFT n (intervalIndicator n (2 * q - 1).toNat) l‖) := by by_cases hcond : (k, l) ≠ (0, 0) ∧ (↑(largestPrimeFactor n ^ (n.factorization (largestPrimeFactor n) - 1)) : ℤ) ∣ (↑(ZMod.val k) * p + ↑(ZMod.val l) * q) ∧ ¬((↑(largestPrimeFactor n ^ n.factorization (largestPrimeFactor n)) : ℤ) ∣ (↑(ZMod.val k) * p + ↑(ZMod.val l) * q)) · rw [if_pos hcond] have hP0 := hcond.2.1 have hd := hcond.2.2 calc ‖normalizedDFT n (intervalIndicator n (2 * p - 1).toNat) k * normalizedDFT n (intervalIndicator n (2 * q - 1).toNat) l * ramanujanSum n (↑(ZMod.val k) * p + ↑(ZMod.val l) * q)‖ = ‖normalizedDFT n (intervalIndicator n (2 * p - 1).toNat) k‖ * ‖normalizedDFT n (intervalIndicator n (2 * q - 1).toNat) l‖ * ‖ramanujanSum n (↑(ZMod.val k) * p + ↑(ZMod.val l) * q)‖ := by rw [norm_mul, norm_mul] _ ≤ ‖normalizedDFT n (intervalIndicator n (2 * p - 1).toNat) k‖ * ‖normalizedDFT n (intervalIndicator n (2 * q - 1).toNat) l‖ * ((Nat.totient n : ℝ) / ((largestPrimeFactor n : ℝ) - 1)) := by gcongr exact ramanujanSum_EP0_norm_bound n hn _ hP0 hd _ = (Nat.totient n : ℝ) / ((largestPrimeFactor n : ℝ) - 1) * (‖normalizedDFT n (intervalIndicator n (2 * p - 1).toNat) k‖ * ‖normalizedDFT n (intervalIndicator n (2 * q - 1).toNat) l‖) := by ring · rw [if_neg hcond, norm_zero] have hP := largestPrimeFactor_ge_two n hn apply mul_nonneg · apply div_nonneg (Nat.cast_nonneg' _) have : (2 : ℝ) ≤ (largestPrimeFactor n : ℝ) := by exact_mod_cast hP linarith · exact mul_nonneg (norm_nonneg _) (norm_nonneg _) lemma norm_errorTermEP0_le_double_sum (n : ℕ) [NeZero n] (hn : 2 ≤ n) (p q : ℤ) (hp : 1 ≤ p) (hq : 1 ≤ q) (hpq : (p : ℝ) + (q : ℝ) < (n : ℝ) / 2) : ‖errorTermEP0 n p q‖ ≤ (Nat.totient n : ℝ) / ((largestPrimeFactor n : ℝ) - 1) * (∑ k : ZMod n, ∑ l : ZMod n, ‖normalizedDFT n (intervalIndicator n (2 * p - 1).toNat) k‖ * ‖normalizedDFT n (intervalIndicator n (2 * q - 1).toNat) l‖) := by have h_tri : ‖errorTermEP0 n p q‖ ≤ ∑ k : ZMod n, ∑ l : ZMod n, ‖(if (k, l) ≠ (0, 0) ∧ (↑(largestPrimeFactor n ^ (n.factorization (largestPrimeFactor n) - 1)) : ℤ) ∣ (↑(ZMod.val k) * p + ↑(ZMod.val l) * q) ∧ ¬((↑(largestPrimeFactor n ^ n.factorization (largestPrimeFactor n)) : ℤ) ∣ (↑(ZMod.val k) * p + ↑(ZMod.val l) * q)) then normalizedDFT n (intervalIndicator n (2 * p - 1).toNat) k * normalizedDFT n (intervalIndicator n (2 * q - 1).toNat) l * ramanujanSum n (↑(ZMod.val k) * p + ↑(ZMod.val l) * q) else 0 : ℂ)‖ := by unfold errorTermEP0 simp only exact (norm_sum_le ..).trans (Finset.sum_le_sum fun k _ => norm_sum_le ..) calc ‖errorTermEP0 n p q‖ ≤ ∑ k : ZMod n, ∑ l : ZMod n, _ := h_tri _ ≤ ∑ k : ZMod n, ∑ l : ZMod n, ((Nat.totient n : ℝ) / ((largestPrimeFactor n : ℝ) - 1) * (‖normalizedDFT n (intervalIndicator n (2 * p - 1).toNat) k‖ * ‖normalizedDFT n (intervalIndicator n (2 * q - 1).toNat) l‖)) := Finset.sum_le_sum fun k _ => Finset.sum_le_sum fun l _ => summand_norm_bound n hn p q k l _ = (Nat.totient n : ℝ) / ((largestPrimeFactor n : ℝ) - 1) * (∑ k : ZMod n, ∑ l : ZMod n, ‖normalizedDFT n (intervalIndicator n (2 * p - 1).toNat) k‖ * ‖normalizedDFT n (intervalIndicator n (2 * q - 1).toNat) l‖) := by simp_rw [Finset.mul_sum] lemma norm_errorTermEP0_le_product (n : ℕ) [NeZero n] (hn : 2 ≤ n) (p q : ℤ) (hp : 1 ≤ p) (hq : 1 ≤ q) (hpq : (p : ℝ) + (q : ℝ) < (n : ℝ) / 2) : ‖errorTermEP0 n p q‖ ≤ (Nat.totient n : ℝ) / ((largestPrimeFactor n : ℝ) - 1) * (∑ k : ZMod n, ‖normalizedDFT n (intervalIndicator n (2 * p - 1).toNat) k‖) * (∑ l : ZMod n, ‖normalizedDFT n (intervalIndicator n (2 * q - 1).toNat) l‖) := by have h1 := norm_errorTermEP0_le_double_sum n hn p q hp hq hpq rw [double_sum_norms_eq_product] at h1 linarith lemma norm_errorTermEP0_le (n : ℕ) [NeZero n] (hn : 2 ≤ n) (p q : ℤ) (hp : 1 ≤ p) (hq : 1 ≤ q) (hpq : (p : ℝ) + (q : ℝ) < (n : ℝ) / 2) : ‖errorTermEP0 n p q‖ ≤ (Nat.totient n : ℝ) * (1 + Real.log (n : ℝ)) ^ 2 / ((largestPrimeFactor n : ℝ) - 1) := by have h1 := norm_errorTermEP0_le_product n hn p q hp hq hpq have hmp := mp_valid n hn p q hp hq hpq have hmq := mq_valid n hn p q hp hq hpq have h2p := fourier_intervalIndicator_l1_bound n hn (2 * p - 1).toNat hmp.1 hmp.2 have h2q := fourier_intervalIndicator_l1_bound n hn (2 * q - 1).toNat hmq.1 hmq.2 have hP := largestPrimeFactor_ge_two n hn have hP_pos : (0 : ℝ) < (largestPrimeFactor n : ℝ) - 1 := by have : (2 : ℝ) ≤ (largestPrimeFactor n : ℝ) := by exact_mod_cast hP linarith calc ‖errorTermEP0 n p q‖ ≤ (Nat.totient n : ℝ) / ((largestPrimeFactor n : ℝ) - 1) * (∑ k : ZMod n, ‖normalizedDFT n (intervalIndicator n (2 * p - 1).toNat) k‖) * (∑ l : ZMod n, ‖normalizedDFT n (intervalIndicator n (2 * q - 1).toNat) l‖) := h1 _ ≤ (Nat.totient n : ℝ) / ((largestPrimeFactor n : ℝ) - 1) * (1 + Real.log (n : ℝ)) * (1 + Real.log (n : ℝ)) := by gcongr _ = (Nat.totient n : ℝ) * (1 + Real.log (n : ℝ)) ^ 2 / ((largestPrimeFactor n : ℝ) - 1) := by ring lemma error_EP0_universal_bound (n : ℕ) (hn : 2 ≤ n) (p q : ℤ) (hp : 1 ≤ p) (hq : 1 ≤ q) (hpq : (p : ℝ) + (q : ℝ) < (n : ℝ) / 2) : haveI : NeZero n := ⟨by omega⟩ |(errorTermEP0 n p q).re| ≤ (Nat.totient n : ℝ) * (1 + Real.log (n : ℝ)) ^ 2 / ((largestPrimeFactor n : ℝ) - 1) := by haveI : NeZero n := ⟨by omega⟩ exact le_trans (Complex.abs_re_le_norm _) (norm_errorTermEP0_le n hn p q hp hq hpq) lemma summand_norm_le_aux (n : ℕ) [NeZero n] (_p _q : ℤ) (k l : ZMod n) (fp fq : ZMod n → ℂ) (t : ℤ) (cond : Prop) [Decidable cond] : ‖(if cond then normalizedDFT n fp k * normalizedDFT n fq l * ramanujanSum n t else 0)‖ ≤ (Nat.totient n : ℝ) * (if cond then ‖normalizedDFT n fp k‖ * ‖normalizedDFT n fq l‖ else 0) := by by_cases hc : cond · simp only [hc, if_true] rw [norm_mul, norm_mul] calc ‖normalizedDFT n fp k‖ * ‖normalizedDFT n fq l‖ * ‖ramanujanSum n t‖ ≤ ‖normalizedDFT n fp k‖ * ‖normalizedDFT n fq l‖ * (Nat.totient n : ℝ) := by apply mul_le_mul_of_nonneg_left (ramanujanSum_norm_le_totient n t) exact mul_nonneg (norm_nonneg _) (norm_nonneg _) _ = (Nat.totient n : ℝ) * (‖normalizedDFT n fp k‖ * ‖normalizedDFT n fq l‖) := by ring · simp only [hc, if_false, norm_zero, mul_zero, le_refl] lemma summand_norm_le (n : ℕ) [NeZero n] (p q : ℤ) (k l : ZMod n) : let P := largestPrimeFactor n let alpha := n.factorization P let d := P ^ alpha let fp := intervalIndicator n (2 * p - 1).toNat let fq := intervalIndicator n (2 * q - 1).toNat ‖(if (k, l) ≠ (0, 0) ∧ (d : ℤ) ∣ (ZMod.val k * p + ZMod.val l * q) then normalizedDFT n fp k * normalizedDFT n fq l * ramanujanSum n (ZMod.val k * p + ZMod.val l * q) else 0)‖ ≤ (Nat.totient n : ℝ) * (if (k, l) ≠ (0, 0) ∧ ((largestPrimeFactor n ^ n.factorization (largestPrimeFactor n) : ℤ)) ∣ (ZMod.val k * p + ZMod.val l * q) then ‖normalizedDFT n (intervalIndicator n (2 * p - 1).toNat) k‖ * ‖normalizedDFT n (intervalIndicator n (2 * q - 1).toNat) l‖ else 0) := by simp only have : (↑(largestPrimeFactor n ^ n.factorization (largestPrimeFactor n)) : ℤ) = (↑(largestPrimeFactor n) : ℤ) ^ n.factorization (largestPrimeFactor n) := by push_cast; ring rw [this] exact summand_norm_le_aux n p q k l _ _ _ _ lemma errorTermEPalpha_norm_le_totient_mul (n : ℕ) [NeZero n] (p q : ℤ) : ‖errorTermEPalpha n p q‖ ≤ (Nat.totient n : ℝ) * ∑ k : ZMod n, ∑ l : ZMod n, if (k, l) ≠ (0, 0) ∧ ((largestPrimeFactor n ^ n.factorization (largestPrimeFactor n) : ℤ)) ∣ (ZMod.val k * p + ZMod.val l * q) then ‖normalizedDFT n (intervalIndicator n (2 * p - 1).toNat) k‖ * ‖normalizedDFT n (intervalIndicator n (2 * q - 1).toNat) l‖ else 0 := by unfold errorTermEPalpha calc ‖∑ k : ZMod n, ∑ l : ZMod n, if (k, l) ≠ (0, 0) ∧ ((largestPrimeFactor n ^ n.factorization (largestPrimeFactor n) : ℤ)) ∣ (↑(ZMod.val k) * p + ↑(ZMod.val l) * q) then normalizedDFT n (intervalIndicator n (2 * p - 1).toNat) k * normalizedDFT n (intervalIndicator n (2 * q - 1).toNat) l * ramanujanSum n (↑(ZMod.val k) * p + ↑(ZMod.val l) * q) else 0‖ ≤ ∑ k : ZMod n, ‖∑ l : ZMod n, if (k, l) ≠ (0, 0) ∧ ((largestPrimeFactor n ^ n.factorization (largestPrimeFactor n) : ℤ)) ∣ (↑(ZMod.val k) * p + ↑(ZMod.val l) * q) then normalizedDFT n (intervalIndicator n (2 * p - 1).toNat) k * normalizedDFT n (intervalIndicator n (2 * q - 1).toNat) l * ramanujanSum n (↑(ZMod.val k) * p + ↑(ZMod.val l) * q) else 0‖ := norm_sum_le _ _ _ ≤ ∑ k : ZMod n, ∑ l : ZMod n, ‖(if (k, l) ≠ (0, 0) ∧ ((largestPrimeFactor n ^ n.factorization (largestPrimeFactor n) : ℤ)) ∣ (↑(ZMod.val k) * p + ↑(ZMod.val l) * q) then normalizedDFT n (intervalIndicator n (2 * p - 1).toNat) k * normalizedDFT n (intervalIndicator n (2 * q - 1).toNat) l * ramanujanSum n (↑(ZMod.val k) * p + ↑(ZMod.val l) * q) else 0)‖ := Finset.sum_le_sum fun k _ => norm_sum_le _ _ _ ≤ ∑ k : ZMod n, ∑ l : ZMod n, ((Nat.totient n : ℝ) * (if (k, l) ≠ (0, 0) ∧ ((largestPrimeFactor n ^ n.factorization (largestPrimeFactor n) : ℤ)) ∣ (↑(ZMod.val k) * p + ↑(ZMod.val l) * q) then ‖normalizedDFT n (intervalIndicator n (2 * p - 1).toNat) k‖ * ‖normalizedDFT n (intervalIndicator n (2 * q - 1).toNat) l‖ else 0)) := Finset.sum_le_sum fun k _ => Finset.sum_le_sum fun l _ => summand_norm_le n p q k l _ = (Nat.totient n : ℝ) * ∑ k : ZMod n, ∑ l : ZMod n, (if (k, l) ≠ (0, 0) ∧ ((largestPrimeFactor n ^ n.factorization (largestPrimeFactor n) : ℤ)) ∣ (↑(ZMod.val k) * p + ↑(ZMod.val l) * q) then ‖normalizedDFT n (intervalIndicator n (2 * p - 1).toNat) k‖ * ‖normalizedDFT n (intervalIndicator n (2 * q - 1).toNat) l‖ else 0) := by rw [Finset.mul_sum] congr 1 ext k rw [Finset.mul_sum] lemma d_pos (n : ℕ) (hn : 2 ≤ n) : 0 < largestPrimeFactor n ^ n.factorization (largestPrimeFactor n) := by have h1 := Nat.prime_of_mem_primeFactors (largestPrimeFactor_mem_primeFactors n hn) exact Nat.pos_of_ne_zero (Nat.ne_of_gt (Nat.one_le_pow _ _ h1.pos)) lemma val_unitOfCoprime_eq_mod (d a : ℕ) (hcoprime : a.Coprime d) : (ZMod.unitOfCoprime a hcoprime : ZMod d).val = a % d := by have h₁ : (↑(ZMod.unitOfCoprime a hcoprime) : ZMod d) = (a : ZMod d) := by apply ZMod.coe_unitOfCoprime have h₂ : (ZMod.unitOfCoprime a hcoprime : ZMod d).val = (a : ZMod d).val := by rw [h₁] have h₃ : (a : ZMod d).val = a % d := by apply ZMod.val_natCast rw [h₂, h₃] lemma combine_cases_arithmetic (C : ℝ) (L : ℝ) (d : ℝ) : C * (5 * L / d) + C * (L / d) = C * (6 * L / d) := by ring lemma min_val_pos (n : ℕ) [NeZero n] (k : ZMod n) (hk : k ≠ 0) : (0 : ℝ) < min (ZMod.val k : ℝ) ((n : ℝ) - ZMod.val k) := by have h₁ : 0 < (ZMod.val k : ℕ) := by haveI : Fact (n ≠ 0) := ⟨by simpa using NeZero.ne n⟩ have h₃ : ZMod.val k ≠ 0 := by intro h₃ have h₄ : (k : ZMod n) = 0 := by have h₅ : (ZMod.val k : ℕ) = 0 := by simpa using h₃ have h₆ : (k : ZMod n) = 0 := by rw [ZMod.val_eq_zero] at h₅ simp_all exact h₆ contradiction have h₄ : 0 < ZMod.val k := Nat.pos_of_ne_zero h₃ exact_mod_cast h₄ have h₂ : (ZMod.val k : ℕ) < n := by haveI : Fact (n ≠ 0) := ⟨by simpa using NeZero.ne n⟩ have h₃ : (ZMod.val k : ℕ) < n := ZMod.val_lt k exact_mod_cast h₃ have h₃ : (0 : ℝ) < (ZMod.val k : ℝ) := by norm_cast at h₁ ⊢ have h₄ : (0 : ℝ) < (n : ℝ) - (ZMod.val k : ℝ) := by have h₄₁ : (ZMod.val k : ℕ) < n := h₂ have h₄₂ : (ZMod.val k : ℝ) < (n : ℝ) := by norm_cast have h₄₃ : (0 : ℝ) < (n : ℝ) - (ZMod.val k : ℝ) := by linarith exact h₄₃ have h₅ : (0 : ℝ) < min (ZMod.val k : ℝ) ((n : ℝ) - ZMod.val k) := by have h₅₃ : (0 : ℝ) < min (ZMod.val k : ℝ) ((n : ℝ) - ZMod.val k) := by cases' le_total (ZMod.val k : ℝ) ((n : ℝ) - ZMod.val k) with h h <;> simp_all [min_eq_left, min_eq_right] exact h₅₃ exact h₅ lemma summand_nonneg (n d : ℕ) [NeZero n] [NeZero d] (mq : ℕ) (q : ℤ) (u : (ZMod d)ˣ) (k : ZMod n) (l : ZMod n) : 0 ≤ (if k ≠ 0 ∧ ((d : ℤ) ∣ (↑(ZMod.val k) * ↑(u : ZMod d).val + ↑(ZMod.val l) * q)) then ‖normalizedDFT n (intervalIndicator n mq) l‖ / (2 * min (ZMod.val k : ℝ) ((n : ℝ) - ZMod.val k)) else 0) := by split_ifs with h · exact div_nonneg (norm_nonneg _) (mul_nonneg (by norm_num) (le_of_lt (min_val_pos n k h.1))) · exact le_refl 0 lemma sum_exchange_weighted (n d : ℕ) [NeZero n] [NeZero d] (mq : ℕ) (q : ℤ) : ∑ u : (ZMod d)ˣ, (∑ k : ZMod n, ∑ l : ZMod n, if k ≠ 0 ∧ ((d : ℤ) ∣ (↑(ZMod.val k) * ↑(u : ZMod d).val + ↑(ZMod.val l) * q)) then ‖normalizedDFT n (intervalIndicator n mq) l‖ / (2 * min (ZMod.val k : ℝ) ((n : ℝ) - ZMod.val k)) else 0) = ∑ k : ZMod n, ∑ u : (ZMod d)ˣ, (∑ l : ZMod n, if k ≠ 0 ∧ ((d : ℤ) ∣ (↑(ZMod.val k) * ↑(u : ZMod d).val + ↑(ZMod.val l) * q)) then ‖normalizedDFT n (intervalIndicator n mq) l‖ / (2 * min (ZMod.val k : ℝ) ((n : ℝ) - ZMod.val k)) else 0) := by have h₁ : ∑ u : (ZMod d)ˣ, (∑ k : ZMod n, ∑ l : ZMod n, if k ≠ 0 ∧ (↑(ZMod.val k) * ↑(u : ZMod d).val + ↑(ZMod.val l) * q : ℤ) % (d : ℤ) = 0 then ‖normalizedDFT n (intervalIndicator n mq) l‖ / (2 * min (ZMod.val k : ℝ) ((n : ℝ) - ZMod.val k)) else 0) = ∑ k : ZMod n, ∑ u : (ZMod d)ˣ, (∑ l : ZMod n, if k ≠ 0 ∧ (↑(ZMod.val k) * ↑(u : ZMod d).val + ↑(ZMod.val l) * q : ℤ) % (d : ℤ) = 0 then ‖normalizedDFT n (intervalIndicator n mq) l‖ / (2 * min (ZMod.val k : ℝ) ((n : ℝ) - ZMod.val k)) else 0) := by rw [Finset.sum_comm] simp_all [Int.emod_eq_emod_iff_emod_sub_eq_zero] lemma k_zero_summand_vanish (n d : ℕ) [NeZero n] [NeZero d] (mq : ℕ) (q : ℤ) (u : (ZMod d)ˣ) : (∑ l : ZMod n, if (0 : ZMod n) ≠ 0 ∧ ((d : ℤ) ∣ (↑(ZMod.val (0 : ZMod n)) * ↑(u : ZMod d).val + ↑(ZMod.val l) * q)) then ‖normalizedDFT n (intervalIndicator n mq) l‖ / (2 * min (ZMod.val (0 : ZMod n) : ℝ) ((n : ℝ) - ZMod.val (0 : ZMod n))) else 0) = 0 := by have h_main : ∀ (l : ZMod n), (if (0 : ZMod n) ≠ 0 ∧ ((d : ℤ) ∣ (↑(ZMod.val (0 : ZMod n)) * ↑(u : ZMod d).val + ↑(ZMod.val l) * q)) then ‖normalizedDFT n (intervalIndicator n mq) l‖ / (2 * min (ZMod.val (0 : ZMod n) : ℝ) ((n : ℝ) - ZMod.val (0 : ZMod n))) else 0) = 0 := by intro l have h₁ : ¬((0 : ZMod n) ≠ 0) := by intro h apply h rfl split_ifs <;> simp_all [h₁] have h_sum : (∑ l : ZMod n, if (0 : ZMod n) ≠ 0 ∧ ((d : ℤ) ∣ (↑(ZMod.val (0 : ZMod n)) * ↑(u : ZMod d).val + ↑(ZMod.val l) * q)) then ‖normalizedDFT n (intervalIndicator n mq) l‖ / (2 * min (ZMod.val (0 : ZMod n) : ℝ) ((n : ℝ) - ZMod.val (0 : ZMod n))) else 0) = 0 := by calc (∑ l : ZMod n, if (0 : ZMod n) ≠ 0 ∧ ((d : ℤ) ∣ (↑(ZMod.val (0 : ZMod n)) * ↑(u : ZMod d).val + ↑(ZMod.val l) * q)) then ‖normalizedDFT n (intervalIndicator n mq) l‖ / (2 * min (ZMod.val (0 : ZMod n) : ℝ) ((n : ℝ) - ZMod.val (0 : ZMod n))) else 0) = ∑ l : ZMod n, 0 := by apply Finset.sum_congr rfl intro l _ rw [h_main l] _ = 0 := by simp apply h_sum lemma outer_sum_split (n : ℕ) [NeZero n] (G : ZMod n → ℝ) : ∑ k : ZMod n, G k = G 0 + ∑ k ∈ Finset.univ.filter (fun k : ZMod n => k ≠ 0), G k := by have h := Finset.sum_filter_add_sum_filter_not Finset.univ (fun k : ZMod n => k = 0) G rw [Finset.sum_filter, Finset.sum_ite_eq' Finset.univ 0 G, if_pos (Finset.mem_univ _)] at h linarith lemma zero_term_vanishes (n d : ℕ) [NeZero n] [NeZero d] (mq : ℕ) (q : ℤ) : ∑ u : (ZMod d)ˣ, (∑ l : ZMod n, if (0 : ZMod n) ≠ 0 ∧ ((d : ℤ) ∣ (↑(ZMod.val (0 : ZMod n)) * ↑(u : ZMod d).val + ↑(ZMod.val l) * q)) then ‖normalizedDFT n (intervalIndicator n mq) l‖ / (2 * min (ZMod.val (0 : ZMod n) : ℝ) ((n : ℝ) - ZMod.val (0 : ZMod n))) else 0) = 0 := by apply Finset.sum_eq_zero intro u _ apply Finset.sum_eq_zero intro l _ simp lemma summand_congr_on_filter (n d : ℕ) [NeZero n] [NeZero d] (mq : ℕ) (q : ℤ) (k : ZMod n) (hk : k ≠ 0) : (∑ u : (ZMod d)ˣ, (∑ l : ZMod n, if k ≠ 0 ∧ ((d : ℤ) ∣ (↑(ZMod.val k) * ↑(u : ZMod d).val + ↑(ZMod.val l) * q)) then ‖normalizedDFT n (intervalIndicator n mq) l‖ / (2 * min (ZMod.val k : ℝ) ((n : ℝ) - ZMod.val k)) else 0)) = (∑ u : (ZMod d)ˣ, (∑ l : ZMod n, if ((d : ℤ) ∣ (↑(ZMod.val k) * ↑(u : ZMod d).val + ↑(ZMod.val l) * q)) then ‖normalizedDFT n (intervalIndicator n mq) l‖ / (2 * min (ZMod.val k : ℝ) ((n : ℝ) - ZMod.val k)) else 0)) := by congr 1; ext u; congr 1; ext l simp [hk] lemma sum_restrict_to_nonzero (n d : ℕ) [NeZero n] [NeZero d] (mq : ℕ) (q : ℤ) : ∑ k : ZMod n, ∑ u : (ZMod d)ˣ, (∑ l : ZMod n, if k ≠ 0 ∧ ((d : ℤ) ∣ (↑(ZMod.val k) * ↑(u : ZMod d).val + ↑(ZMod.val l) * q)) then ‖normalizedDFT n (intervalIndicator n mq) l‖ / (2 * min (ZMod.val k : ℝ) ((n : ℝ) - ZMod.val k)) else 0) = ∑ k ∈ Finset.univ.filter (fun k : ZMod n => k ≠ 0), ∑ u : (ZMod d)ˣ, (∑ l : ZMod n, if ((d : ℤ) ∣ (↑(ZMod.val k) * ↑(u : ZMod d).val + ↑(ZMod.val l) * q)) then ‖normalizedDFT n (intervalIndicator n mq) l‖ / (2 * min (ZMod.val k : ℝ) ((n : ℝ) - ZMod.val k)) else 0) := by rw [outer_sum_split] rw [zero_term_vanishes] simp only [zero_add] exact Finset.sum_congr rfl fun k hk => by exact summand_congr_on_filter n d mq q k (Finset.mem_filter.mp hk).2 lemma split_nonzero_by_divisibility (n d : ℕ) [NeZero n] [NeZero d] (mq : ℕ) (q : ℤ) : ∑ k ∈ Finset.univ.filter (fun k : ZMod n => k ≠ 0), ∑ u : (ZMod d)ˣ, (∑ l : ZMod n, if ((d : ℤ) ∣ (↑(ZMod.val k) * ↑(u : ZMod d).val + ↑(ZMod.val l) * q)) then ‖normalizedDFT n (intervalIndicator n mq) l‖ / (2 * min (ZMod.val k : ℝ) ((n : ℝ) - ZMod.val k)) else 0) = (∑ k ∈ Finset.univ.filter (fun k : ZMod n => k ≠ 0 ∧ ¬((d : ℕ) ∣ ZMod.val k)), ∑ u : (ZMod d)ˣ, (∑ l : ZMod n, if ((d : ℤ) ∣ (↑(ZMod.val k) * ↑(u : ZMod d).val + ↑(ZMod.val l) * q)) then ‖normalizedDFT n (intervalIndicator n mq) l‖ / (2 * min (ZMod.val k : ℝ) ((n : ℝ) - ZMod.val k)) else 0)) + (∑ k ∈ Finset.univ.filter (fun k : ZMod n => k ≠ 0 ∧ (d : ℕ) ∣ ZMod.val k), ∑ u : (ZMod d)ˣ, (∑ l : ZMod n, if ((d : ℤ) ∣ (↑(ZMod.val k) * ↑(u : ZMod d).val + ↑(ZMod.val l) * q)) then ‖normalizedDFT n (intervalIndicator n mq) l‖ / (2 * min (ZMod.val k : ℝ) ((n : ℝ) - ZMod.val k)) else 0)) := by have h1 : (∑ k ∈ Finset.univ.filter (fun k : ZMod n => k ≠ 0), ∑ u : (ZMod d)ˣ, (∑ l : ZMod n, if (d : ℤ) ∣ (↑(ZMod.val k) * ↑(u : ZMod d).val + ↑(ZMod.val l) * q) then ‖normalizedDFT n (intervalIndicator n mq) l‖ / (2 * min (ZMod.val k : ℝ) ((n : ℝ) - ZMod.val k)) else 0)) = (∑ k ∈ Finset.univ.filter (fun k : ZMod n => k ≠ 0 ∧ ¬((d : ℕ) ∣ ZMod.val k)) ∪ Finset.univ.filter (fun k : ZMod n => k ≠ 0 ∧ (d : ℕ) ∣ ZMod.val k), ∑ u : (ZMod d)ˣ, (∑ l : ZMod n, if (d : ℤ) ∣ (↑(ZMod.val k) * ↑(u : ZMod d).val + ↑(ZMod.val l) * q) then ‖normalizedDFT n (intervalIndicator n mq) l‖ / (2 * min (ZMod.val k : ℝ) ((n : ℝ) - ZMod.val k)) else 0)) := by have h2 : Finset.univ.filter (fun k : ZMod n => k ≠ 0 ∧ ¬((d : ℕ) ∣ ZMod.val k)) ∪ Finset.univ.filter (fun k : ZMod n => k ≠ 0 ∧ (d : ℕ) ∣ ZMod.val k) = Finset.univ.filter (fun k : ZMod n => k ≠ 0) := by apply Finset.ext intro x simp only [Finset.mem_union, Finset.mem_filter] constructor · intro h by_cases hx : x = 0 <;> by_cases hd : (d : ℕ) ∣ ZMod.val x <;> simp_all [hx, hd, not_and_or] · intro h by_cases hx : x = 0 <;> by_cases hd : (d : ℕ) ∣ ZMod.val x <;> simp_all [hx, hd, not_and_or] rw [h2] have h3 : (∑ k ∈ Finset.univ.filter (fun k : ZMod n => k ≠ 0 ∧ ¬((d : ℕ) ∣ ZMod.val k)) ∪ Finset.univ.filter (fun k : ZMod n => k ≠ 0 ∧ (d : ℕ) ∣ ZMod.val k), ∑ u : (ZMod d)ˣ, (∑ l : ZMod n, if (d : ℤ) ∣ (↑(ZMod.val k) * ↑(u : ZMod d).val + ↑(ZMod.val l) * q) then ‖normalizedDFT n (intervalIndicator n mq) l‖ / (2 * min (ZMod.val k : ℝ) ((n : ℝ) - ZMod.val k)) else 0)) = (∑ k ∈ Finset.univ.filter (fun k : ZMod n => k ≠ 0 ∧ ¬((d : ℕ) ∣ ZMod.val k)), ∑ u : (ZMod d)ˣ, (∑ l : ZMod n, if (d : ℤ) ∣ (↑(ZMod.val k) * ↑(u : ZMod d).val + ↑(ZMod.val l) * q) then ‖normalizedDFT n (intervalIndicator n mq) l‖ / (2 * min (ZMod.val k : ℝ) ((n : ℝ) - ZMod.val k)) else 0)) + (∑ k ∈ Finset.univ.filter (fun k : ZMod n => k ≠ 0 ∧ (d : ℕ) ∣ ZMod.val k), ∑ u : (ZMod d)ˣ, (∑ l : ZMod n, if (d : ℤ) ∣ (↑(ZMod.val k) * ↑(u : ZMod d).val + ↑(ZMod.val l) * q) then ‖normalizedDFT n (intervalIndicator n mq) l‖ / (2 * min (ZMod.val k : ℝ) ((n : ℝ) - ZMod.val k)) else 0)) := by have h4 : Disjoint (Finset.univ.filter (fun k : ZMod n => k ≠ 0 ∧ ¬((d : ℕ) ∣ ZMod.val k))) (Finset.univ.filter (fun k : ZMod n => k ≠ 0 ∧ (d : ℕ) ∣ ZMod.val k)) := by apply Finset.disjoint_left.mpr intro x hx1 hx2 simp only [Finset.mem_filter] at hx1 hx2 have h5 : ¬((d : ℕ) ∣ ZMod.val x) := hx1.2.2 have h6 : (d : ℕ) ∣ ZMod.val x := hx2.2.2 exact h5 h6 rw [Finset.sum_union h4] rw [h1, h3] lemma k_sum_split_by_d_divisibility (n d : ℕ) [NeZero n] [NeZero d] (mq : ℕ) (q : ℤ) : ∑ k : ZMod n, ∑ u : (ZMod d)ˣ, (∑ l : ZMod n, if k ≠ 0 ∧ ((d : ℤ) ∣ (↑(ZMod.val k) * ↑(u : ZMod d).val + ↑(ZMod.val l) * q)) then ‖normalizedDFT n (intervalIndicator n mq) l‖ / (2 * min (ZMod.val k : ℝ) ((n : ℝ) - ZMod.val k)) else 0) = (∑ k ∈ Finset.univ.filter (fun k : ZMod n => k ≠ 0 ∧ ¬((d : ℕ) ∣ ZMod.val k)), ∑ u : (ZMod d)ˣ, (∑ l : ZMod n, if ((d : ℤ) ∣ (↑(ZMod.val k) * ↑(u : ZMod d).val + ↑(ZMod.val l) * q)) then ‖normalizedDFT n (intervalIndicator n mq) l‖ / (2 * min (ZMod.val k : ℝ) ((n : ℝ) - ZMod.val k)) else 0)) + (∑ k ∈ Finset.univ.filter (fun k : ZMod n => k ≠ 0 ∧ (d : ℕ) ∣ ZMod.val k), ∑ u : (ZMod d)ˣ, (∑ l : ZMod n, if ((d : ℤ) ∣ (↑(ZMod.val k) * ↑(u : ZMod d).val + ↑(ZMod.val l) * q)) then ‖normalizedDFT n (intervalIndicator n mq) l‖ / (2 * min (ZMod.val k : ℝ) ((n : ℝ) - ZMod.val k)) else 0)) := by rw [sum_restrict_to_nonzero, split_nonzero_by_divisibility] lemma factor_weight_from_double_sum (n d : ℕ) [NeZero n] [NeZero d] (mq : ℕ) (q : ℤ) (k : ZMod n) (hk : k ≠ 0) : (∑ u : (ZMod d)ˣ, (∑ l : ZMod n, if ((d : ℤ) ∣ (↑(ZMod.val k) * ↑(u : ZMod d).val + ↑(ZMod.val l) * q)) then ‖normalizedDFT n (intervalIndicator n mq) l‖ / (2 * min (ZMod.val k : ℝ) ((n : ℝ) - ZMod.val k)) else 0)) = (∑ u : (ZMod d)ˣ, (∑ l : ZMod n, if ((d : ℤ) ∣ (↑(ZMod.val k) * ↑(u : ZMod d).val + ↑(ZMod.val l) * q)) then ‖normalizedDFT n (intervalIndicator n mq) l‖ else 0)) / (2 * min (ZMod.val k : ℝ) ((n : ℝ) - ZMod.val k)) := by have h₂ : (∑ u : (ZMod d)ˣ, (∑ l : ZMod n, (if ((d : ℤ) ∣ (↑(ZMod.val k) * ↑(u : ZMod d).val + ↑(ZMod.val l) * q)) then ‖normalizedDFT n (intervalIndicator n mq) l‖ / (2 * min (ZMod.val k : ℝ) ((n : ℝ) - ZMod.val k)) else 0))) = (∑ u : (ZMod d)ˣ, (∑ l : ZMod n, (if ((d : ℤ) ∣ (↑(ZMod.val k) * ↑(u : ZMod d).val + ↑(ZMod.val l) * q)) then ‖normalizedDFT n (intervalIndicator n mq) l‖ else 0)) / (2 * min (ZMod.val k : ℝ) ((n : ℝ) - ZMod.val k))) := by calc (∑ u : (ZMod d)ˣ, (∑ l : ZMod n, (if ((d : ℤ) ∣ (↑(ZMod.val k) * ↑(u : ZMod d).val + ↑(ZMod.val l) * q)) then ‖normalizedDFT n (intervalIndicator n mq) l‖ / (2 * min (ZMod.val k : ℝ) ((n : ℝ) - ZMod.val k)) else 0))) = (∑ u : (ZMod d)ˣ, (∑ l : ZMod n, (if ((d : ℤ) ∣ (↑(ZMod.val k) * ↑(u : ZMod d).val + ↑(ZMod.val l) * q)) then ‖normalizedDFT n (intervalIndicator n mq) l‖ else 0) / (2 * min (ZMod.val k : ℝ) ((n : ℝ) - ZMod.val k))) ) := by apply Finset.sum_congr rfl intro u _ apply Finset.sum_congr rfl intro l _ split_ifs <;> simp_all [div_eq_mul_inv, mul_assoc] _ = (∑ u : (ZMod d)ˣ, (∑ l : ZMod n, (if ((d : ℤ) ∣ (↑(ZMod.val k) * ↑(u : ZMod d).val + ↑(ZMod.val l) * q)) then ‖normalizedDFT n (intervalIndicator n mq) l‖ else 0)) / (2 * min (ZMod.val k : ℝ) ((n : ℝ) - ZMod.val k))) := by apply Finset.sum_congr rfl intro u _ have h₃ : (∑ l : ZMod n, (if ((d : ℤ) ∣ (↑(ZMod.val k) * ↑(u : ZMod d).val + ↑(ZMod.val l) * q)) then ‖normalizedDFT n (intervalIndicator n mq) l‖ else 0) / (2 * min (ZMod.val k : ℝ) ((n : ℝ) - ZMod.val k))) = (∑ l : ZMod n, (if ((d : ℤ) ∣ (↑(ZMod.val k) * ↑(u : ZMod d).val + ↑(ZMod.val l) * q)) then ‖normalizedDFT n (intervalIndicator n mq) l‖ else 0)) / (2 * min (ZMod.val k : ℝ) ((n : ℝ) - ZMod.val k)) := by rw [Finset.sum_div] rw [h₃] have h₃ : (∑ u : (ZMod d)ˣ, (∑ l : ZMod n, (if ((d : ℤ) ∣ (↑(ZMod.val k) * ↑(u : ZMod d).val + ↑(ZMod.val l) * q)) then ‖normalizedDFT n (intervalIndicator n mq) l‖ else 0)) / (2 * min (ZMod.val k : ℝ) ((n : ℝ) - ZMod.val k))) = (∑ u : (ZMod d)ˣ, (∑ l : ZMod n, (if ((d : ℤ) ∣ (↑(ZMod.val k) * ↑(u : ZMod d).val + ↑(ZMod.val l) * q)) then ‖normalizedDFT n (intervalIndicator n mq) l‖ else 0))) / (2 * min (ZMod.val k : ℝ) ((n : ℝ) - ZMod.val k)) := by calc (∑ u : (ZMod d)ˣ, (∑ l : ZMod n, (if ((d : ℤ) ∣ (↑(ZMod.val k) * ↑(u : ZMod d).val + ↑(ZMod.val l) * q)) then ‖normalizedDFT n (intervalIndicator n mq) l‖ else 0)) / (2 * min (ZMod.val k : ℝ) ((n : ℝ) - ZMod.val k))) = (∑ u : (ZMod d)ˣ, ((∑ l : ZMod n, (if ((d : ℤ) ∣ (↑(ZMod.val k) * ↑(u : ZMod d).val + ↑(ZMod.val l) * q)) then ‖normalizedDFT n (intervalIndicator n mq) l‖ else 0)) * (1 / (2 * min (ZMod.val k : ℝ) ((n : ℝ) - ZMod.val k))))) := by apply Finset.sum_congr rfl intro u _ have h₄ : 0 < (2 * min (ZMod.val k : ℝ) ((n : ℝ) - ZMod.val k)) := by have h₅ : 0 < (ZMod.val k : ℝ) := by exact_mod_cast Nat.pos_of_ne_zero (by intro h; simp_all [ZMod.val_eq_zero]) have h₆ : (n : ℝ) - ZMod.val k > 0 := by have h₇ : (n : ℝ) > (ZMod.val k : ℝ) := by have h₈ : (n : ℕ) > ZMod.val k := by have h₉ : ZMod.val k < n := ZMod.val_lt k linarith exact_mod_cast h₈ linarith positivity field_simp [h₄.ne'] _ = (∑ u : (ZMod d)ˣ, ((∑ l : ZMod n, (if ((d : ℤ) ∣ (↑(ZMod.val k) * ↑(u : ZMod d).val + ↑(ZMod.val l) * q)) then ‖normalizedDFT n (intervalIndicator n mq) l‖ else 0)) * (1 / (2 * min (ZMod.val k : ℝ) ((n : ℝ) - ZMod.val k))))) := by rfl _ = (∑ u : (ZMod d)ˣ, (∑ l : ZMod n, (if ((d : ℤ) ∣ (↑(ZMod.val k) * ↑(u : ZMod d).val + ↑(ZMod.val l) * q)) then ‖normalizedDFT n (intervalIndicator n mq) l‖ else 0))) * (1 / (2 * min (ZMod.val k : ℝ) ((n : ℝ) - ZMod.val k))) := by simp [Finset.sum_mul] _ = (∑ u : (ZMod d)ˣ, (∑ l : ZMod n, (if ((d : ℤ) ∣ (↑(ZMod.val k) * ↑(u : ZMod d).val + ↑(ZMod.val l) * q)) then ‖normalizedDFT n (intervalIndicator n mq) l‖ else 0))) / (2 * min (ZMod.val k : ℝ) ((n : ℝ) - ZMod.val k)) := by field_simp calc (∑ u : (ZMod d)ˣ, (∑ l : ZMod n, (if ((d : ℤ) ∣ (↑(ZMod.val k) * ↑(u : ZMod d).val + ↑(ZMod.val l) * q)) then ‖normalizedDFT n (intervalIndicator n mq) l‖ / (2 * min (ZMod.val k : ℝ) ((n : ℝ) - ZMod.val k)) else 0))) = (∑ u : (ZMod d)ˣ, (∑ l : ZMod n, (if ((d : ℤ) ∣ (↑(ZMod.val k) * ↑(u : ZMod d).val + ↑(ZMod.val l) * q)) then ‖normalizedDFT n (intervalIndicator n mq) l‖ / (2 * min (ZMod.val k : ℝ) ((n : ℝ) - ZMod.val k)) else 0))) := rfl _ = (∑ u : (ZMod d)ˣ, (∑ l : ZMod n, (if ((d : ℤ) ∣ (↑(ZMod.val k) * ↑(u : ZMod d).val + ↑(ZMod.val l) * q)) then ‖normalizedDFT n (intervalIndicator n mq) l‖ else 0)) / (2 * min (ZMod.val k : ℝ) ((n : ℝ) - ZMod.val k))) := by rw [h₂] _ = (∑ u : (ZMod d)ˣ, (∑ l : ZMod n, (if ((d : ℤ) ∣ (↑(ZMod.val k) * ↑(u : ZMod d).val + ↑(ZMod.val l) * q)) then ‖normalizedDFT n (intervalIndicator n mq) l‖ else 0))) / (2 * min (ZMod.val k : ℝ) ((n : ℝ) - ZMod.val k)) := by rw [h₃] lemma dvd_simplify_multiple_case (n d : ℕ) [NeZero n] [NeZero d] (k : ZMod n) (l : ZMod n) (u : (ZMod d)ˣ) (q : ℤ) (hdk : (d : ℕ) ∣ ZMod.val k) (hq_coprime_d : Int.gcd q (d : ℤ) = 1) : ((d : ℤ) ∣ (↑(ZMod.val k) * ↑(u : ZMod d).val + ↑(ZMod.val l) * q)) ↔ ((d : ℤ) ∣ ↑(ZMod.val l)) := by constructor · intro h have h₁ : (d : ℤ) ∣ (↑(ZMod.val k) * ↑(u : ZMod d).val) := by have h₂ : (d : ℤ) ∣ ↑(ZMod.val k) := by exact_mod_cast hdk have h₃ : (d : ℤ) ∣ ↑(ZMod.val k) * ↑(u : ZMod d).val := by exact dvd_mul_of_dvd_left h₂ _ exact h₃ have h₂ : (d : ℤ) ∣ ↑(ZMod.val l) * q := by have h₃ : (d : ℤ) ∣ (↑(ZMod.val k) * ↑(u : ZMod d).val + ↑(ZMod.val l) * q) := h have h₄ : (d : ℤ) ∣ (↑(ZMod.val k) * ↑(u : ZMod d).val) := h₁ have h₅ : (d : ℤ) ∣ (↑(ZMod.val l) * q) := by have h₆ : (d : ℤ) ∣ (↑(ZMod.val k) * ↑(u : ZMod d).val + ↑(ZMod.val l) * q) - (↑(ZMod.val k) * ↑(u : ZMod d).val) := by exact dvd_sub h₃ h₄ simpa [add_comm, add_left_comm, add_assoc] using h₆ exact h₅ have h₃ : (d : ℤ) ∣ ↑(ZMod.val l) := by have h₄ : IsCoprime (q : ℤ) (d : ℤ) := by rw [Int.isCoprime_iff_gcd_eq_one] <;> simp_all [Int.gcd_comm] have h₅ : (d : ℤ) ∣ ↑(ZMod.val l) * q := h₂ have h₆ : (d : ℤ) ∣ ↑(ZMod.val l) := by have h₇ : IsCoprime (q : ℤ) (d : ℤ) := h₄ have h₈ : (d : ℤ) ∣ ↑(ZMod.val l) * q := h₅ exact (h₇.symm.dvd_of_dvd_mul_right h₈) exact h₆ exact h₃ · intro h have h₁ : (d : ℤ) ∣ (↑(ZMod.val k) * ↑(u : ZMod d).val) := by have h₂ : (d : ℤ) ∣ ↑(ZMod.val k) := by exact_mod_cast hdk have h₃ : (d : ℤ) ∣ ↑(ZMod.val k) * ↑(u : ZMod d).val := by exact dvd_mul_of_dvd_left h₂ _ exact h₃ have h₂ : (d : ℤ) ∣ (↑(ZMod.val l) * q) := by have h₃ : (d : ℤ) ∣ ↑(ZMod.val l) := h have h₄ : (d : ℤ) ∣ ↑(ZMod.val l) * q := by exact dvd_mul_of_dvd_left h₃ _ exact h₄ have h₃ : (d : ℤ) ∣ (↑(ZMod.val k) * ↑(u : ZMod d).val + ↑(ZMod.val l) * q) := by have h₄ : (d : ℤ) ∣ (↑(ZMod.val k) * ↑(u : ZMod d).val) := h₁ have h₅ : (d : ℤ) ∣ (↑(ZMod.val l) * q) := h₂ exact dvd_add h₄ h₅ exact h₃ lemma mq_bounds (n : ℕ) (hn : 2 ≤ n) (q : ℤ) (hq_pos : 1 ≤ q) (hq_bound : (q : ℝ) < (n : ℝ) / 2) : 1 ≤ (2 * q - 1).toNat ∧ (2 * q - 1).toNat < n := by have h₂ : (2 * q - 1 : ℤ) < n := by have h₅ : (2 * q - 1 : ℤ) < n := by have h₆ : (2 * q - 1 : ℝ) < (n : ℝ) := by linarith have h₉ : (2 * q - 1 : ℤ) < (n : ℤ) := by exact_mod_cast h₆ exact_mod_cast h₉ exact h₅ have h₃ : 1 ≤ (2 * q - 1).toNat := by have h₄ : 0 ≤ (2 * q - 1 : ℤ) := by linarith have h₇ : (1 : ℕ) ≤ (2 * q - 1).toNat := by have h₉ : (2 * q - 1).toNat ≥ 1 := by have h₁₁ : (2 * q - 1).toNat ≥ 1 := by have h₁₃ : (2 * q - 1).toNat ≥ 1 := by have h₁₆ : (2 * q - 1).toNat ≥ 1 := by have h₁₇ : (2 * q - 1 : ℤ) ≥ 1 := by linarith have h₁₈ : (2 * q - 1).toNat ≥ 1 := by norm_cast at h₁₇ ⊢ <;> simp_all [Int.toNat_of_nonneg (by linarith : (0 : ℤ) ≤ 2 * q - 1)] <;> omega exact h₁₈ exact h₁₆ exact h₁₃ exact h₁₁ omega exact h₇ have h₄ : (2 * q - 1).toNat < n := by have h₅ : (2 * q - 1 : ℤ) < n := h₂ have h₆ : 0 ≤ (2 * q - 1 : ℤ) := by linarith have h₇ : (2 * q - 1).toNat < n := by have h₈ : (2 * q - 1).toNat < n := by have h₁₁ : (2 * q - 1).toNat < n := by have h₁₂ : (2 * q - 1 : ℤ) < (n : ℤ) := by exact_mod_cast h₅ have h₁₃ : 0 ≤ (2 * q - 1 : ℤ) := by linarith norm_cast at h₁₂ ⊢ <;> simp_all [Int.toNat_of_nonneg h₁₃] <;> omega exact h₁₁ exact h₈ exact h₇ exact ⟨h₃, h₄⟩ lemma symmetric_sum_le_one_plus_log (n d : ℕ) (hn : 2 ≤ n) (hd_dvd : d ∣ n) (hd_pos : 0 < d) : ∑ j ∈ Finset.Icc 1 (n / d - 1), (1 : ℝ) / (2 * min (j : ℝ) ((↑(n / d) : ℝ) - j)) ≤ 1 + Real.log n := by set N := n / d with hN_def by_cases hN_small : N ≤ 1 · have : N - 1 = 0 := Nat.sub_eq_zero_of_le hN_small rw [this] simp have : (1 : ℝ) ≤ (n : ℝ) := by exact_mod_cast (Nat.one_le_iff_ne_zero.mpr (by omega)) linarith [Real.log_nonneg this] · push_neg at hN_small have hN2 : 2 ≤ N := hN_small have h_log := symmetric_harmonic_sum_le_log N hN2 have hN_le_n : (N : ℝ) ≤ (n : ℝ) := by exact_mod_cast Nat.div_le_self n d have hN_pos : (0 : ℝ) < (N : ℝ) := by positivity have h_log_mono : Real.log (N : ℝ) ≤ Real.log (n : ℝ) := Real.log_le_log hN_pos hN_le_n linarith lemma mul_lt_of_mem_Icc (n d : ℕ) (hd_dvd : d ∣ n) (hd_pos : 0 < d) (j : ℕ) (hj : j ∈ Finset.Icc 1 (n / d - 1)) : j * d < n := by have h₁ : n / d ≥ 1 := by simp only [Finset.mem_Icc] at hj; omega have h₂ : j + 1 ≤ n / d := by simp only [Finset.mem_Icc] at hj; omega have h₃ : (j + 1) * d ≤ n := by have h₂_val := (Finset.mem_Icc.mp hj).2; have := Nat.div_mul_le_self n d; nlinarith have h₅ : j * d < n := by nlinarith exact h₅ lemma fwd_mem (n d : ℕ) [NeZero n] [NeZero d] (hd_dvd : d ∣ n) (hd_pos : 0 < d) (j : ℕ) (hj : j ∈ Finset.Icc 1 (n / d - 1)) : (↑(j * d) : ZMod n) ∈ Finset.univ.filter (fun k : ZMod n => k ≠ 0 ∧ (d : ℕ) ∣ ZMod.val k) := by have hjd_lt : j * d < n := mul_lt_of_mem_Icc n d hd_dvd hd_pos j hj have hj_bounds := Finset.mem_Icc.mp hj simp only [Finset.mem_filter, Finset.mem_univ, true_and] constructor · intro h rw [ZMod.natCast_eq_zero_iff] at h have hjd_pos : 0 < j * d := Nat.mul_pos (by omega : 0 < j) hd_pos exact absurd h (Nat.not_dvd_of_pos_of_lt hjd_pos hjd_lt) · rw [ZMod.val_natCast_of_lt hjd_lt] exact dvd_mul_left d j lemma bwd_mem (n d : ℕ) [NeZero n] [NeZero d] (hd_dvd : d ∣ n) (hd_pos : 0 < d) (k : ZMod n) (hk : k ∈ Finset.univ.filter (fun k : ZMod n => k ≠ 0 ∧ (d : ℕ) ∣ ZMod.val k)) : ZMod.val k / d ∈ Finset.Icc 1 (n / d - 1) := by simp only [Finset.mem_filter, Finset.mem_univ, true_and] at hk obtain ⟨hk_ne, hd_dvd_val⟩ := hk have hval_pos : 0 < ZMod.val k := Nat.pos_of_ne_zero ((ZMod.val_ne_zero k).mpr hk_ne) have hval_lt : ZMod.val k < n := ZMod.val_lt k rw [Finset.mem_Icc] constructor · exact Nat.div_pos (Nat.le_of_dvd hval_pos hd_dvd_val) hd_pos · have h1 : ZMod.val k / d < n / d := Nat.div_lt_div_of_lt_of_dvd hd_dvd hval_lt omega lemma left_inv (n d : ℕ) [NeZero n] [NeZero d] (hd_dvd : d ∣ n) (hd_pos : 0 < d) (j : ℕ) (hj : j ∈ Finset.Icc 1 (n / d - 1)) : ZMod.val (↑(j * d) : ZMod n) / d = j := by have hjd : j * d < n := mul_lt_of_mem_Icc n d hd_dvd hd_pos j hj rw [ZMod.val_natCast_of_lt hjd, Nat.mul_div_cancel j hd_pos] lemma right_inv (n d : ℕ) [NeZero n] [NeZero d] (hd_dvd : d ∣ n) (hd_pos : 0 < d) (k : ZMod n) (hk : k ∈ Finset.univ.filter (fun k : ZMod n => k ≠ 0 ∧ (d : ℕ) ∣ ZMod.val k)) : (↑(ZMod.val k / d * d) : ZMod n) = k := by have hmem := (Finset.mem_filter.mp hk).2 have hdvd : d ∣ ZMod.val k := hmem.2 rw [Nat.div_mul_cancel hdvd, ZMod.natCast_zmod_val] lemma div_lt_div_of_dvd (n d : ℕ) [NeZero n] [NeZero d] (hd_dvd : d ∣ n) (k : ZMod n) (hd_dvd_val : d ∣ ZMod.val k) : ZMod.val k / d < n / d := by have h_val_lt_n : ZMod.val k < n := ZMod.val_lt k exact Nat.div_lt_div_of_lt_of_dvd hd_dvd h_val_lt_n lemma min_factor_d_nat (n d : ℕ) [NeZero n] [NeZero d] (hd_dvd : d ∣ n) (k : ZMod n) (hk_ne : k ≠ 0) (hd_dvd_val : d ∣ ZMod.val k) : min (ZMod.val k : ℝ) ((n : ℝ) - ZMod.val k) = (d : ℝ) * min (↑(ZMod.val k / d) : ℝ) ((↑(n / d) : ℝ) - ↑(ZMod.val k / d)) := by have hj_lt : ZMod.val k / d < n / d := div_lt_div_of_dvd n d hd_dvd k hd_dvd_val have hval_eq : ZMod.val k = ZMod.val k / d * d := (Nat.div_mul_cancel hd_dvd_val).symm have hn_eq : n = n / d * d := (Nat.div_mul_cancel hd_dvd).symm have hd_pos : (0 : ℝ) ≤ (d : ℝ) := Nat.cast_nonneg d set j := ZMod.val k / d set N := n / d have hval_cast : (ZMod.val k : ℝ) = (j : ℝ) * (d : ℝ) := by rw [← Nat.cast_mul, ← hval_eq] have hn_cast : (n : ℝ) = (N : ℝ) * (d : ℝ) := by rw [← Nat.cast_mul, ← hn_eq] rw [hval_cast, hn_cast, show (N : ℝ) * (d : ℝ) - (j : ℝ) * (d : ℝ) = ((N : ℝ) - (j : ℝ)) * (d : ℝ) from by ring] rw [← min_mul_of_nonneg _ _ hd_pos, mul_comm] lemma div_factor_d (d M : ℝ) (hd : d ≠ 0) : (1 : ℝ) / (2 * (d * M)) = (1 / d) * (1 / (2 * M)) := by have h₁ : (1 : ℝ) / (2 * (d * M)) = (1 : ℝ) / (2 * d * M) := by ring_nf rw [h₁] by_cases h₂ : M = 0 · simp_all · have h₃ : (1 : ℝ) / (2 * d * M) = (1 / d) * (1 / (2 * M)) := by have h₄ : 2 * d * M = 2 * M * d := by ring rw [h₄] field_simp [hd, h₂] rw [h₃] lemma summand_eq_via_bwd (n d : ℕ) [NeZero n] [NeZero d] (hd_dvd : d ∣ n) (_hd_pos : 0 < d) (k : ZMod n) (hk : k ∈ Finset.univ.filter (fun k : ZMod n => k ≠ 0 ∧ (d : ℕ) ∣ ZMod.val k)) : let N := n / d let j := ZMod.val k / d (1 : ℝ) / (2 * min (ZMod.val k : ℝ) ((n : ℝ) - ZMod.val k)) = (1 / (d : ℝ)) * ((1 : ℝ) / (2 * min (j : ℝ) ((N : ℝ) - j))) := by simp only [Finset.mem_filter, Finset.mem_univ, true_and] at hk obtain ⟨hk_ne, hd_dvd_val⟩ := hk intro N j rw [min_factor_d_nat n d hd_dvd k hk_ne hd_dvd_val] exact div_factor_d (d : ℝ) _ (Nat.cast_ne_zero.mpr (Nat.pos_of_ne_zero (NeZero.ne d)).ne') lemma reindex_multiples_of_d (n d : ℕ) [NeZero n] [NeZero d] (hd_dvd : d ∣ n) (hd_pos : 0 < d) : let N := n / d ∑ k ∈ Finset.univ.filter (fun k : ZMod n => k ≠ 0 ∧ (d : ℕ) ∣ ZMod.val k), (1 : ℝ) / (2 * min (ZMod.val k : ℝ) ((n : ℝ) - ZMod.val k)) = (1 / (d : ℝ)) * ∑ j ∈ Finset.Icc 1 (N - 1), (1 : ℝ) / (2 * min (j : ℝ) ((N : ℝ) - j)) := by simp only rw [Finset.mul_sum] apply Finset.sum_nbij' (fun k => ZMod.val k / d) (fun j => (↑(j * d) : ZMod n)) · exact fun k hk => bwd_mem n d hd_dvd hd_pos k hk · exact fun j hj => fwd_mem n d hd_dvd hd_pos j hj · exact fun k hk => right_inv n d hd_dvd hd_pos k hk · exact fun j hj => left_inv n d hd_dvd hd_pos j hj · intro k hk exact summand_eq_via_bwd n d hd_dvd hd_pos k hk lemma weight_sum_multiples_of_d_bound (n d : ℕ) [NeZero n] [NeZero d] (hn : 2 ≤ n) (hd_dvd : d ∣ n) (hd_pos : 0 < d) : ∑ k ∈ Finset.univ.filter (fun k : ZMod n => k ≠ 0 ∧ (d : ℕ) ∣ ZMod.val k), (1 : ℝ) / (2 * min (ZMod.val k : ℝ) ((n : ℝ) - ZMod.val k)) ≤ (1 + Real.log (n : ℝ)) / d := by have hd_cast : (0 : ℝ) < (d : ℝ) := Nat.cast_pos.mpr hd_pos rw [reindex_multiples_of_d n d hd_dvd hd_pos] have h := symmetric_sum_le_one_plus_log n d hn hd_dvd hd_pos calc 1 / (d : ℝ) * ∑ j ∈ Finset.Icc 1 (n / d - 1), (1 : ℝ) / (2 * min (j : ℝ) ((↑(n / d) : ℝ) - j)) ≤ 1 / (d : ℝ) * (1 + Real.log n) := by apply mul_le_mul_of_nonneg_left h positivity _ = (1 + Real.log (n : ℝ)) / d := by ring lemma d_dvd_n (n : ℕ) (hn : 2 ≤ n) : largestPrimeFactor n ^ n.factorization (largestPrimeFactor n) ∣ n := by exact Nat.ordProj_dvd n (largestPrimeFactor n) lemma coprimality_q_d (n : ℕ) (hn : 2 ≤ n) (q : ℤ) (hq_coprime : Int.gcd q (largestPrimeFactor n : ℤ) = 1) (d : ℕ) (hd : d = largestPrimeFactor n ^ n.factorization (largestPrimeFactor n)) : Int.gcd q (d : ℤ) = 1 := by rw [hd, Nat.cast_pow] exact Int.isCoprime_iff_gcd_eq_one.mp (Int.isCoprime_iff_gcd_eq_one.mpr hq_coprime |>.pow_right) lemma simplify_u_sum_when_d_dvd_k (n d : ℕ) [NeZero n] [NeZero d] (mq : ℕ) (q : ℤ) (k : ZMod n) (hdk : (d : ℕ) ∣ ZMod.val k) (hq_coprime_d : Int.gcd q (d : ℤ) = 1) : (∑ u : (ZMod d)ˣ, (∑ l : ZMod n, if ((d : ℤ) ∣ (↑(ZMod.val k) * ↑(u : ZMod d).val + ↑(ZMod.val l) * q)) then ‖normalizedDFT n (intervalIndicator n mq) l‖ else 0)) = ↑(Fintype.card (ZMod d)ˣ) * (∑ l : ZMod n, if ((d : ℤ) ∣ ↑(ZMod.val l)) then ‖normalizedDFT n (intervalIndicator n mq) l‖ else 0) := by have h : ∀ u : (ZMod d)ˣ, (∑ l : ZMod n, if ((d : ℤ) ∣ (↑(ZMod.val k) * ↑(u : ZMod d).val + ↑(ZMod.val l) * q)) then ‖normalizedDFT n (intervalIndicator n mq) l‖ else 0) = (∑ l : ZMod n, if ((d : ℤ) ∣ ↑(ZMod.val l)) then ‖normalizedDFT n (intervalIndicator n mq) l‖ else 0) := by intro u apply Finset.sum_congr rfl intro l _ have h := dvd_simplify_multiple_case n d k l u q hdk hq_coprime_d simp only [h] simp_rw [h] simp [Finset.sum_const, Finset.card_univ, nsmul_eq_mul] lemma restricted_fourier_mass_le (n d : ℕ) [NeZero n] [NeZero d] (hn : 2 ≤ n) (mq : ℕ) (hmq1 : 1 ≤ mq) (hmq2 : mq < n) : (∑ l : ZMod n, if ((d : ℤ) ∣ ↑(ZMod.val l)) then ‖normalizedDFT n (intervalIndicator n mq) l‖ else 0) ≤ 1 + Real.log (n : ℝ) := by calc (∑ l : ZMod n, if ((d : ℤ) ∣ ↑(ZMod.val l)) then ‖normalizedDFT n (intervalIndicator n mq) l‖ else 0) ≤ ∑ l : ZMod n, ‖normalizedDFT n (intervalIndicator n mq) l‖ := by apply Finset.sum_le_sum intro l _ split_ifs with h · exact le_refl _ · exact norm_nonneg _ _ ≤ 1 + Real.log (n : ℝ) := fourier_intervalIndicator_l1_bound n hn mq hmq1 hmq2 lemma triple_sum_eq_card_times_product (n d : ℕ) [NeZero n] [NeZero d] (hn : 2 ≤ n) (mq : ℕ) (q : ℤ) (hq_coprime_d : Int.gcd q (d : ℤ) = 1) (hd_dvd : d ∣ n) : (∑ k ∈ Finset.univ.filter (fun k : ZMod n => k ≠ 0 ∧ (d : ℕ) ∣ ZMod.val k), ∑ u : (ZMod d)ˣ, (∑ l : ZMod n, if ((d : ℤ) ∣ (↑(ZMod.val k) * ↑(u : ZMod d).val + ↑(ZMod.val l) * q)) then ‖normalizedDFT n (intervalIndicator n mq) l‖ / (2 * min (ZMod.val k : ℝ) ((n : ℝ) - ZMod.val k)) else 0)) ≤ ↑(Fintype.card (ZMod d)ˣ) * (∑ l : ZMod n, if ((d : ℤ) ∣ ↑(ZMod.val l)) then ‖normalizedDFT n (intervalIndicator n mq) l‖ else 0) * (∑ k ∈ Finset.univ.filter (fun k : ZMod n => k ≠ 0 ∧ (d : ℕ) ∣ ZMod.val k), (1 : ℝ) / (2 * min (ZMod.val k : ℝ) ((n : ℝ) - ZMod.val k))) := by set A := (∑ l : ZMod n, if ((d : ℤ) ∣ ↑(ZMod.val l)) then ‖normalizedDFT n (intervalIndicator n mq) l‖ else 0) with hA_def set C := (Fintype.card (ZMod d)ˣ : ℝ) with hC_def have hk_eq : ∀ k ∈ Finset.univ.filter (fun k : ZMod n => k ≠ 0 ∧ (d : ℕ) ∣ ZMod.val k), (∑ u : (ZMod d)ˣ, (∑ l : ZMod n, if ((d : ℤ) ∣ (↑(ZMod.val k) * ↑(u : ZMod d).val + ↑(ZMod.val l) * q)) then ‖normalizedDFT n (intervalIndicator n mq) l‖ / (2 * min (ZMod.val k : ℝ) ((n : ℝ) - ZMod.val k)) else 0)) = C * A / (2 * min (ZMod.val k : ℝ) ((n : ℝ) - ZMod.val k)) := by intro k hk simp only [Finset.mem_filter, Finset.mem_univ, true_and] at hk rw [factor_weight_from_double_sum n d mq q k hk.1, simplify_u_sum_when_d_dvd_k n d mq q k hk.2 hq_coprime_d] have lhs_eq : (∑ k ∈ Finset.univ.filter (fun k : ZMod n => k ≠ 0 ∧ (d : ℕ) ∣ ZMod.val k), (∑ u : (ZMod d)ˣ, (∑ l : ZMod n, if ((d : ℤ) ∣ (↑(ZMod.val k) * ↑(u : ZMod d).val + ↑(ZMod.val l) * q)) then ‖normalizedDFT n (intervalIndicator n mq) l‖ / (2 * min (ZMod.val k : ℝ) ((n : ℝ) - ZMod.val k)) else 0))) = C * A * ∑ k ∈ Finset.univ.filter (fun k : ZMod n => k ≠ 0 ∧ (d : ℕ) ∣ ZMod.val k), 1 / (2 * min (ZMod.val k : ℝ) ((n : ℝ) - ZMod.val k)) := by rw [Finset.sum_congr rfl hk_eq] simp_rw [div_eq_mul_inv] rw [← Finset.mul_sum] congr 1 simp linarith [le_refl (C * A * ∑ k ∈ Finset.univ.filter (fun k : ZMod n => k ≠ 0 ∧ (d : ℕ) ∣ ZMod.val k), 1 / (2 * min (ZMod.val k : ℝ) ((n : ℝ) - ZMod.val k)))] lemma triple_sum_bound_via_factoring (n d : ℕ) [NeZero n] [NeZero d] (hn : 2 ≤ n) (hd : d = largestPrimeFactor n ^ n.factorization (largestPrimeFactor n)) (q : ℤ) (hq_coprime : Int.gcd q (largestPrimeFactor n : ℤ) = 1) (_hq_pos : 1 ≤ q) (_hq_bound : (q : ℝ) < (n : ℝ) / 2) (mq : ℕ) (_hmq : mq = (2 * q - 1).toNat) (hmq1 : 1 ≤ mq) (hmq2 : mq < n) : (∑ k ∈ Finset.univ.filter (fun k : ZMod n => k ≠ 0 ∧ (d : ℕ) ∣ ZMod.val k), ∑ u : (ZMod d)ˣ, (∑ l : ZMod n, if ((d : ℤ) ∣ (↑(ZMod.val k) * ↑(u : ZMod d).val + ↑(ZMod.val l) * q)) then ‖normalizedDFT n (intervalIndicator n mq) l‖ / (2 * min (ZMod.val k : ℝ) ((n : ℝ) - ZMod.val k)) else 0)) ≤ ↑(Fintype.card (ZMod d)ˣ) * ((1 + Real.log ↑n) ^ 2 / ↑d) := by have hq_coprime_d : Int.gcd q (d : ℤ) = 1 := coprimality_q_d n hn q hq_coprime d hd have hd_dvd : d ∣ n := hd ▸ d_dvd_n n hn have hd_pos : 0 < d := hd ▸ d_pos n hn have h1 := triple_sum_eq_card_times_product n d hn mq q hq_coprime_d hd_dvd have h2 := restricted_fourier_mass_le n d hn mq hmq1 hmq2 have h3 := weight_sum_multiples_of_d_bound n d hn hd_dvd hd_pos calc (∑ k ∈ Finset.univ.filter (fun k : ZMod n => k ≠ 0 ∧ (d : ℕ) ∣ ZMod.val k), ∑ u : (ZMod d)ˣ, (∑ l : ZMod n, if ((d : ℤ) ∣ (↑(ZMod.val k) * ↑(u : ZMod d).val + ↑(ZMod.val l) * q)) then ‖normalizedDFT n (intervalIndicator n mq) l‖ / (2 * min (ZMod.val k : ℝ) ((n : ℝ) - ZMod.val k)) else 0)) ≤ ↑(Fintype.card (ZMod d)ˣ) * (∑ l : ZMod n, if ((d : ℤ) ∣ ↑(ZMod.val l)) then ‖normalizedDFT n (intervalIndicator n mq) l‖ else 0) * (∑ k ∈ Finset.univ.filter (fun k : ZMod n => k ≠ 0 ∧ (d : ℕ) ∣ ZMod.val k), (1 : ℝ) / (2 * min (ZMod.val k : ℝ) ((n : ℝ) - ZMod.val k))) := h1 _ ≤ ↑(Fintype.card (ZMod d)ˣ) * (1 + Real.log ↑n) * ((1 + Real.log ↑n) / ↑d) := by have hA := h2 have hB := h3 have hcard_nonneg : (0 : ℝ) ≤ ↑(Fintype.card (ZMod d)ˣ) := Nat.cast_nonneg _ have hA_nonneg : (0 : ℝ) ≤ ∑ l : ZMod n, if ((d : ℤ) ∣ ↑(ZMod.val l)) then ‖normalizedDFT n (intervalIndicator n mq) l‖ else 0 := Finset.sum_nonneg (fun l _ => by split_ifs <;> positivity) have hB_nonneg : (0 : ℝ) ≤ ∑ k ∈ Finset.univ.filter (fun k : ZMod n => k ≠ 0 ∧ (d : ℕ) ∣ ZMod.val k), (1 : ℝ) / (2 * min (ZMod.val k : ℝ) ((n : ℝ) - ZMod.val k)) := Finset.sum_nonneg (fun k hk => by have hkne : k ≠ 0 := (Finset.mem_filter.mp hk).2.1 exact div_nonneg zero_le_one (mul_nonneg (by norm_num) (le_of_lt (min_val_pos n k hkne)))) nlinarith [mul_le_mul_of_nonneg_left hA (mul_nonneg hcard_nonneg hB_nonneg), mul_le_mul_of_nonneg_left hB (mul_nonneg hcard_nonneg (le_trans hA_nonneg hA))] _ = ↑(Fintype.card (ZMod d)ˣ) * ((1 + Real.log ↑n) ^ 2 / ↑d) := by ring lemma multiple_d_weighted_bound (n d : ℕ) [NeZero n] [NeZero d] (hn : 2 ≤ n) (hd : d = largestPrimeFactor n ^ n.factorization (largestPrimeFactor n)) (q : ℤ) (hq_coprime : Int.gcd q (largestPrimeFactor n : ℤ) = 1) (hq_pos : 1 ≤ q) (hq_bound : (q : ℝ) < (n : ℝ) / 2) (mq : ℕ) (hmq : mq = (2 * q - 1).toNat) : (∑ k ∈ Finset.univ.filter (fun k : ZMod n => k ≠ 0 ∧ (d : ℕ) ∣ ZMod.val k), ∑ u : (ZMod d)ˣ, (∑ l : ZMod n, if ((d : ℤ) ∣ (↑(ZMod.val k) * ↑(u : ZMod d).val + ↑(ZMod.val l) * q)) then ‖normalizedDFT n (intervalIndicator n mq) l‖ / (2 * min (ZMod.val k : ℝ) ((n : ℝ) - ZMod.val k)) else 0)) ≤ ↑(Fintype.card (ZMod d)ˣ) * ((1 + Real.log ↑n) ^ 2 / ↑d) := by have hmq_valid : 1 ≤ mq ∧ mq < n := by rw [hmq] exact mq_bounds n hn q hq_pos hq_bound exact triple_sum_bound_via_factoring n d hn hd q hq_coprime hq_pos hq_bound mq hmq hmq_valid.1 hmq_valid.2 lemma weight_nonneg (n : ℕ) [NeZero n] (k : ZMod n) (hk : k ≠ 0) : (0 : ℝ) ≤ 2 * min (ZMod.val k : ℝ) ((n : ℝ) - ZMod.val k) := by have h := min_val_pos n k hk linarith lemma weight_sum_le_log (n d : ℕ) [NeZero n] [NeZero d] (hn : 2 ≤ n) : ∑ k ∈ Finset.univ.filter (fun k : ZMod n => k ≠ 0 ∧ ¬((d : ℕ) ∣ ZMod.val k)), (1 : ℝ) / (2 * min (ZMod.val k : ℝ) ((n : ℝ) - ZMod.val k)) ≤ 1 + Real.log ↑n := by have h_subset : Finset.univ.filter (fun k : ZMod n => k ≠ 0 ∧ ¬((d : ℕ) ∣ ZMod.val k)) ⊆ Finset.univ.filter (fun k : ZMod n => k ≠ 0) := by intro k simp only [Finset.mem_filter, Finset.mem_univ, true_and] exact And.left have h_nonneg : ∀ k ∈ Finset.univ.filter (fun k : ZMod n => k ≠ 0), k ∉ Finset.univ.filter (fun k : ZMod n => k ≠ 0 ∧ ¬((d : ℕ) ∣ ZMod.val k)) → 0 ≤ (1 : ℝ) / (2 * min (ZMod.val k : ℝ) ((n : ℝ) - ZMod.val k)) := by intro k hk _ simp only [Finset.mem_filter, Finset.mem_univ, true_and] at hk exact div_nonneg zero_le_one (mul_nonneg (by norm_num) (le_of_lt (min_val_pos n k hk))) calc ∑ k ∈ Finset.univ.filter (fun k : ZMod n => k ≠ 0 ∧ ¬((d : ℕ) ∣ ZMod.val k)), (1 : ℝ) / (2 * min (ZMod.val k : ℝ) ((n : ℝ) - ZMod.val k)) ≤ ∑ k ∈ Finset.univ.filter (fun k : ZMod n => k ≠ 0), (1 : ℝ) / (2 * min (ZMod.val k : ℝ) ((n : ℝ) - ZMod.val k)) := Finset.sum_le_sum_of_subset_of_nonneg h_subset h_nonneg _ = ∑ t ∈ Finset.Icc 1 (n - 1), (1 : ℝ) / (2 * min (t : ℝ) ((n : ℝ) - t)) := sum_nonzero_reindex n hn _ ≤ Real.log n := symmetric_harmonic_sum_le_log n hn _ ≤ 1 + Real.log n := le_add_of_nonneg_left (by norm_num) lemma const_bound_nonneg (n d : ℕ) [NeZero n] [NeZero d] (_hn : 2 ≤ n) : (0 : ℝ) ≤ ↑(Fintype.card (ZMod d)ˣ) * (5 * (1 + Real.log ↑n) / ↑d) := by positivity set_option linter.unusedVariables false set_option linter.unusedSimpArgs false set_option linter.unnecessarySeqFocus false lemma sum_eq_two_mul_half_sum (M : ℕ) : (∑ t ∈ Finset.Icc 1 (M - 1), 1 / min ((t : ℝ)) ((M : ℝ) - (t : ℝ))) = 2 * (∑ t ∈ Finset.Icc 1 (M - 1), (1 : ℝ) / (2 * min (t : ℝ) ((M : ℝ) - t))) := by have h1 : (∑ t ∈ Finset.Icc 1 (M - 1), 1 / min ((t : ℝ)) ((M : ℝ) - (t : ℝ))) = 2 * (∑ t ∈ Finset.Icc 1 (M - 1), (1 : ℝ) / (2 * min (t : ℝ) ((M : ℝ) - t))) := by have h2 : ∀ (t : ℕ), t ∈ Finset.Icc 1 (M - 1) → 1 / (min ((t : ℝ)) ((M : ℝ) - (t : ℝ)) : ℝ) = 2 * ((1 : ℝ) / (2 * min (t : ℝ) ((M : ℝ) - t))) := by intro t ht have h3 : (min ((t : ℝ)) ((M : ℝ) - (t : ℝ)) : ℝ) > 0 := by have h4 : (t : ℕ) ∈ Finset.Icc 1 (M - 1) := ht have h5 : 1 ≤ t := by simp [Finset.mem_Icc] at h4 linarith have h6 : t ≤ M - 1 := by simp [Finset.mem_Icc] at h4 linarith have h8 : (t : ℝ) < M := by have h10 : (M : ℕ) ≥ 1 := by by_contra h have h11 : M = 0 := by omega simp_all [Finset.Icc_eq_empty] have h11 : (t : ℕ) < M := by omega exact_mod_cast h11 have h10 : (min ((t : ℝ)) ((M : ℝ) - (t : ℝ)) : ℝ) > 0 := by cases' le_total ((t : ℝ)) ((M : ℝ) - (t : ℝ)) with h11 h11 <;> simp_all [min_eq_left, min_eq_right, le_of_lt] <;> (try { linarith }) exact h10 have h4 : 1 / (min ((t : ℝ)) ((M : ℝ) - (t : ℝ)) : ℝ) = 2 * ((1 : ℝ) / (2 * min (t : ℝ) ((M : ℝ) - t))) := by have h5 : (min ((t : ℝ)) ((M : ℝ) - (t : ℝ)) : ℝ) = min (t : ℝ) ((M : ℝ) - t) := by simp [min_eq_left, min_eq_right, le_of_lt] rw [h5] field_simp exact h4 calc (∑ t ∈ Finset.Icc 1 (M - 1), 1 / min ((t : ℝ)) ((M : ℝ) - (t : ℝ))) = ∑ t ∈ Finset.Icc 1 (M - 1), (2 * ((1 : ℝ) / (2 * min (t : ℝ) ((M : ℝ) - t)))) := by apply Finset.sum_congr rfl intro t ht rw [h2 t ht] _ = 2 * (∑ t ∈ Finset.Icc 1 (M - 1), (1 : ℝ) / (2 * min (t : ℝ) ((M : ℝ) - t))) := by rw [Finset.mul_sum] exact h1 lemma harmonic_min_sum_le_two_log (M n : ℕ) (hM : 2 ≤ M) (hMn : M ≤ n) : (∑ t ∈ Finset.Icc 1 (M - 1), 1 / min ((t : ℝ)) ((M : ℝ) - (t : ℝ))) ≤ 2 * (1 + Real.log ↑n) := by rw [sum_eq_two_mul_half_sum M] have h1 : ∑ t ∈ Finset.Icc 1 (M - 1), (1 : ℝ) / (2 * min (t : ℝ) ((M : ℝ) - t)) ≤ Real.log M := symmetric_harmonic_sum_le_log M hM have h2 : Real.log (M : ℝ) ≤ Real.log (n : ℝ) := Real.log_le_log (by positivity) (by exact_mod_cast hMn) linarith lemma d_ge_P (n : ℕ) (hn : 2 ≤ n) : largestPrimeFactor n ≤ largestPrimeFactor n ^ n.factorization (largestPrimeFactor n) := by have hP := largestPrimeFactor_pos n hn have hα := largest_prime_factor_multiplicity_pos n hn exact le_self_pow hP (by omega) lemma one_plus_log_nonneg (n : ℕ) (hn : 2 ≤ n) : 0 ≤ 1 + Real.log (n : ℝ) := by have h₁ : 0 ≤ Real.log (n : ℝ) := by have h₂ : (1 : ℝ) ≤ (n : ℝ) := by norm_cast <;> linarith exact Real.log_nonneg h₂ linarith lemma key_val_eq (d : ℕ) [NeZero d] (k_val : ℕ) (hcop : Nat.Coprime k_val d) (u : (ZMod d)ˣ) : let k_unit := ZMod.unitOfCoprime k_val hcop ((k_unit * u : (ZMod d)ˣ) : ZMod d).val = (k_val * (↑u : ZMod d).val) % d := by intro k_unit have h1 : ((k_unit * u : (ZMod d)ˣ) : ZMod d).val = ((↑k_unit : ZMod d) * (↑u : ZMod d)).val := by rfl have h2 : ((↑k_unit : ZMod d) * (↑u : ZMod d)).val = (↑k_unit : ZMod d).val * (↑u : ZMod d).val % d := by exact ZMod.val_mul _ _ have h3 : (↑k_unit : ZMod d) = (↑k_val : ZMod d) := by rfl have h5 : (↑k_val : ZMod d).val = k_val % d := by simp have h7 : ((k_unit * u : (ZMod d)ˣ) : ZMod d).val = (k_val % d * (↑u : ZMod d).val) % d := by simp_all have h8 : (k_val * (↑u : ZMod d).val) % d = (k_val % d * (↑u : ZMod d).val) % d := by simp have h9 : ((k_unit * u : (ZMod d)ˣ) : ZMod d).val = (k_val * (↑u : ZMod d).val) % d := by nlinarith assumption lemma coprime_case_sum_eq (d : ℕ) [NeZero d] (k_val : ℕ) (hcop : Nat.Coprime k_val d) : (∑ u : (ZMod d)ˣ, 1 / min ((k_val * (u : ZMod d).val % d : ℕ) : ℝ) (((d : ℕ) : ℝ) - (k_val * (u : ZMod d).val % d : ℕ))) = (∑ u : (ZMod d)ˣ, 1 / min (((u : ZMod d).val : ℕ) : ℝ) (((d : ℕ) : ℝ) - ((u : ZMod d).val : ℕ))) := by set k_unit := ZMod.unitOfCoprime k_val hcop have lhs_rw : ∀ u : (ZMod d)ˣ, (k_val * (u : ZMod d).val % d : ℕ) = ((k_unit * u : (ZMod d)ˣ) : ZMod d).val := by intro u; exact (key_val_eq d k_val hcop u).symm simp_rw [lhs_rw] exact Fintype.sum_bijective (fun u => k_unit * u) (Equiv.mulLeft k_unit).bijective _ _ (fun u => by simp) lemma units_val_injective (d : ℕ) [NeZero d] : Function.Injective (fun u : (ZMod d)ˣ => (u : ZMod d).val) := (ZMod.val_injective d).comp Units.val_injective lemma unit_val_mem_Icc (d : ℕ) [NeZero d] (hd : 2 ≤ d) (u : (ZMod d)ˣ) : (u : ZMod d).val ∈ Finset.Icc 1 (d - 1) := by have h_val_lt_d : (u : ZMod d).val < d := ZMod.val_lt _ have h_val_coprime_d : Nat.Coprime (u : ZMod d).val d := by exact ZMod.val_coe_unit_coprime u have h_val_pos : 1 ≤ (u : ZMod d).val := by exact Nat.pos_of_ne_zero (fun h => by simp [h, Nat.Coprime] at h_val_coprime_d; omega) have h_val_le_d_sub_one : (u : ZMod d).val ≤ d - 1 := by omega have h_main : (u : ZMod d).val ∈ Finset.Icc 1 (d - 1) := by simp_all exact h_main lemma units_sum_summand_nonneg (d : ℕ) (t : ℕ) (ht : t ∈ Finset.Icc 1 (d - 1)) : (0 : ℝ) ≤ 1 / min ((t : ℝ)) (((d : ℕ) : ℝ) - (t : ℝ)) := by have h₁ : 1 ≤ t := by simp [Finset.mem_Icc] at ht exact ht.1 have h₂ : t ≤ d - 1 := by simp [Finset.mem_Icc] at ht exact ht.2 have h₄ : (d : ℕ) ≥ t + 1 := by have h₄₂ : t + 1 ≤ d := by have h₄₄ : t + 1 ≤ d := by have h₄₅ : d ≥ t + 1 := by by_cases h : d = 0 · simp_all · have h₄₆ : d - 1 + 1 = d := by have h₄₇ : d ≥ 1 := by by_contra h₄₈ simp_all [Nat.sub_eq_zero_iff_le] omega omega omega omega omega have h₅ : ((d : ℕ) : ℝ) - (t : ℝ) > 0 := by have h₅₁ : (d : ℝ) > (t : ℝ) := by have h₅₂ : (d : ℕ) ≥ t + 1 := h₄ have h₅₃ : (d : ℝ) ≥ (t + 1 : ℝ) := by exact_mod_cast h₅₂ linarith linarith have h₆ : (0 : ℝ) < min ((t : ℝ)) (((d : ℕ) : ℝ) - (t : ℝ)) := by apply lt_min · exact_mod_cast by linarith · exact h₅ have h₇ : (0 : ℝ) ≤ 1 / min ((t : ℝ)) (((d : ℕ) : ℝ) - (t : ℝ)) := by have h₇₁ : (0 : ℝ) < min ((t : ℝ)) (((d : ℕ) : ℝ) - (t : ℝ)) := h₆ exact div_nonneg (by norm_num) (le_of_lt h₇₁) exact h₇ lemma units_sum_le_Icc_sum (d : ℕ) [NeZero d] (hd : 2 ≤ d) : (∑ u : (ZMod d)ˣ, 1 / min (((u : ZMod d).val : ℕ) : ℝ) (((d : ℕ) : ℝ) - ((u : ZMod d).val : ℕ))) ≤ (∑ t ∈ Finset.Icc 1 (d - 1), 1 / min ((t : ℝ)) (((d : ℕ) : ℝ) - (t : ℝ))) := by rw [show (∑ u : (ZMod d)ˣ, 1 / min (((u : ZMod d).val : ℕ) : ℝ) (((d : ℕ) : ℝ) - ((u : ZMod d).val : ℕ))) = ∑ t ∈ Finset.univ.image (fun u : (ZMod d)ˣ => (u : ZMod d).val), 1 / min ((t : ℝ)) (((d : ℕ) : ℝ) - (t : ℝ)) from by rw [Finset.sum_image (fun a _ b _ h => units_val_injective d h)]] exact Finset.sum_le_sum_of_subset_of_nonneg (fun t ht => by simp only [Finset.mem_image, Finset.mem_univ, true_and] at ht obtain ⟨u, hu⟩ := ht rw [← hu] exact unit_val_mem_Icc d hd u) (fun t ht _ => units_sum_summand_nonneg d t ht) lemma nat_mul_mod_right (a b n : ℕ) : a * b % n = a * (b % n) % n := by simp lemma kval_mul_unit_mod_eq_pv_mul (d : ℕ) [NeZero d] (p : ℕ) (hp : Nat.Prime p) (α : ℕ) (hα : 1 ≤ α) (hd_eq : d = p ^ α) (k_val : ℕ) (hk_nd : ¬((d : ℕ) ∣ k_val)) (hk_dvd_p : p ∣ k_val) (v : ℕ) (hv_pos : 1 ≤ v) (hv_lt : v < α) (hv_val : p ^ v ∣ k_val) (hv_max : ¬(p ^ (v + 1) ∣ k_val)) [NeZero (p ^ (α - v))] (u : (ZMod d)ˣ) : k_val * (u : ZMod d).val % d = p ^ v * ((k_val / p ^ v) * ((u : ZMod d).val % p ^ (α - v)) % p ^ (α - v)) := by have hd_split : d = p ^ v * p ^ (α - v) := by rw [hd_eq, ← pow_add, Nat.add_sub_cancel' hv_lt.le] set u_val := (u : ZMod d).val with hu_val_def have hk_split : k_val = p ^ v * (k_val / p ^ v) := by rw [mul_comm]; exact (Nat.div_mul_cancel hv_val).symm calc k_val * u_val % d = p ^ v * (k_val / p ^ v) * u_val % (p ^ v * p ^ (α - v)) := by rw [← hk_split, ← hd_split] _ = p ^ v * ((k_val / p ^ v) * u_val) % (p ^ v * p ^ (α - v)) := by ring_nf _ = p ^ v * ((k_val / p ^ v) * u_val % p ^ (α - v)) := by rw [Nat.mul_mod_mul_left] _ = p ^ v * ((k_val / p ^ v) * (u_val % p ^ (α - v)) % p ^ (α - v)) := by rw [nat_mul_mod_right] lemma not_p_dvd_div_pow_1 (p : ℕ) (hp : Nat.Prime p) (k_val v : ℕ) (hv_val : p ^ v ∣ k_val) (hv_max : ¬(p ^ (v + 1) ∣ k_val)) : ¬(p ∣ k_val / p ^ v) := by intro h_dvd have h₁ : p ^ v * (k_val / p ^ v) = k_val := by apply Nat.mul_div_cancel' exact hv_val have h₂ : p ^ (v + 1) ∣ k_val := by have h₃ : p ∣ k_val / p ^ v := h_dvd have h₄ : ∃ m, k_val / p ^ v = p * m := by obtain ⟨m, hm⟩ := h₃ exact ⟨m, by linarith⟩ obtain ⟨m, hm⟩ := h₄ have h₅ : k_val = p ^ v * (p * m) := by calc k_val = p ^ v * (k_val / p ^ v) := by rw [h₁] _ = p ^ v * (p * m) := by rw [hm] have h₆ : k_val = p ^ (v + 1) * m := by calc k_val = p ^ v * (p * m) := h₅ _ = (p ^ v * p) * m := by ring _ = p ^ (v + 1) * m := by simp [pow_succ, mul_assoc] have h₇ : p ^ (v + 1) ∣ k_val := by use m exact h₇ exact hv_max h₂ lemma dvd_of_dvd_mod_of_dvd (p a m : ℕ) (hpm : p ∣ m) (hpr : p ∣ a % m) : p ∣ a := by have h₁ : p ∣ m := hpm have h₂ : p ∣ a % m := hpr have h₃ : p ∣ a := by have h₄ : a % m + m * (a / m) = a := by have h₅ := Nat.mod_add_div a m linarith have h₅ : p ∣ m * (a / m) := dvd_mul_of_dvd_left h₁ (a / m) have h₆ : p ∣ a % m + m * (a / m) := dvd_add h₂ h₅ have h₇ : p ∣ a := by rw [← h₄] exact h₆ exact h₇ exact h₃ lemma not_p_dvd_unit_val_mod (p : ℕ) (hp : Nat.Prime p) (α : ℕ) (hα : 1 ≤ α) (v : ℕ) (hv_lt : v < α) [NeZero (p ^ α)] (u : (ZMod (p ^ α))ˣ) : ¬(p ∣ (u : ZMod (p ^ α)).val % p ^ (α - v)) := by have hcop : (u : ZMod (p ^ α)).val.Coprime (p ^ α) := ZMod.val_coe_unit_coprime u have hcop_p : p.Coprime (u : ZMod (p ^ α)).val := (Nat.Coprime.of_dvd_right (dvd_pow_self p (by omega : α ≠ 0)) hcop).symm have hndvd : ¬ p ∣ (u : ZMod (p ^ α)).val := (hp.coprime_iff_not_dvd.mp hcop_p) have hpdvd : p ∣ p ^ (α - v) := dvd_pow_self p (by omega : α - v ≠ 0) intro h exact hndvd (dvd_of_dvd_mod_of_dvd p (u : ZMod (p ^ α)).val (p ^ (α - v)) hpdvd h) lemma mul_not_dvd_of_not_dvd (p a b : ℕ) (hp : Nat.Prime p) (ha : ¬(p ∣ a)) (hb : ¬(p ∣ b)) : ¬(p ∣ a * b) := by have h : ¬(p ∣ a * b) := by intro h₁ have h₂ : p ∣ a * b := h₁ have h₃ : p ∣ a * b := h₂ have h₄ : p ∣ a ∨ p ∣ b := by have h₅ : p ∣ a * b := h₃ exact hp.dvd_mul.mp h₅ cases h₄ with | inl h₄ => exact ha h₄ | inr h₄ => exact hb h₄ exact h lemma mod_ne_zero_of_not_dvd_prime (p : ℕ) (hp : Nat.Prime p) (k : ℕ) (hk : 1 ≤ k) (n : ℕ) (hn : ¬(p ∣ n)) : n % p ^ k ≠ 0 := by have h₁ : n % p ^ k ≠ 0 := by intro h have h₂ : p ^ k ∣ n := by have h₃ : p ^ k ∣ n := Nat.dvd_of_mod_eq_zero h exact h₃ have h₃ : p ∣ n := by have h₄ : p ∣ p ^ k := by exact dvd_pow_self p (by omega) exact dvd_trans h₄ h₂ contradiction exact h₁ lemma reduced_product_mod_ne_zero (p : ℕ) (hp : Nat.Prime p) (α : ℕ) (hα : 1 ≤ α) (k_val : ℕ) (v : ℕ) (hv_pos : 1 ≤ v) (hv_lt : v < α) (hv_val : p ^ v ∣ k_val) (hv_max : ¬(p ^ (v + 1) ∣ k_val)) [NeZero (p ^ α)] [NeZero (p ^ (α - v))] (u : (ZMod (p ^ α))ˣ) : (k_val / p ^ v) * ((u : ZMod (p ^ α)).val % p ^ (α - v)) % p ^ (α - v) ≠ 0 := by have _ := hv_pos have h1 : ¬(p ∣ k_val / p ^ v) := not_p_dvd_div_pow_1 p hp k_val v hv_val hv_max have h2 : ¬(p ∣ (u : ZMod (p ^ α)).val % p ^ (α - v)) := not_p_dvd_unit_val_mod p hp α hα v hv_lt u have h3 : ¬(p ∣ (k_val / p ^ v) * ((u : ZMod (p ^ α)).val % p ^ (α - v))) := mul_not_dvd_of_not_dvd p _ _ hp h1 h2 exact mod_ne_zero_of_not_dvd_prime p hp (α - v) (by omega) _ h3 lemma min_pv_factor (p : ℕ) (v M x : ℕ) (hx_pos : 0 < x) (hx_lt : x < M) : min ((p ^ v * x : ℕ) : ℝ) (((p ^ v * M : ℕ) : ℝ) - ((p ^ v * x : ℕ) : ℝ)) = ((p ^ v : ℕ) : ℝ) * min ((x : ℕ) : ℝ) (((M : ℕ) : ℝ) - ((x : ℕ) : ℝ)) := by have h_sub_mul : ((p ^ v * M : ℕ) : ℝ) - ((p ^ v * x : ℕ) : ℝ) = ((p ^ v : ℕ) : ℝ) * (((M : ℕ) : ℝ) - ((x : ℕ) : ℝ)) := by push_cast; ring have h_min_mul : ∀ (a b c : ℝ), 0 ≤ a → min (a * b) (a * c) = a * min b c := by exact fun a b c ha => (mul_min_of_nonneg b c ha).symm have h_main : min ((p ^ v * x : ℕ) : ℝ) (((p ^ v * M : ℕ) : ℝ) - ((p ^ v * x : ℕ) : ℝ)) = ((p ^ v : ℕ) : ℝ) * min ((x : ℕ) : ℝ) (((M : ℕ) : ℝ) - ((x : ℕ) : ℝ)) := by simp_all assumption lemma fiber_element_lt (p : ℕ) (hp : Nat.Prime p) (α v : ℕ) (hv_lt : v < α) (s : ℕ) (hs_lt : s < p ^ (α - v)) (j : ℕ) (hj : j < p ^ v) : s + j * p ^ (α - v) < p ^ α := by have h₁ : α - v + v = α := by have h₂ : v ≤ α := by linarith have h₃ : α - v + v = α := by rw [Nat.sub_add_cancel h₂] exact h₃ have h₂ : p ^ α = p ^ (α - v) * p ^ v := by calc p ^ α = p ^ (α - v + v) := by rw [h₁] _ = p ^ (α - v) * p ^ v := by rw [pow_add] _ = p ^ (α - v) * p ^ v := by rfl have h₃ : s + j * p ^ (α - v) < p ^ (α - v) * p ^ v := by have h₆ : p ^ (α - v) > 0 := pow_pos (Nat.Prime.pos hp) (α - v) have h₇ : p ^ v > 0 := pow_pos (Nat.Prime.pos hp) v have h₈ : s + j * p ^ (α - v) ≤ (p ^ (α - v) - 1) + (p ^ v - 1) * p ^ (α - v) := by have h₉ : s ≤ p ^ (α - v) - 1 := by have h₁₁ : s ≤ p ^ (α - v) - 1 := by omega exact h₁₁ have h₁₀ : j ≤ p ^ v - 1 := by have h₁₂ : j ≤ p ^ v - 1 := by omega exact h₁₂ have h₁₁ : j * p ^ (α - v) ≤ (p ^ v - 1) * p ^ (α - v) := by have h₁₂ : j ≤ p ^ v - 1 := h₁₀ have h₁₄ : j * p ^ (α - v) ≤ (p ^ v - 1) * p ^ (α - v) := by exact Nat.mul_le_mul_right (p ^ (α - v)) h₁₂ exact h₁₄ have h₁₂ : s + j * p ^ (α - v) ≤ (p ^ (α - v) - 1) + (p ^ v - 1) * p ^ (α - v) := by calc s + j * p ^ (α - v) ≤ (p ^ (α - v) - 1) + j * p ^ (α - v) := by omega _ ≤ (p ^ (α - v) - 1) + (p ^ v - 1) * p ^ (α - v) := by omega exact h₁₂ have h₉ : (p ^ (α - v) - 1) + (p ^ v - 1) * p ^ (α - v) + 1 = p ^ (α - v) * p ^ v := by have h₁₂ : (p ^ (α - v) - 1) + (p ^ v - 1) * p ^ (α - v) + 1 = p ^ (α - v) * p ^ v := by have h₁₃ : p ^ v - 1 + 1 = p ^ v := by have h₁₅ : p ^ v - 1 + 1 = p ^ v := by omega exact h₁₅ have h₁₄ : (p ^ v - 1) * p ^ (α - v) + p ^ (α - v) = p ^ (α - v) * p ^ v := by calc (p ^ v - 1) * p ^ (α - v) + p ^ (α - v) = (p ^ v - 1 + 1) * p ^ (α - v) := by ring_nf _ = p ^ v * p ^ (α - v) := by have h₁₅ : p ^ v - 1 + 1 = p ^ v := by omega rw [h₁₅] _ = p ^ (α - v) * p ^ v := by ring_nf calc (p ^ (α - v) - 1) + (p ^ v - 1) * p ^ (α - v) + 1 = (p ^ (α - v) - 1 + 1) + (p ^ v - 1) * p ^ (α - v) := by ring_nf _ = p ^ (α - v) + (p ^ v - 1) * p ^ (α - v) := by have h₁₅ : p ^ (α - v) - 1 + 1 = p ^ (α - v) := by omega rw [h₁₅] _ = (p ^ v - 1) * p ^ (α - v) + p ^ (α - v) := by ring_nf _ = p ^ (α - v) * p ^ v := by rw [h₁₄] exact h₁₂ have h₁₀ : s + j * p ^ (α - v) < p ^ (α - v) * p ^ v := by have h₁₃ : s + j * p ^ (α - v) < p ^ (α - v) * p ^ v := by omega exact h₁₃ exact h₁₀ calc s + j * p ^ (α - v) < p ^ (α - v) * p ^ v := h₃ _ = p ^ α := by rw [h₂] lemma not_p_dvd_fiber_element (p : ℕ) (hp : Nat.Prime p) (α v : ℕ) (hv_lt : v < α) (s : ℕ) (hs_cop : Nat.Coprime s p) (j : ℕ) : ¬ p ∣ (s + j * p ^ (α - v)) := by have h_main : (s + j * p ^ (α - v)) % p = s % p := by have h₁ : (s + j * p ^ (α - v)) % p = (s % p + (j * p ^ (α - v)) % p) % p := by simp [Nat.add_mod] rw [h₁] have h₂ : (j * p ^ (α - v)) % p = 0 := by have h₃ : p ∣ j * p ^ (α - v) := by have h₄ : p ∣ p ^ (α - v) := by exact dvd_pow_self p (by have h₅ : α - v ≥ 1 := by have h₇ : α - v > 0 := by omega omega omega) exact dvd_mul_of_dvd_right h₄ j exact Nat.mod_eq_zero_of_dvd h₃ rw [h₂] <;> simp [Nat.add_mod, Nat.zero_mod] have h₂ : s % p ≠ 0 := by intro h₃ have h₄ : p ∣ s := by have h₅ : s % p = 0 := h₃ exact Nat.dvd_of_mod_eq_zero h₅ have h₅ : p ∣ s := h₄ have h₆ : ¬p ∣ s := by have h₇ : Nat.Coprime s p := hs_cop have h₈ : ¬p ∣ s := by by_contra h₉ have h₁₀ : p ∣ s := h₉ have h₁₁ : p ∣ Nat.gcd s p := Nat.dvd_gcd h₁₀ (by simp [Nat.dvd_refl]) have h₁₂ : Nat.gcd s p = 1 := by rw [Nat.coprime_iff_gcd_eq_one] at hs_cop exact hs_cop rw [h₁₂] at h₁₁ have h₁₃ : p ∣ 1 := h₁₁ have h₁₄ : p ≤ 1 := Nat.le_of_dvd (by norm_num) h₁₃ have h₁₅ : p ≥ 2 := Nat.Prime.two_le hp linarith exact h₈ exact h₆ h₅ intro h have h₅ : s % p = 0 := by omega contradiction lemma fiber_element_coprime (p : ℕ) (hp : Nat.Prime p) (α v : ℕ) (hv_lt : v < α) (s : ℕ) (hs_cop : Nat.Coprime s p) (j : ℕ) : Nat.Coprime (s + j * p ^ (α - v)) (p ^ α) := by exact hp.coprime_pow_of_not_dvd (not_p_dvd_fiber_element p hp α v hv_lt s hs_cop j) lemma fiber_element_mod_eq (p : ℕ) (α v : ℕ) (s : ℕ) (hs_lt : s < p ^ (α - v)) (j : ℕ) : (s + j * p ^ (α - v)) % p ^ (α - v) = s := by have h₁ : (s + j * p ^ (α - v)) % p ^ (α - v) = s % p ^ (α - v) := by have h₂ : (s + j * p ^ (α - v)) % p ^ (α - v) = (s % p ^ (α - v) + (j * p ^ (α - v)) % p ^ (α - v)) % p ^ (α - v) := by simp [Nat.add_mod] rw [h₂] have h₃ : (j * p ^ (α - v)) % p ^ (α - v) = 0 := by have h₄ : p ^ (α - v) ∣ j * p ^ (α - v) := by exact ⟨j, by ring⟩ have h₅ : (j * p ^ (α - v)) % p ^ (α - v) = 0 := by exact Nat.mod_eq_zero_of_dvd h₄ exact h₅ rw [h₃] have h₆ : (s % p ^ (α - v) + 0) % p ^ (α - v) = s % p ^ (α - v) := by simp [Nat.add_mod] rw [h₆] rw [h₁] have h₂ : s % p ^ (α - v) = s := by have h₃ : s < p ^ (α - v) := hs_lt have h₄ : s % p ^ (α - v) = s := Nat.mod_eq_of_lt h₃ exact h₄ rw [h₂] lemma fiber_index_lt (p : ℕ) (hp : Nat.Prime p) (α v : ℕ) (hv_lt : v < α) [NeZero (p ^ α)] (s : ℕ) (hs_lt : s < p ^ (α - v)) (u : (ZMod (p ^ α))ˣ) (hu : (u : ZMod (p ^ α)).val % p ^ (α - v) = s) : ((u : ZMod (p ^ α)).val - s) / p ^ (α - v) < p ^ v := by have h₁ : ((u : ZMod (p ^ α)).val : ℕ) < p ^ α := by have h₂ : (u : ZMod (p ^ α)).val < p ^ α := by exact ZMod.val_lt _ exact_mod_cast h₂ have h₃ : ((u : ZMod (p ^ α)).val - s) / p ^ (α - v) < p ^ v := by have h₄ : α - v + v = α := by have h₅ : v ≤ α := by linarith have h₆ : α - v + v = α := by rw [Nat.sub_add_cancel h₅] exact h₆ have h₅ : p ^ (α - v) * p ^ v = p ^ α := by calc p ^ (α - v) * p ^ v = p ^ ((α - v) + v) := by rw [← pow_add] _ = p ^ α := by rw [h₄] have h₆ : ((u : ZMod (p ^ α)).val - s) / p ^ (α - v) < p ^ v := by have h₇ : ((u : ZMod (p ^ α)).val - s) < p ^ (α - v) * p ^ v := by have h₁₀ : ((u : ZMod (p ^ α)).val - s) ≤ (u : ZMod (p ^ α)).val := by omega omega have h₈ : ((u : ZMod (p ^ α)).val - s) / p ^ (α - v) < p ^ v := by have h₁₀ : ((u : ZMod (p ^ α)).val - s) / p ^ (α - v) < p ^ v := by apply Nat.div_lt_of_lt_mul nlinarith [Nat.zero_le (p ^ (α - v))] exact h₁₀ exact h₈ exact h₆ exact h₃ lemma fiber_reconstruct (M s n : ℕ) (hn : n % M = s) (hs_le : s ≤ n) : s + (n - s) / M * M = n := by have h₁ : M * (n / M) + s = n := by have h₁₀ : M * (n / M) + n % M = n := Nat.div_add_mod n M rw [hn] at h₁₀ <;> linarith have h₂ : M * (n / M) = n - s := by have h₂₃ : M * (n / M) = n - s := by have h₂₅ : M * (n / M) = n - s := by omega exact h₂₅ exact h₂₃ have h₃ : M ∣ n - s := by have h₃₂ : M ∣ n - s := by use n / M <;> linarith exact h₃₂ have h₄ : (n - s) / M * M = n - s := by have h₄₁ : M ∣ n - s := h₃ have h₄₂ : (n - s) / M * M = n - s := by have h₄₃ : (n - s) / M * M = n - s := by apply Nat.div_mul_cancel h₄₁ exact h₄₃ exact h₄₂ have h₅ : s + (n - s) / M * M = n := by linarith exact h₅ lemma fiber_fwd_bwd (p : ℕ) (hp : Nat.Prime p) (α v : ℕ) (hv_lt : v < α) [NeZero (p ^ α)] (s : ℕ) (hs_lt : s < p ^ (α - v)) (hs_cop : Nat.Coprime s p) (j : ℕ) (hj : j < p ^ v) : let a := s + j * p ^ (α - v) let hcop := fiber_element_coprime p hp α v hv_lt s hs_cop j ((ZMod.unitOfCoprime a hcop : ZMod (p ^ α)).val - s) / p ^ (α - v) = j := by simp only have ha_lt : s + j * p ^ (α - v) < p ^ α := fiber_element_lt p hp α v hv_lt s hs_lt j hj rw [val_unitOfCoprime_eq_mod, Nat.mod_eq_of_lt ha_lt, Nat.add_sub_cancel_left, Nat.mul_div_cancel _ (Nat.pos_of_ne_zero (pow_ne_zero _ hp.ne_zero))] lemma fiber_bwd_fwd (p : ℕ) (hp : Nat.Prime p) (α v : ℕ) (hv_lt : v < α) [NeZero (p ^ α)] [NeZero (p ^ (α - v))] (s : ℕ) (hs_lt : s < p ^ (α - v)) (hs_cop : Nat.Coprime s p) (u : (ZMod (p ^ α))ˣ) (hu : (u : ZMod (p ^ α)).val % p ^ (α - v) = s) : let idx := ((u : ZMod (p ^ α)).val - s) / p ^ (α - v) let a := s + idx * p ^ (α - v) let hcop := fiber_element_coprime p hp α v hv_lt s hs_cop idx ZMod.unitOfCoprime a hcop = u := by intro idx a hcop apply Units.ext simp only [ZMod.coe_unitOfCoprime] have hkey : a = (u : ZMod (p ^ α)).val := fiber_reconstruct (p ^ (α - v)) s ((u : ZMod (p ^ α)).val) hu (hu ▸ Nat.mod_le _ _) rw [hkey, ZMod.natCast_zmod_val] lemma fiber_fwd_mem (p : ℕ) (hp : Nat.Prime p) (α v : ℕ) (hv_lt : v < α) [NeZero (p ^ α)] (s : ℕ) (hs_lt : s < p ^ (α - v)) (hs_cop : Nat.Coprime s p) (j : ℕ) (hj : j < p ^ v) : let a := s + j * p ^ (α - v) let hcop := fiber_element_coprime p hp α v hv_lt s hs_cop j let u := ZMod.unitOfCoprime a hcop (u : ZMod (p ^ α)).val % p ^ (α - v) = s := by simp only rw [val_unitOfCoprime_eq_mod] rw [Nat.mod_eq_of_lt (fiber_element_lt p hp α v hv_lt s hs_lt j hj)] exact fiber_element_mod_eq p α v s hs_lt j lemma projection_fiber_card (p : ℕ) (hp : Nat.Prime p) (α : ℕ) (_hα : 1 ≤ α) (v : ℕ) (_hv_pos : 1 ≤ v) (hv_lt : v < α) [NeZero (p ^ α)] [NeZero (p ^ (α - v))] (s : ℕ) (hs_lt : s < p ^ (α - v)) (hs_cop : Nat.Coprime s p) : (Finset.univ.filter (fun u : (ZMod (p ^ α))ˣ => (u : ZMod (p ^ α)).val % p ^ (α - v) = s)).card = p ^ v := by set F := Finset.univ.filter (fun u : (ZMod (p ^ α))ˣ => (u : ZMod (p ^ α)).val % p ^ (α - v) = s) set R := Finset.range (p ^ v) set fwd : (ZMod (p ^ α))ˣ → ℕ := fun u => ((u : ZMod (p ^ α)).val - s) / p ^ (α - v) set bwd : ℕ → (ZMod (p ^ α))ˣ := fun j => ZMod.unitOfCoprime (s + j * p ^ (α - v)) (fiber_element_coprime p hp α v hv_lt s hs_cop j) rw [show p ^ v = R.card from (Finset.card_range _).symm] exact Finset.card_nbij' fwd bwd (fun u hu => by simp only [F, Finset.mem_coe, Finset.mem_filter, Finset.mem_univ, true_and] at hu exact Finset.mem_coe.mpr (Finset.mem_range.mpr (fiber_index_lt p hp α v hv_lt s hs_lt u hu))) (fun j hj => by simp only [F, Finset.mem_coe, Finset.mem_filter, Finset.mem_univ, true_and] exact fiber_fwd_mem p hp α v hv_lt s hs_lt hs_cop j (Finset.mem_range.mp (Finset.mem_coe.mp hj))) (fun u hu => by simp only [F, Finset.mem_coe, Finset.mem_filter, Finset.mem_univ, true_and] at hu exact fiber_bwd_fwd p hp α v hv_lt s hs_lt hs_cop u hu) (fun j hj => by exact fiber_fwd_bwd p hp α v hv_lt s hs_lt hs_cop j (Finset.mem_range.mp (Finset.mem_coe.mp hj))) lemma kprime_coprime_p (p : ℕ) (hp : Nat.Prime p) (k_val : ℕ) (v : ℕ) (hv_val : p ^ v ∣ k_val) (hv_max : ¬(p ^ (v + 1) ∣ k_val)) : Nat.Coprime (k_val / p ^ v) p := by have h₁ : ¬p ∣ (k_val / p ^ v) := by intro h have h₂ : p ^ (v + 1) ∣ k_val := by have h₃ : p ∣ (k_val / p ^ v) := h have h₄ : p ^ (v + 1) ∣ k_val := by have h₇ : p ^ (v + 1) ∣ k_val := by have h₈ : p ^ (v + 1) = p ^ v * p := by ring_nf rw [h₈] have h₉ : p ^ v ∣ k_val := hv_val have h₁₀ : p ∣ (k_val / p ^ v) := h₃ have h₁₁ : p ^ v * p ∣ k_val := by obtain ⟨m, hm⟩ := h₉ obtain ⟨n, _⟩ := h₁₀ use m * n rw [hm] simp_all [mul_assoc, mul_comm, mul_left_comm] exact h₁₁ exact h₇ exact h₄ exact hv_max h₂ have h₂ : Nat.Coprime (k_val / p ^ v) p := by have h₄ : ¬p ∣ (k_val / p ^ v) := h₁ have h₅ : Nat.Coprime (k_val / p ^ v) p := by rw [Nat.coprime_comm] apply Nat.Prime.coprime_iff_not_dvd hp |>.mpr exact h₄ exact h₅ exact h₂ lemma reduced_product_mod_lt (p : ℕ) (_hp : Nat.Prime p) (α v : ℕ) (_hv_lt : v < α) [NeZero (p ^ (α - v))] (k_val : ℕ) (u : (ZMod (p ^ α))ˣ) : (k_val / p ^ v) * ((u : ZMod (p ^ α)).val % p ^ (α - v)) % p ^ (α - v) < p ^ (α - v) := by exact Nat.mod_lt _ (Nat.pos_of_ne_zero (NeZero.ne _)) lemma summand_rewrite (p : ℕ) (hp : Nat.Prime p) (α : ℕ) (hα : 1 ≤ α) (k_val : ℕ) (hk_nd : ¬((p ^ α : ℕ) ∣ k_val)) (hk_dvd_p : p ∣ k_val) (v : ℕ) (hv_pos : 1 ≤ v) (hv_lt : v < α) (hv_val : p ^ v ∣ k_val) (hv_max : ¬(p ^ (v + 1) ∣ k_val)) [NeZero (p ^ α)] [NeZero (p ^ (α - v))] : (∑ u : (ZMod (p ^ α))ˣ, 1 / min ((k_val * (u : ZMod (p ^ α)).val % (p ^ α) : ℕ) : ℝ) (((p ^ α : ℕ) : ℝ) - (k_val * (u : ZMod (p ^ α)).val % (p ^ α) : ℕ))) = (∑ u : (ZMod (p ^ α))ˣ, 1 / (((p ^ v : ℕ) : ℝ) * min (((k_val / p ^ v) * ((u : ZMod (p ^ α)).val % p ^ (α - v)) % p ^ (α - v) : ℕ) : ℝ) (((p ^ (α - v) : ℕ) : ℝ) - ((k_val / p ^ v) * ((u : ZMod (p ^ α)).val % p ^ (α - v)) % p ^ (α - v) : ℕ)))) := by congr 1; ext u have hd_eq : p ^ α = p ^ α := rfl have hmod := kval_mul_unit_mod_eq_pv_mul (p ^ α) p hp α hα rfl k_val hk_nd hk_dvd_p v hv_pos hv_lt hv_val hv_max u have hne := reduced_product_mod_ne_zero p hp α hα k_val v hv_pos hv_lt hv_val hv_max u have hlt := reduced_product_mod_lt p hp α v hv_lt k_val u set r := (k_val / p ^ v) * ((u : ZMod (p ^ α)).val % p ^ (α - v)) % p ^ (α - v) have hr_pos : 0 < r := Nat.pos_of_ne_zero hne rw [hmod] have hpow : p ^ α = p ^ v * p ^ (α - v) := by rw [← pow_add]; congr 1; omega rw [hpow] rw [min_pv_factor p v (p ^ (α - v)) r hr_pos hlt] lemma pv_cancel (pv : ℝ) (x : ℝ) (hpv : 0 < pv) (hx : x ≠ 0) : pv * (1 / (pv * x)) = 1 / x := by have h₁ : pv * (1 / (pv * x)) = 1 / x := by have h₂ : pv ≠ 0 := by linarith have h₃ : pv * x ≠ 0 := by intro h₄ have h₅ : x = 0 := by apply mul_left_cancel₀ h₂ nlinarith contradiction field_simp [h₂, h₃] exact h₁ lemma unit_mod_coprime_p (p : ℕ) (hp : Nat.Prime p) (α : ℕ) (hα : 1 ≤ α) (v : ℕ) (hv_lt : v < α) [NeZero (p ^ α)] (u : (ZMod (p ^ α))ˣ) : Nat.Coprime ((u : ZMod (p ^ α)).val % p ^ (α - v)) p := by have hcop : Nat.Coprime (u : ZMod (p ^ α)).val (p ^ α) := ZMod.val_coe_unit_coprime u have hcop_p : Nat.Coprime (u : ZMod (p ^ α)).val p := hcop.coprime_dvd_right (dvd_pow_self p (by omega)) rw [Nat.coprime_comm, hp.coprime_iff_not_dvd] at hcop_p ⊢ intro hdvd exact hcop_p (dvd_of_dvd_mod_of_dvd p (u : ZMod (p ^ α)).val (p ^ (α - v)) (dvd_pow_self p (by omega)) hdvd) lemma summand_fiber_constant (k' M s u_val : ℕ) (hs : u_val % M = s) : k' * (u_val % M) % M = k' * s % M := by subst hs; rfl lemma reduced_product_mod_ne_zero_of_coprime (p : ℕ) (hp : Nat.Prime p) (α : ℕ) (hα : 1 ≤ α) (k_val : ℕ) (v : ℕ) (hv_pos : 1 ≤ v) (hv_lt : v < α) (hv_val : p ^ v ∣ k_val) (hv_max : ¬(p ^ (v + 1) ∣ k_val)) [NeZero (p ^ (α - v))] (s : ℕ) (hs_cop : Nat.Coprime s p) : (k_val / p ^ v) * s % p ^ (α - v) ≠ 0 := by have h₁ : α - v ≥ 1 := by omega have h₃ : (k_val / p ^ v) * s % p ^ (α - v) ≠ 0 := by by_contra h have h₄ : (k_val / p ^ v) * s % p ^ (α - v) = 0 := by simpa using h have h₅ : p ^ (α - v) ∣ (k_val / p ^ v) * s := by rw [Nat.dvd_iff_mod_eq_zero] exact h₄ have h₆ : p ∣ (k_val / p ^ v) * s := by have h₇ : p ∣ p ^ (α - v) := by exact dvd_pow_self p (by omega) exact dvd_trans h₇ h₅ have h₇ : p ∣ (k_val / p ^ v) ∨ p ∣ s := by have h₈ : p.Prime := hp have h₉ : p ∣ (k_val / p ^ v) * s := h₆ exact h₈.dvd_mul.mp h₉ cases h₇ with | inl h₈ => have h₉ : p ∣ (k_val / p ^ v) := h₈ have h₁₀ : p ^ (v + 1) ∣ k_val := by have h₁₃ : p ^ v * (k_val / p ^ v) = k_val := by have h₁₄ : p ^ v ∣ k_val := hv_val have h₁₅ : p ^ v * (k_val / p ^ v) = k_val := by rw [Nat.mul_div_cancel' h₁₄] exact h₁₅ have h₁₆ : p ^ (v + 1) ∣ k_val := by have h₁₇ : p ^ (v + 1) = p ^ v * p := by ring_nf rw [h₁₇] have h₁₈ : p ^ v * p ∣ k_val := by have h₁₉ : p ∣ (k_val / p ^ v) := h₉ have h₂₀ : ∃ m, (k_val / p ^ v) = p * m := by obtain ⟨m, hm⟩ := h₁₉ exact ⟨m, by linarith⟩ obtain ⟨m, hm⟩ := h₂₀ have h₂₁ : p ^ v * (k_val / p ^ v) = p ^ v * (p * m) := by rw [hm] use m <;> linarith exact h₁₈ exact h₁₆ have h₁₁ : p ^ (v + 1) ∣ k_val := h₁₀ exact hv_max h₁₁ | inr h₈ => have h₉ : p ∣ s := h₈ have h₁₀ : p ∣ s := h₉ have h₁₁ : ¬p ∣ s := by have h₁₂ : Nat.Coprime s p := hs_cop have h₁₃ : ¬p ∣ s := by intro h₁₄ have h₁₅ : p ∣ s := h₁₄ have h₁₆ : p ∣ s.gcd p := Nat.dvd_gcd h₁₅ (by simp [Nat.dvd_refl]) have h₁₇ : s.gcd p = 1 := by rw [Nat.coprime_iff_gcd_eq_one] at h₁₂ exact h₁₂ rw [h₁₇] at h₁₆ have h₁₈ : p ∣ 1 := h₁₆ have h₁₉ : p ≤ 1 := Nat.le_of_dvd (by decide) h₁₈ have h₂₀ : p ≥ 2 := Nat.Prime.two_le hp linarith exact h₁₃ exact h₁₁ h₁₀ exact h₃ lemma min_pos_of_ne_zero_lt (r M : ℕ) (hr_ne : r ≠ 0) (hr_lt : r < M) : (0 : ℝ) < min ((r : ℝ)) (((M : ℕ) : ℝ) - (r : ℝ)) := by have h₁ : (0 : ℝ) < (r : ℝ) := by norm_cast exact Nat.pos_of_ne_zero hr_ne have h₂ : (0 : ℝ) < ((M : ℕ) : ℝ) - (r : ℝ) := by have h₃ : (r : ℕ) < M := hr_lt have h₄ : (r : ℝ) < (M : ℝ) := by norm_cast linarith have h₃ : (0 : ℝ) < min ((r : ℝ)) (((M : ℕ) : ℝ) - (r : ℝ)) := by have h₄ : (0 : ℝ) < (r : ℝ) := h₁ have h₅ : (0 : ℝ) < ((M : ℕ) : ℝ) - (r : ℝ) := h₂ exact lt_min h₄ h₅ exact h₃ lemma fiber_sum_cancel (p : ℕ) (hp : Nat.Prime p) (α : ℕ) (hα : 1 ≤ α) (k_val : ℕ) (hk_nd : ¬((p ^ α : ℕ) ∣ k_val)) (v : ℕ) (hv_pos : 1 ≤ v) (hv_lt : v < α) (hv_val : p ^ v ∣ k_val) (hv_max : ¬(p ^ (v + 1) ∣ k_val)) [NeZero (p ^ α)] [NeZero (p ^ (α - v))] (s : ℕ) (hs_lt : s < p ^ (α - v)) (hs_cop : Nat.Coprime s p) : (∑ u ∈ Finset.univ.filter (fun u : (ZMod (p ^ α))ˣ => (u : ZMod (p ^ α)).val % p ^ (α - v) = s), (1 : ℝ) / (((p ^ v : ℕ) : ℝ) * min (((k_val / p ^ v) * ((u : ZMod (p ^ α)).val % p ^ (α - v)) % p ^ (α - v) : ℕ) : ℝ) (((p ^ (α - v) : ℕ) : ℝ) - ((k_val / p ^ v) * ((u : ZMod (p ^ α)).val % p ^ (α - v)) % p ^ (α - v) : ℕ)))) = (1 : ℝ) / min (((k_val / p ^ v) * s % p ^ (α - v) : ℕ) : ℝ) (((p ^ (α - v) : ℕ) : ℝ) - ((k_val / p ^ v) * s % p ^ (α - v) : ℕ)) := by have h_const : ∀ u ∈ Finset.univ.filter (fun u : (ZMod (p ^ α))ˣ => (u : ZMod (p ^ α)).val % p ^ (α - v) = s), (1 : ℝ) / (((p ^ v : ℕ) : ℝ) * min (((k_val / p ^ v) * ((u : ZMod (p ^ α)).val % p ^ (α - v)) % p ^ (α - v) : ℕ) : ℝ) (((p ^ (α - v) : ℕ) : ℝ) - ((k_val / p ^ v) * ((u : ZMod (p ^ α)).val % p ^ (α - v)) % p ^ (α - v) : ℕ))) = (1 : ℝ) / (((p ^ v : ℕ) : ℝ) * min (((k_val / p ^ v) * s % p ^ (α - v) : ℕ) : ℝ) (((p ^ (α - v) : ℕ) : ℝ) - ((k_val / p ^ v) * s % p ^ (α - v) : ℕ))) := by intro u hu simp only [Finset.mem_filter, Finset.mem_univ, true_and] at hu rw [summand_fiber_constant (k_val / p ^ v) (p ^ (α - v)) s _ hu] rw [Finset.sum_congr rfl h_const, Finset.sum_const, nsmul_eq_mul] rw [projection_fiber_card p hp α hα v hv_pos hv_lt s hs_lt hs_cop] have hpv_pos : (0 : ℝ) < ((p ^ v : ℕ) : ℝ) := Nat.cast_pos.mpr (Nat.pos_of_ne_zero (pow_ne_zero v hp.ne_zero)) have hr_ne : (k_val / p ^ v) * s % p ^ (α - v) ≠ 0 := reduced_product_mod_ne_zero_of_coprime p hp α hα k_val v hv_pos hv_lt hv_val hv_max s hs_cop have hr_lt : (k_val / p ^ v) * s % p ^ (α - v) < p ^ (α - v) := Nat.mod_lt _ (Nat.pos_of_ne_zero (NeZero.ne _)) have hmin_ne : (min (((k_val / p ^ v) * s % p ^ (α - v) : ℕ) : ℝ) (((p ^ (α - v) : ℕ) : ℝ) - ((k_val / p ^ v) * s % p ^ (α - v) : ℕ))) ≠ 0 := ne_of_gt (min_pos_of_ne_zero_lt _ _ hr_ne hr_lt) exact pv_cancel ((p ^ v : ℕ) : ℝ) _ hpv_pos hmin_ne lemma unit_mod_coprime_pow (p : ℕ) (hp : Nat.Prime p) (α : ℕ) (hα : 1 ≤ α) (v : ℕ) (hv_lt : v < α) [NeZero (p ^ α)] (u : (ZMod (p ^ α))ˣ) : Nat.Coprime ((u : ZMod (p ^ α)).val % p ^ (α - v)) (p ^ (α - v)) := hp.coprime_pow_of_not_dvd ((hp.coprime_iff_not_dvd.mp (unit_mod_coprime_p p hp α hα v hv_lt u).symm)) lemma unitProjection_filter_iff (p : ℕ) (hp : Nat.Prime p) (α : ℕ) (hα : 1 ≤ α) (v : ℕ) (hv_lt : v < α) [NeZero (p ^ α)] [NeZero (p ^ (α - v))] (u : (ZMod (p ^ α))ˣ) (t : (ZMod (p ^ (α - v)))ˣ) : ZMod.unitOfCoprime ((u : ZMod (p ^ α)).val % p ^ (α - v)) (unit_mod_coprime_pow p hp α hα v hv_lt u) = t ↔ (u : ZMod (p ^ α)).val % p ^ (α - v) = (t : ZMod (p ^ (α - v))).val := by constructor · intro h have hval : (ZMod.unitOfCoprime ((u : ZMod (p ^ α)).val % p ^ (α - v)) (unit_mod_coprime_pow p hp α hα v hv_lt u) : ZMod (p ^ (α - v))).val = (t : ZMod (p ^ (α - v))).val := by rw [h] rw [val_unitOfCoprime_eq_mod] at hval rwa [Nat.mod_eq_of_lt (Nat.mod_lt _ (Nat.pos_of_ne_zero (NeZero.ne _)))] at hval · intro h apply Units.val_injective apply ZMod.val_injective rw [val_unitOfCoprime_eq_mod, Nat.mod_eq_of_lt (Nat.mod_lt _ (Nat.pos_of_ne_zero (NeZero.ne _))), h] lemma fiberwise_sum_eq_double_sum (p : ℕ) (hp : Nat.Prime p) (α : ℕ) (hα : 1 ≤ α) (k_val : ℕ) (hk_nd : ¬((p ^ α : ℕ) ∣ k_val)) (v : ℕ) (hv_pos : 1 ≤ v) (hv_lt : v < α) (hv_val : p ^ v ∣ k_val) (hv_max : ¬(p ^ (v + 1) ∣ k_val)) [NeZero (p ^ α)] [NeZero (p ^ (α - v))] : (∑ u : (ZMod (p ^ α))ˣ, 1 / (((p ^ v : ℕ) : ℝ) * min (((k_val / p ^ v) * ((u : ZMod (p ^ α)).val % p ^ (α - v)) % p ^ (α - v) : ℕ) : ℝ) (((p ^ (α - v) : ℕ) : ℝ) - ((k_val / p ^ v) * ((u : ZMod (p ^ α)).val % p ^ (α - v)) % p ^ (α - v) : ℕ)))) = ∑ t : (ZMod (p ^ (α - v)))ˣ, ∑ u ∈ Finset.univ.filter (fun u : (ZMod (p ^ α))ˣ => (u : ZMod (p ^ α)).val % p ^ (α - v) = (t : ZMod (p ^ (α - v))).val), (1 : ℝ) / (((p ^ v : ℕ) : ℝ) * min (((k_val / p ^ v) * ((u : ZMod (p ^ α)).val % p ^ (α - v)) % p ^ (α - v) : ℕ) : ℝ) (((p ^ (α - v) : ℕ) : ℝ) - ((k_val / p ^ v) * ((u : ZMod (p ^ α)).val % p ^ (α - v)) % p ^ (α - v) : ℕ))) := by set π : (ZMod (p ^ α))ˣ → (ZMod (p ^ (α - v)))ˣ := fun u => ZMod.unitOfCoprime ((u : ZMod (p ^ α)).val % p ^ (α - v)) (unit_mod_coprime_pow p hp α hα v hv_lt u) with hπ_def set f : (ZMod (p ^ α))ˣ → ℝ := fun u => 1 / (((p ^ v : ℕ) : ℝ) * min (((k_val / p ^ v) * ((u : ZMod (p ^ α)).val % p ^ (α - v)) % p ^ (α - v) : ℕ) : ℝ) (((p ^ (α - v) : ℕ) : ℝ) - ((k_val / p ^ v) * ((u : ZMod (p ^ α)).val % p ^ (α - v)) % p ^ (α - v) : ℕ))) with hf_def have h_fiber : ∑ t : (ZMod (p ^ (α - v)))ˣ, ∑ u ∈ Finset.univ.filter (fun u => π u = t), f u = ∑ u : (ZMod (p ^ α))ˣ, f u := Finset.sum_fiberwise_of_maps_to (fun _ _ => Finset.mem_univ _) f rw [show ∑ u : (ZMod (p ^ α))ˣ, f u = ∑ t, ∑ u ∈ Finset.univ.filter (fun u => π u = t), f u from h_fiber.symm] congr 1 ext t apply Finset.sum_congr · ext u simp only [Finset.mem_filter, Finset.mem_univ, true_and] exact unitProjection_filter_iff p hp α hα v hv_lt u t · intros; rfl lemma fiber_grouping_step (p : ℕ) (hp : Nat.Prime p) (α : ℕ) (hα : 1 ≤ α) (k_val : ℕ) (hk_nd : ¬((p ^ α : ℕ) ∣ k_val)) (v : ℕ) (hv_pos : 1 ≤ v) (hv_lt : v < α) (hv_val : p ^ v ∣ k_val) (hv_max : ¬(p ^ (v + 1) ∣ k_val)) [NeZero (p ^ α)] [NeZero (p ^ (α - v))] : (∑ u : (ZMod (p ^ α))ˣ, 1 / (((p ^ v : ℕ) : ℝ) * min (((k_val / p ^ v) * ((u : ZMod (p ^ α)).val % p ^ (α - v)) % p ^ (α - v) : ℕ) : ℝ) (((p ^ (α - v) : ℕ) : ℝ) - ((k_val / p ^ v) * ((u : ZMod (p ^ α)).val % p ^ (α - v)) % p ^ (α - v) : ℕ)))) = (∑ t : (ZMod (p ^ (α - v)))ˣ, 1 / min (((k_val / p ^ v) * (t : ZMod (p ^ (α - v))).val % p ^ (α - v) : ℕ) : ℝ) (((p ^ (α - v) : ℕ) : ℝ) - ((k_val / p ^ v) * (t : ZMod (p ^ (α - v))).val % p ^ (α - v) : ℕ))) := by rw [fiberwise_sum_eq_double_sum p hp α hα k_val hk_nd v hv_pos hv_lt hv_val hv_max] congr 1 ext t have ht_lt : (t : ZMod (p ^ (α - v))).val < p ^ (α - v) := ZMod.val_lt (t : ZMod (p ^ (α - v))) have ht_cop : Nat.Coprime (t : ZMod (p ^ (α - v))).val p := (ZMod.val_coe_unit_coprime t).coprime_dvd_right (dvd_pow_self p (by omega : α - v ≠ 0)) exact fiber_sum_cancel p hp α hα k_val hk_nd v hv_pos hv_lt hv_val hv_max (t : ZMod (p ^ (α - v))).val ht_lt ht_cop lemma coprime_of_prime_power_not_dvd (d : ℕ) (p : ℕ) (hp : Nat.Prime p) (α : ℕ) (hα : 1 ≤ α) (hd_eq : d = p ^ α) (k_val : ℕ) (hp_ndvd : ¬(p ∣ k_val)) : Nat.Coprime k_val d := by rw [hd_eq] have h₁ : Nat.Coprime k_val (p ^ α) := by have h₂ : ¬p ∣ k_val := hp_ndvd have h₃ : Nat.Coprime k_val p := by rw [Nat.coprime_comm] simpa [Nat.prime_iff_prime_int.mp hp] using hp.coprime_iff_not_dvd.mpr h₂ exact Nat.Coprime.pow_right _ h₃ exact h₁ lemma permutation_step (p : ℕ) (hp : Nat.Prime p) (α : ℕ) (_hα : 1 ≤ α) (k_val : ℕ) (v : ℕ) (_hv_pos : 1 ≤ v) (hv_lt : v < α) (hv_val : p ^ v ∣ k_val) (hv_max : ¬(p ^ (v + 1) ∣ k_val)) [NeZero (p ^ (α - v))] : (∑ t : (ZMod (p ^ (α - v)))ˣ, 1 / min (((k_val / p ^ v) * (t : ZMod (p ^ (α - v))).val % p ^ (α - v) : ℕ) : ℝ) (((p ^ (α - v) : ℕ) : ℝ) - ((k_val / p ^ v) * (t : ZMod (p ^ (α - v))).val % p ^ (α - v) : ℕ))) = (∑ t : (ZMod (p ^ (α - v)))ˣ, 1 / min (((t : ZMod (p ^ (α - v))).val : ℕ) : ℝ) (((p ^ (α - v) : ℕ) : ℝ) - ((t : ZMod (p ^ (α - v))).val : ℕ))) := by have hndvd : ¬(p ∣ k_val / p ^ v) := not_p_dvd_div_pow_1 p hp k_val v hv_val hv_max have hcop : Nat.Coprime (k_val / p ^ v) (p ^ (α - v)) := coprime_of_prime_power_not_dvd (p ^ (α - v)) p hp (α - v) (by omega) rfl (k_val / p ^ v) hndvd exact coprime_case_sum_eq (p ^ (α - v)) (k_val / p ^ v) hcop lemma orbit_fiber_sum_eq (d : ℕ) [NeZero d] (p : ℕ) (hp : Nat.Prime p) (α : ℕ) (hα : 1 ≤ α) (hd_eq : d = p ^ α) (k_val : ℕ) (hk_nd : ¬((d : ℕ) ∣ k_val)) (hk_dvd_p : p ∣ k_val) (v : ℕ) (hv_pos : 1 ≤ v) (hv_lt : v < α) (hv_val : p ^ v ∣ k_val) (hv_max : ¬(p ^ (v + 1) ∣ k_val)) [NeZero (p ^ (α - v))] : (∑ u : (ZMod d)ˣ, 1 / min ((k_val * (u : ZMod d).val % d : ℕ) : ℝ) (((d : ℕ) : ℝ) - (k_val * (u : ZMod d).val % d : ℕ))) = (∑ t : (ZMod (p ^ (α - v)))ˣ, 1 / min (((t : ZMod (p ^ (α - v))).val : ℕ) : ℝ) (((p ^ (α - v) : ℕ) : ℝ) - ((t : ZMod (p ^ (α - v))).val : ℕ))) := by subst hd_eq calc (∑ u : (ZMod (p ^ α))ˣ, 1 / min ((k_val * (u : ZMod (p ^ α)).val % (p ^ α) : ℕ) : ℝ) (((p ^ α : ℕ) : ℝ) - (k_val * (u : ZMod (p ^ α)).val % (p ^ α) : ℕ))) = (∑ u : (ZMod (p ^ α))ˣ, 1 / (((p ^ v : ℕ) : ℝ) * min (((k_val / p ^ v) * ((u : ZMod (p ^ α)).val % p ^ (α - v)) % p ^ (α - v) : ℕ) : ℝ) (((p ^ (α - v) : ℕ) : ℝ) - ((k_val / p ^ v) * ((u : ZMod (p ^ α)).val % p ^ (α - v)) % p ^ (α - v) : ℕ)))) := by exact summand_rewrite p hp α hα k_val hk_nd hk_dvd_p v hv_pos hv_lt hv_val hv_max _ = (∑ t : (ZMod (p ^ (α - v)))ˣ, 1 / min (((k_val / p ^ v) * (t : ZMod (p ^ (α - v))).val % p ^ (α - v) : ℕ) : ℝ) (((p ^ (α - v) : ℕ) : ℝ) - ((k_val / p ^ v) * (t : ZMod (p ^ (α - v))).val % p ^ (α - v) : ℕ))) := by exact fiber_grouping_step p hp α hα k_val hk_nd v hv_pos hv_lt hv_val hv_max _ = (∑ t : (ZMod (p ^ (α - v)))ˣ, 1 / min (((t : ZMod (p ^ (α - v))).val : ℕ) : ℝ) (((p ^ (α - v) : ℕ) : ℝ) - ((t : ZMod (p ^ (α - v))).val : ℕ))) := by exact permutation_step p hp α hα k_val v hv_pos hv_lt hv_val hv_max lemma distribute_two_over_sum (k : ℕ) (hk : 1 ≤ k) : 2 * ((∑ u ∈ Finset.Icc 1 (k - 1), (u : ℝ)⁻¹) + 1 / (2 * (k : ℝ))) = 2 * (∑ u ∈ Finset.Icc 1 (k - 1), (u : ℝ)⁻¹) + 1 / (k : ℝ) := by have h₁ : (2 : ℝ) * (1 / (2 * (k : ℝ))) = 1 / (k : ℝ) := by have h₂ : (k : ℝ) ≠ 0 := by norm_cast <;> (try omega) field_simp [h₂] calc 2 * ((∑ u ∈ Finset.Icc 1 (k - 1), (u : ℝ)⁻¹) + 1 / (2 * (k : ℝ))) = 2 * (∑ u ∈ Finset.Icc 1 (k - 1), (u : ℝ)⁻¹) + 2 * (1 / (2 * (k : ℝ))) := by ring_nf _ = 2 * (∑ u ∈ Finset.Icc 1 (k - 1), (u : ℝ)⁻¹) + 1 / (k : ℝ) := by rw [h₁] lemma even_step_lhs_eq (k : ℕ) (hk : 1 ≤ k) : (∑ t ∈ Finset.Icc 1 (2 * k - 1), 1 / min ((t : ℝ)) ((2 * k : ℝ) - (t : ℝ))) = 2 * (∑ u ∈ Finset.Icc 1 (k - 1), (u : ℝ)⁻¹) + 1 / (k : ℝ) := by have h1 : (∑ t ∈ Finset.Icc 1 (2 * k - 1), 1 / min ((t : ℝ)) ((2 * k : ℝ) - (t : ℝ))) = 2 * (∑ t ∈ Finset.Icc 1 (2 * k - 1), (1 : ℝ) / (2 * min (t : ℝ) ((2 * k : ℝ) - t))) := by have := sum_eq_two_mul_half_sum (2 * k) simp only [Nat.cast_mul, Nat.cast_ofNat] at this exact this rw [h1, symmetric_sum_even k hk] exact distribute_two_over_sum k hk lemma lhs_eq_1 (k : ℕ) (hk : 1 ≤ k) : (∑ t ∈ Finset.Icc 1 (2 * k), 1 / min ((t : ℝ)) ((2 * (k : ℝ) + 1) - (t : ℝ))) = 2 * ∑ u ∈ Finset.Icc 1 k, (u : ℝ)⁻¹ := by have h1 := sum_eq_two_mul_half_sum (2 * k + 1) simp only [show (2 * k + 1) - 1 = 2 * k from by omega] at h1 push_cast [Nat.cast_add, Nat.cast_mul, Nat.cast_one] at h1 rw [h1] congr 1 exact symmetric_sum_odd k hk lemma harmonic_split (k : ℕ) (hk : 1 ≤ k) : ∑ u ∈ Finset.Icc 1 k, (u : ℝ)⁻¹ = (∑ u ∈ Finset.Icc 1 (k - 1), (u : ℝ)⁻¹) + (k : ℝ)⁻¹ := by have h₁ : ∑ u ∈ Finset.Icc 1 k, (u : ℝ)⁻¹ = ∑ u ∈ Finset.Icc 1 (k - 1), (u : ℝ)⁻¹ + (k : ℝ)⁻¹ := by have h₂ : ∑ u ∈ Finset.Icc 1 k, (u : ℝ)⁻¹ = ∑ u ∈ Finset.Icc 1 (k - 1), (u : ℝ)⁻¹ + (k : ℝ)⁻¹ := by cases k with | zero => exfalso linarith | succ k' => cases k' with | zero => norm_num [Finset.sum_Icc_succ_top] | succ k'' => simp_all [Finset.sum_Icc_succ_top, Nat.cast_add, Nat.cast_one] exact h₂ exact h₁ lemma even_step (k : ℕ) (hk : 1 ≤ k) : (∑ t ∈ Finset.Icc 1 (2 * k - 1), 1 / min ((t : ℝ)) ((2 * k : ℝ) - (t : ℝ))) ≤ (∑ t ∈ Finset.Icc 1 (2 * k), 1 / min ((t : ℝ)) ((2 * k + 1 : ℝ) - (t : ℝ))) := by rw [even_step_lhs_eq k hk, lhs_eq_1 k hk, harmonic_split k hk] have hk_pos : (0 : ℝ) < (k : ℝ) := Nat.cast_pos.mpr (by omega) have : 1 / (k : ℝ) ≤ 2 * (k : ℝ)⁻¹ := by rw [one_div] linarith [inv_pos.mpr hk_pos] linarith lemma rhs_eq (k : ℕ) (hk : 1 ≤ k) : (∑ t ∈ Finset.Icc 1 (2 * k + 1), 1 / min ((t : ℝ)) ((2 * (k : ℝ) + 1 + 1) - (t : ℝ))) = 2 * ((∑ u ∈ Finset.Icc 1 k, (u : ℝ)⁻¹) + 1 / (2 * ((k : ℝ) + 1))) := by have hM : (2 * (k + 1) : ℕ) - 1 = 2 * k + 1 := by omega have h1 := sum_eq_two_mul_half_sum (2 * (k + 1)) rw [hM] at h1 conv at h1 => lhs; arg 2; ext t; rw [show (↑(2 * (k + 1)) : ℝ) = 2 * (↑k : ℝ) + 1 + 1 from by push_cast; ring] conv at h1 => rhs; arg 2; arg 2; ext t; rw [show (↑(2 * (k + 1)) : ℝ) = 2 * (↑k : ℝ) + 1 + 1 from by push_cast; ring] rw [h1] have h2 := symmetric_sum_even (k + 1) (by omega : 1 ≤ k + 1) rw [show 2 * (k + 1) - 1 = 2 * k + 1 from by omega, show k + 1 - 1 = k from by omega] at h2 congr 1 conv at h2 => lhs; arg 2; ext t; rw [show (2 * (↑(k + 1) : ℝ) : ℝ) = 2 * (↑k : ℝ) + 1 + 1 from by push_cast; ring] rw [h2] congr 1 push_cast; ring lemma odd_step (k : ℕ) (hk : 1 ≤ k) : (∑ t ∈ Finset.Icc 1 (2 * k), 1 / min ((t : ℝ)) ((2 * (k : ℝ) + 1) - (t : ℝ))) ≤ (∑ t ∈ Finset.Icc 1 (2 * k + 1), 1 / min ((t : ℝ)) ((2 * (k : ℝ) + 1 + 1) - (t : ℝ))) := by rw [lhs_eq_1 k hk, rhs_eq k hk] linarith [show (0 : ℝ) < 1 / (2 * ((k : ℝ) + 1)) from by positivity] lemma harmonic_min_sum_step (N : ℕ) (hN : 2 ≤ N) : (∑ t ∈ Finset.Icc 1 (N - 1), 1 / min ((t : ℝ)) (((N : ℕ) : ℝ) - (t : ℝ))) ≤ (∑ t ∈ Finset.Icc 1 ((N + 1) - 1), 1 / min ((t : ℝ)) ((((N + 1) : ℕ) : ℝ) - (t : ℝ))) := by obtain ⟨k, rfl | rfl⟩ := Nat.even_or_odd' N · have hk : 1 ≤ k := by omega show (∑ t ∈ Finset.Icc 1 (2 * k - 1), 1 / min ((t : ℝ)) (((2 * k : ℕ) : ℝ) - (t : ℝ))) ≤ (∑ t ∈ Finset.Icc 1 ((2 * k + 1) - 1), 1 / min ((t : ℝ)) ((((2 * k + 1) : ℕ) : ℝ) - (t : ℝ))) simp only [show (2 * k + 1 : ℕ) - 1 = 2 * k from by omega] push_cast exact even_step k hk · have hk : 1 ≤ k := by omega show (∑ t ∈ Finset.Icc 1 ((2 * k + 1) - 1), 1 / min ((t : ℝ)) ((((2 * k + 1) : ℕ) : ℝ) - (t : ℝ))) ≤ (∑ t ∈ Finset.Icc 1 ((2 * k + 1 + 1) - 1), 1 / min ((t : ℝ)) ((((2 * k + 1 + 1) : ℕ) : ℝ) - (t : ℝ))) simp only [show (2 * k + 1 : ℕ) - 1 = 2 * k from by omega, show (2 * k + 1 + 1 : ℕ) - 1 = 2 * k + 1 from by omega] push_cast exact odd_step k hk lemma harmonic_min_sum_mono (M d : ℕ) (hM : 2 ≤ M) (hMd : M ≤ d) : (∑ t ∈ Finset.Icc 1 (M - 1), 1 / min ((t : ℝ)) (((M : ℕ) : ℝ) - (t : ℝ))) ≤ (∑ t ∈ Finset.Icc 1 (d - 1), 1 / min ((t : ℝ)) (((d : ℕ) : ℝ) - (t : ℝ))) := by obtain ⟨k, rfl⟩ := Nat.exists_eq_add_of_le hMd induction k with | zero => simp | succ k ih => have ih' := ih (by omega) have hstep := harmonic_min_sum_step (M + k) (by omega) have h1 : M + k + 1 - 1 = M + k := by omega have h2 : M + (k + 1) - 1 = M + k := by omega rw [h2] rw [h1] at hstep exact le_trans ih' hstep lemma exists_padic_valuation (p : ℕ) (hp : Nat.Prime p) (α : ℕ) (hα : 1 ≤ α) (k_val : ℕ) (hk_dvd_p : p ∣ k_val) (hk_nd : ¬(p ^ α ∣ k_val)) : ∃ v, 1 ≤ v ∧ v < α ∧ p ^ v ∣ k_val ∧ ¬(p ^ (v + 1) ∣ k_val) := by by_cases hk : k_val = 0 · have h_absurd : False := by simp_all have h_main : ∃ v, 1 ≤ v ∧ v < α ∧ p ^ v ∣ k_val ∧ ¬(p ^ (v + 1) ∣ k_val) := by contradiction exact h_main · haveI := Fact.mk hp have h1 : 1 ≤ padicValNat p k_val := by exact one_le_padicValNat_of_dvd hk hk_dvd_p have h2 : padicValNat p k_val < α := by by_contra h_ge push_neg at h_ge exact hk_nd ((Nat.pow_dvd_pow p h_ge).trans pow_padicValNat_dvd) have h3 : p ^ (padicValNat p k_val) ∣ k_val := by exact pow_padicValNat_dvd have h4 : ¬(p ^ (padicValNat p k_val + 1) ∣ k_val) := pow_succ_padicValNat_not_dvd hk exact ⟨padicValNat p k_val, h1, h2, h3, h4⟩ lemma general_case_bound (d : ℕ) [NeZero d] (p : ℕ) (hp : Nat.Prime p) (α : ℕ) (hα : 1 ≤ α) (hd_eq : d = p ^ α) (k_val : ℕ) (hk_nd : ¬((d : ℕ) ∣ k_val)) (hk_dvd_p : p ∣ k_val) : (∑ u : (ZMod d)ˣ, 1 / min ((k_val * (u : ZMod d).val % d : ℕ) : ℝ) (((d : ℕ) : ℝ) - (k_val * (u : ZMod d).val % d : ℕ))) ≤ (∑ t ∈ Finset.Icc 1 (d - 1), 1 / min ((t : ℝ)) (((d : ℕ) : ℝ) - (t : ℝ))) := by have hk_nd' : ¬(p ^ α ∣ k_val) := hd_eq ▸ hk_nd obtain ⟨v, hv_pos, hv_lt, hv_dvd, hv_max⟩ := exists_padic_valuation p hp α hα k_val hk_dvd_p hk_nd' set M := p ^ (α - v) with hM_def have hM_pos : 0 < M := by simp only [hM_def] exact pow_pos hp.pos _ haveI : NeZero M := ⟨by omega⟩ haveI : NeZero (p ^ (α - v)) := ⟨by omega⟩ have hM_ge : 2 ≤ M := by have : p ^ 1 ≤ M := by apply Nat.pow_le_pow_right hp.pos omega linarith [hp.two_le] calc (∑ u : (ZMod d)ˣ, 1 / min ((k_val * (u : ZMod d).val % d : ℕ) : ℝ) (((d : ℕ) : ℝ) - (k_val * (u : ZMod d).val % d : ℕ))) = (∑ t : (ZMod M)ˣ, 1 / min (((t : ZMod M).val : ℕ) : ℝ) (((M : ℕ) : ℝ) - ((t : ZMod M).val : ℕ))) := orbit_fiber_sum_eq d p hp α hα hd_eq k_val hk_nd hk_dvd_p v hv_pos hv_lt hv_dvd hv_max _ ≤ (∑ t ∈ Finset.Icc 1 (M - 1), 1 / min ((t : ℝ)) (((M : ℕ) : ℝ) - (t : ℝ))) := units_sum_le_Icc_sum M hM_ge _ ≤ (∑ t ∈ Finset.Icc 1 (d - 1), 1 / min ((t : ℝ)) (((d : ℕ) : ℝ) - (t : ℝ))) := by apply harmonic_min_sum_mono M d hM_ge calc M = p ^ (α - v) := rfl _ ≤ p ^ α := Nat.pow_le_pow_right hp.pos (by omega) _ = d := hd_eq.symm lemma orbit_fiber_sum_bound (d : ℕ) [NeZero d] (p : ℕ) (hp : Nat.Prime p) (α : ℕ) (hα : 1 ≤ α) (hd_eq : d = p ^ α) (k_val : ℕ) (hk_nd : ¬((d : ℕ) ∣ k_val)) : (∑ u : (ZMod d)ˣ, 1 / min ((k_val * (u : ZMod d).val % d : ℕ) : ℝ) (((d : ℕ) : ℝ) - (k_val * (u : ZMod d).val % d : ℕ))) ≤ (∑ t ∈ Finset.Icc 1 (d - 1), 1 / min ((t : ℝ)) (((d : ℕ) : ℝ) - (t : ℝ))) := by by_cases hp_dvd : p ∣ k_val · exact general_case_bound d p hp α hα hd_eq k_val hk_nd hp_dvd · have hcop : Nat.Coprime k_val d := coprime_of_prime_power_not_dvd d p hp α hα hd_eq k_val hp_dvd have hd2 : 2 ≤ d := by rw [hd_eq]; exact le_trans (Nat.Prime.two_le hp) (Nat.le_self_pow (by omega) p) calc (∑ u : (ZMod d)ˣ, 1 / min ((k_val * (u : ZMod d).val % d : ℕ) : ℝ) (((d : ℕ) : ℝ) - (k_val * (u : ZMod d).val % d : ℕ))) = (∑ u : (ZMod d)ˣ, 1 / min (((u : ZMod d).val : ℕ) : ℝ) (((d : ℕ) : ℝ) - ((u : ZMod d).val : ℕ))) := coprime_case_sum_eq d k_val hcop _ ≤ (∑ t ∈ Finset.Icc 1 (d - 1), 1 / min ((t : ℝ)) (((d : ℕ) : ℝ) - (t : ℝ))) := units_sum_le_Icc_sum d hd2 lemma d_ge_two (n d : ℕ) (hn : 2 ≤ n) (hd : d = largestPrimeFactor n ^ n.factorization (largestPrimeFactor n)) : 2 ≤ d := by rw [hd] exact le_trans (largestPrimeFactor_ge_two n hn) (d_ge_P n hn) lemma d_le_n (n d : ℕ) (hn : 2 ≤ n) (hd : d = largestPrimeFactor n ^ n.factorization (largestPrimeFactor n)) : d ≤ n := by rw [hd] exact Nat.le_of_dvd (by omega) (d_dvd_n n hn) lemma orbit_sum_le_two_log (n d : ℕ) [NeZero n] [NeZero d] (hn : 2 ≤ n) (hd : d = largestPrimeFactor n ^ n.factorization (largestPrimeFactor n)) (k : ZMod n) (hk : k ≠ 0) (hk_nd : ¬((d : ℕ) ∣ ZMod.val k)) : (∑ u : (ZMod d)ˣ, 1 / min ((ZMod.val k * (u : ZMod d).val % d : ℕ) : ℝ) ((d : ℝ) - (ZMod.val k * (u : ZMod d).val % d : ℕ))) ≤ 2 * (1 + Real.log ↑n) := by set P := largestPrimeFactor n set α := n.factorization P have hP : Nat.Prime P := largest_prime_factor_prime n hn have hα : 1 ≤ α := largest_prime_factor_multiplicity_pos n hn have hd2 : 2 ≤ d := d_ge_two n d hn hd have hdn : d ≤ n := d_le_n n d hn hd calc (∑ u : (ZMod d)ˣ, 1 / min ((ZMod.val k * (u : ZMod d).val % d : ℕ) : ℝ) ((d : ℝ) - (ZMod.val k * (u : ZMod d).val % d : ℕ))) ≤ (∑ t ∈ Finset.Icc 1 (d - 1), 1 / min ((t : ℝ)) ((d : ℝ) - (t : ℝ))) := orbit_fiber_sum_bound d P hP α hα hd (ZMod.val k) hk_nd _ ≤ 2 * (1 + Real.log ↑n) := harmonic_min_sum_le_two_log d n hd2 hdn lemma pow_pred_mul_eq (P α : ℕ) (hα : 0 < α) : P ^ (α - 1) * P = P ^ α := by have h1 : α - 1 + 1 = α := by have h2 : 1 ≤ α := by linarith have h3 : α - 1 + 1 = α := by have h4 : α - 1 + 1 = α := by rw [Nat.sub_add_cancel h2] exact h4 exact h3 calc P ^ (α - 1) * P = P ^ (α - 1) * P ^ 1 := by simp [pow_one] _ = P ^ ((α - 1) + 1) := by rw [pow_add] _ = P ^ α := by rw [h1] lemma cast_nat_sub_one (P : ℕ) (hP2 : 2 ≤ P) : (↑(P - 1) : ℝ) = ↑P - 1 := by have h₁ : 1 ≤ P := by omega have h₂ : (↑(P - 1) : ℝ) = (P : ℝ) - 1 := by norm_num [h₁] at hP2 ⊢ exact h₂ lemma totient_prime_pow_simplify (P α : ℕ) (hP2 : 2 ≤ P) (hα : 0 < α) : (↑(P ^ (α - 1) * (P - 1)) : ℝ) * (4 / ↑(P ^ α)) = 4 * (↑P - 1) / ↑P := by have hP_pos : (0 : ℝ) < ↑P := by positivity have hPα1_pos : (0 : ℝ) < ↑(P ^ (α - 1)) := by positivity have hkey : (↑(P ^ α) : ℝ) = ↑(P ^ (α - 1)) * ↑P := by rw [← Nat.cast_mul, pow_pred_mul_eq P α hα] have hcast : (↑(P - 1) : ℝ) = ↑P - 1 := cast_nat_sub_one P hP2 rw [Nat.cast_mul, hcast, hkey] have hPne : (↑P : ℝ) ≠ 0 := ne_of_gt hP_pos have hPα1ne : (↑(P ^ (α - 1)) : ℝ) ≠ 0 := ne_of_gt hPα1_pos field_simp lemma four_times_sub_one_div_ge_two (P : ℕ) (hP2 : 2 ≤ P) : 2 ≤ 4 * ((↑P : ℝ) - 1) / ↑P := by have hP_pos : (0 : ℝ) < ↑P := by positivity rw [le_div_iff₀ hP_pos] nlinarith [show (2 : ℝ) ≤ ↑P from by exact_mod_cast hP2] lemma totient_prime_pow_times_four_div_ge_two (P α : ℕ) (hP : Nat.Prime P) (hα : 0 < α) (hP2 : 2 ≤ P) : 2 ≤ ((P ^ α).totient : ℝ) * (4 / ((P ^ α : ℕ) : ℝ)) := by rw [Nat.totient_prime_pow hP hα] rw [totient_prime_pow_simplify P α hP2 hα] exact four_times_sub_one_div_ge_two P hP2 lemma totient_times_four_div_d_ge_two (n d : ℕ) [NeZero d] (hn : 2 ≤ n) (hd : d = largestPrimeFactor n ^ n.factorization (largestPrimeFactor n)) : 2 ≤ (d.totient : ℝ) * (4 / (d : ℝ)) := by have hP := largest_prime_factor_prime n hn have hα := largest_prime_factor_multiplicity_pos n hn have hP2 := largestPrimeFactor_ge_two n hn rw [hd] exact totient_prime_pow_times_four_div_ge_two _ _ hP (by omega) hP2 lemma two_log_le_card_times_bound (n d : ℕ) [NeZero n] [NeZero d] (hn : 2 ≤ n) (hd : d = largestPrimeFactor n ^ n.factorization (largestPrimeFactor n)) : 2 * (1 + Real.log ↑n) ≤ ↑(Fintype.card (ZMod d)ˣ) * (4 * (1 + Real.log ↑n) / ↑d) := by have hlog := one_plus_log_nonneg n hn have hd_pos : (0 : ℝ) < (d : ℝ) := Nat.cast_pos.mpr (NeZero.pos d) rw [show (4 : ℝ) * (1 + Real.log ↑n) / ↑d = 4 / ↑d * (1 + Real.log ↑n) by ring] rw [show (↑(Fintype.card (ZMod d)ˣ) : ℝ) * (4 / ↑d * (1 + Real.log ↑n)) = (↑(Fintype.card (ZMod d)ˣ) : ℝ) * (4 / ↑d) * (1 + Real.log ↑n) by ring] rw [show (2 : ℝ) * (1 + Real.log ↑n) = 2 * (1 + Real.log ↑n) from rfl] rw [ZMod.card_units_eq_totient] calc 2 * (1 + Real.log ↑n) = 2 * (1 + Real.log ↑n) := rfl _ ≤ (↑(d.totient) * (4 / ↑d)) * (1 + Real.log ↑n) := by apply mul_le_mul_of_nonneg_right _ hlog exact totient_times_four_div_d_ge_two n d hn hd lemma orbit_reciprocal_sum_bound (n d : ℕ) [NeZero n] [NeZero d] (hn : 2 ≤ n) (hd : d = largestPrimeFactor n ^ n.factorization (largestPrimeFactor n)) (k : ZMod n) (hk : k ≠ 0) (hk_nd : ¬((d : ℕ) ∣ ZMod.val k)) : (∑ u : (ZMod d)ˣ, 1 / min ((ZMod.val k * (u : ZMod d).val % d : ℕ) : ℝ) ((d : ℝ) - (ZMod.val k * (u : ZMod d).val % d : ℕ))) ≤ ↑(Fintype.card (ZMod d)ˣ) * (4 * (1 + Real.log ↑n) / ↑d) := by calc (∑ u : (ZMod d)ˣ, 1 / min ((ZMod.val k * (u : ZMod d).val % d : ℕ) : ℝ) ((d : ℝ) - (ZMod.val k * (u : ZMod d).val % d : ℕ))) ≤ 2 * (1 + Real.log ↑n) := orbit_sum_le_two_log n d hn hd k hk hk_nd _ ≤ ↑(Fintype.card (ZMod d)ˣ) * (4 * (1 + Real.log ↑n) / ↑d) := two_log_le_card_times_bound n d hn hd namespace PerUnitMerge lemma neg_inv_isUnit (d : ℕ) [NeZero d] (q : ℤ) (hq : Int.gcd q (d : ℤ) = 1) : IsUnit (-(q : ZMod d)⁻¹) := by apply IsUnit.neg apply ZMod.isUnit_inv rw [ZMod.coe_int_isUnit_iff_isCoprime] rw [Int.isCoprime_iff_gcd_eq_one] rwa [Int.gcd_comm] lemma dvd_of_dvd_mul_unit_val (d : ℕ) [NeZero d] (k_val : ℕ) (u : (ZMod d)ˣ) (h : d ∣ k_val * (u : ZMod d).val) : d ∣ k_val := by have h_coprime : Nat.Coprime (u : ZMod d).val d := by exact ZMod.val_coe_unit_coprime u have h_coprime_symm : Nat.Coprime d (u : ZMod d).val := by exact h_coprime.symm have h_main : d ∣ k_val := by exact (Nat.Coprime.dvd_of_dvd_mul_right h_coprime_symm h) assumption lemma b_ne_zero (d : ℕ) [NeZero d] (q : ℤ) (hq_coprime_d : Int.gcd q (d : ℤ) = 1) (k_val : ℕ) (hk_nd : ¬(d ∣ k_val)) (u : (ZMod d)ˣ) : (-(q : ZMod d)⁻¹ * ((k_val * (u : ZMod d).val : ℕ) : ZMod d)) ≠ 0 := by intro h apply hk_nd apply dvd_of_dvd_mul_unit_val d k_val u have h2 : ((k_val * (u : ZMod d).val : ℕ) : ZMod d) = 0 := (neg_inv_isUnit d q hq_coprime_d).mul_right_eq_zero.mp h exact (ZMod.natCast_eq_zero_iff _ _).mp h2 lemma b_bounds (d : ℕ) [NeZero d] (q : ℤ) (hq_coprime_d : Int.gcd q (d : ℤ) = 1) (k_val : ℕ) (hk_nd : ¬(d ∣ k_val)) (u : (ZMod d)ˣ) : let b := ZMod.val (-(q : ZMod d)⁻¹ * ((k_val * (u : ZMod d).val : ℕ) : ZMod d)) 1 ≤ b ∧ b < d := by constructor · exact Nat.one_le_iff_ne_zero.mpr ((ZMod.val_ne_zero _).mpr (b_ne_zero d q hq_coprime_d k_val hk_nd u)) · exact ZMod.val_lt _ lemma q_isUnit_of_gcd (d : ℕ) [NeZero d] (q : ℤ) (hq : Int.gcd q (d : ℤ) = 1) : IsUnit (q : ZMod d) := by have h₁ : (q : ℤ).gcd (d : ℤ) = 1 := by assumption have h₂ : IsCoprime (q : ℤ) (d : ℤ) := by exact Int.isCoprime_iff_gcd_eq_one.mpr h₁ rw [ZMod.coe_int_isUnit_iff_isCoprime] exact h₂.symm lemma inv_isUnit_of_isUnit (d : ℕ) [NeZero d] (a : ZMod d) (ha : IsUnit a) : IsUnit (a⁻¹) := by have h : a⁻¹ * a = 1 := ZMod.inv_mul_of_unit a ha have h2 : a * a⁻¹ = 1 := ZMod.mul_inv_of_unit a ha exact ⟨⟨a⁻¹, a, h, h2⟩, rfl⟩ lemma isCoprime_intCast_of_gcd_eq_one (d : ℕ) (q : ℤ) (hq : Int.gcd q (d : ℤ) = 1) : IsCoprime (d : ℤ) q := by have h := Int.isCoprime_iff_gcd_eq_one.mpr hq exact h.symm lemma neg_inv_eq_inv_neg (d : ℕ) [NeZero d] (q : ℤ) (hq : Int.gcd q (d : ℤ) = 1) : -(q : ZMod d)⁻¹ = (-(q : ZMod d))⁻¹ := by have hu := q_isUnit_of_gcd d q hq have h1 : (-(q : ZMod d)) * (-(q : ZMod d)⁻¹) = 1 := by rw [neg_mul_neg] exact ZMod.mul_inv_of_unit _ hu rw [← ZMod.inv_eq_of_mul_eq_one d (-(q : ZMod d)) (-(q : ZMod d)⁻¹) h1] lemma dvd_iff_zmod_eq_zero (d : ℕ) [NeZero d] (k_val u_val l_val : ℕ) (q : ℤ) : ((d : ℤ) ∣ (↑k_val * ↑u_val + ↑l_val * q)) ↔ ((k_val : ZMod d) * (u_val : ZMod d) + (l_val : ZMod d) * (q : ZMod d) = 0) := by have h_iff : ((d : ℤ) ∣ (↑k_val * ↑u_val + ↑l_val * q)) ↔ (((k_val : ℤ) * (u_val : ℤ) + (l_val : ℤ) * q : ℤ) : ZMod d) = 0 := by exact (ZMod.intCast_zmod_eq_zero_iff_dvd _ _).symm have h_final : ((d : ℤ) ∣ (↑k_val * ↑u_val + ↑l_val * q)) ↔ ((k_val : ZMod d) * (u_val : ZMod d) + (l_val : ZMod d) * (q : ZMod d) = 0) := by simp_all assumption lemma zmod_eq_zero_forward (d : ℕ) [NeZero d] (k_val u_val l_val : ℕ) (q : ℤ) (hq : IsUnit (q : ZMod d)) (h : (k_val : ZMod d) * (u_val : ZMod d) + (l_val : ZMod d) * (q : ZMod d) = 0) : (l_val : ZMod d) = -(q : ZMod d)⁻¹ * ((k_val * u_val : ℕ) : ZMod d) := by have h₂ : (q : ZMod d)⁻¹ * (q : ZMod d) = 1 := by exact ZMod.inv_mul_of_unit _ hq have h₃ : (l_val : ZMod d) = -(q : ZMod d)⁻¹ * ((k_val : ZMod d) * (u_val : ZMod d)) := by have : (l_val : ZMod d) * (q : ZMod d) = -((k_val : ZMod d) * (u_val : ZMod d)) := by linear_combination h calc (l_val : ZMod d) = (l_val : ZMod d) * ((q : ZMod d)⁻¹ * (q : ZMod d)) := by rw [h₂, mul_one] _ = ((l_val : ZMod d) * (q : ZMod d)) * (q : ZMod d)⁻¹ := by ring _ = -((k_val : ZMod d) * (u_val : ZMod d)) * (q : ZMod d)⁻¹ := by rw [this] _ = -(q : ZMod d)⁻¹ * ((k_val : ZMod d) * (u_val : ZMod d)) := by ring have h₄ : (l_val : ZMod d) = -(q : ZMod d)⁻¹ * ((k_val * u_val : ℕ) : ZMod d) := by simp_all exact h₄ lemma zmod_eq_zero_backward (d : ℕ) [NeZero d] (k_val u_val l_val : ℕ) (q : ℤ) (hq : IsUnit (q : ZMod d)) (h : (l_val : ZMod d) = -(q : ZMod d)⁻¹ * ((k_val * u_val : ℕ) : ZMod d)) : (k_val : ZMod d) * (u_val : ZMod d) + (l_val : ZMod d) * (q : ZMod d) = 0 := by have h1 : (l_val : ZMod d) * (q : ZMod d) = -((q : ZMod d)⁻¹ * (q : ZMod d)) * ((k_val * u_val : ℕ) : ZMod d) := by rw [h]; ring have h2 : ((q : ZMod d)⁻¹ * (q : ZMod d) : ZMod d) = 1 := by exact ZMod.inv_mul_of_unit _ hq have h3 : (l_val : ZMod d) * (q : ZMod d) = -((k_val * u_val : ℕ) : ZMod d) := by simp_all have h4 : (k_val : ZMod d) * (u_val : ZMod d) = ((k_val * u_val : ℕ) : ZMod d) := by simp have h5 : (k_val : ZMod d) * (u_val : ZMod d) + (l_val : ZMod d) * (q : ZMod d) = 0 := by rw [h4, h3]; ring assumption lemma zmod_eq_zero_iff_eq_neg_inv_mul (d : ℕ) [NeZero d] (k_val u_val l_val : ℕ) (q : ℤ) (hq : IsUnit (q : ZMod d)) : ((k_val : ZMod d) * (u_val : ZMod d) + (l_val : ZMod d) * (q : ZMod d) = 0) ↔ ((l_val : ZMod d) = -(q : ZMod d)⁻¹ * ((k_val * u_val : ℕ) : ZMod d)) := ⟨zmod_eq_zero_forward d k_val u_val l_val q hq, zmod_eq_zero_backward d k_val u_val l_val q hq⟩ lemma residue_iff_zmod_eq (d : ℕ) [NeZero d] (k_val u_val l_val : ℕ) (q : ℤ) : (l_val % d = ZMod.val (-(q : ZMod d)⁻¹ * ((k_val * u_val : ℕ) : ZMod d))) ↔ ((l_val : ZMod d) = -(q : ZMod d)⁻¹ * ((k_val * u_val : ℕ) : ZMod d)) := by have h_main : (l_val : ZMod d) = (l_val % d : ℕ) := by simp have h_val_nat_cast : (l_val : ZMod d).val = l_val % d := by simp have h_forward : (l_val % d = ZMod.val (-(q : ZMod d)⁻¹ * ((k_val * u_val : ℕ) : ZMod d))) → ((l_val : ZMod d) = -(q : ZMod d)⁻¹ * ((k_val * u_val : ℕ) : ZMod d)) := by intro heq have : (l_val : ZMod d).val = (-(q : ZMod d)⁻¹ * ((k_val * u_val : ℕ) : ZMod d)).val := by rw [h_val_nat_cast]; exact heq exact ZMod.val_injective _ this have h_backward : ((l_val : ZMod d) = -(q : ZMod d)⁻¹ * ((k_val * u_val : ℕ) : ZMod d)) → (l_val % d = ZMod.val (-(q : ZMod d)⁻¹ * ((k_val * u_val : ℕ) : ZMod d))) := by intro heq; rw [← h_val_nat_cast, heq] have h_final : (l_val % d = ZMod.val (-(q : ZMod d)⁻¹ * ((k_val * u_val : ℕ) : ZMod d))) ↔ ((l_val : ZMod d) = -(q : ZMod d)⁻¹ * ((k_val * u_val : ℕ) : ZMod d)) := by exact ⟨h_forward, h_backward⟩ assumption lemma divisibility_iff_residue_class (n d : ℕ) [NeZero n] [NeZero d] (_hd_dvd : d ∣ n) (q : ℤ) (hq_coprime_d : Int.gcd q (d : ℤ) = 1) (k : ZMod n) (_hk : k ≠ 0) (u : (ZMod d)ˣ) (l : ZMod n) : let b := ZMod.val (-(q : ZMod d)⁻¹ * ((ZMod.val k * (u : ZMod d).val : ℕ) : ZMod d)) ((d : ℤ) ∣ (↑(ZMod.val k) * ↑(u : ZMod d).val + ↑(ZMod.val l) * q)) ↔ (ZMod.val l % d = b) := by intro b have hq_unit : IsUnit (q : ZMod d) := q_isUnit_of_gcd d q hq_coprime_d rw [dvd_iff_zmod_eq_zero d (ZMod.val k) ((u : ZMod d).val) (ZMod.val l) q, zmod_eq_zero_iff_eq_neg_inv_mul d (ZMod.val k) ((u : ZMod d).val) (ZMod.val l) q hq_unit, ← residue_iff_zmod_eq d (ZMod.val k) ((u : ZMod d).val) (ZMod.val l) q] lemma cond_sum_eq_residue_class_sum (n d : ℕ) [NeZero n] [NeZero d] (hd_dvd : d ∣ n) (q : ℤ) (hq_coprime_d : Int.gcd q (d : ℤ) = 1) (mq : ℕ) (k : ZMod n) (hk : k ≠ 0) (u : (ZMod d)ˣ) : let b := ZMod.val (-(q : ZMod d)⁻¹ * ((ZMod.val k * (u : ZMod d).val : ℕ) : ZMod d)) (∑ l : ZMod n, if ((d : ℤ) ∣ (↑(ZMod.val k) * ↑(u : ZMod d).val + ↑(ZMod.val l) * q)) then ‖normalizedDFT n (intervalIndicator n mq) l‖ else 0) = ∑ l : ZMod n, if (ZMod.val l % d = b) then ‖normalizedDFT n (intervalIndicator n mq) l‖ else 0 := by simp only apply Finset.sum_congr rfl intro l _ have h := divisibility_iff_residue_class n d hd_dvd q hq_coprime_d k hk u l simp only at h simp only [h] lemma nonzero_of_val_mod_eq_pos (n d : ℕ) [NeZero n] [NeZero d] (l : ZMod n) (b : ℕ) (hb_pos : 1 ≤ b) (hb_lt : b < d) (hmod : ZMod.val l % d = b) : l ≠ 0 := by intro h rw [h] at hmod have h₁ : ZMod.val (0 : ZMod n) = 0 := by simp [ZMod.val_zero] have h₂ : (0 : ℕ) % d = 0 := by simp [Nat.zero_mod] rw [h₁] at hmod simp_all [ZMod.val_zero] <;> (try omega) lemma min_eq_val_of_two_mul_le (n : ℕ) [NeZero n] (l : ZMod n) (h2 : 2 * ZMod.val l ≤ n) : (min (ZMod.val l : ℝ) ((n : ℝ) - ZMod.val l)) = (ZMod.val l : ℝ) := by have h₁ : (ZMod.val l : ℝ) ≤ ((n : ℝ) - ZMod.val l) := by have h₃ : 2 * ZMod.val l ≤ n := h2 have h₄ : (2 : ℝ) * (ZMod.val l : ℝ) ≤ (n : ℝ) := by norm_cast at h₃ ⊢ have h₅ : (ZMod.val l : ℝ) ≤ (n : ℝ) - (ZMod.val l : ℝ) := by linarith exact h₅ have h₂ : min (ZMod.val l : ℝ) ((n : ℝ) - ZMod.val l) = (ZMod.val l : ℝ) := by apply min_eq_left exact h₁ exact h₂ lemma pointwise_bound_in_low_range (n d : ℕ) [NeZero n] [NeZero d] (mq : ℕ) (hmq_lo : 1 ≤ mq) (hmq_hi : mq < n) (b : ℕ) (hb_pos : 1 ≤ b) (hb_lt : b < d) (l : ZMod n) (hmod : ZMod.val l % d = b) (hlow : 2 * ZMod.val l ≤ n) : ‖normalizedDFT n (intervalIndicator n mq) l‖ ≤ 1 / (2 * (ZMod.val l : ℝ)) := by have hl_ne : l ≠ 0 := nonzero_of_val_mod_eq_pos n d l b hb_pos hb_lt hmod have hbound := normalizedDFT_intervalIndicator_nonzero_bound n mq hmq_lo hmq_hi l hl_ne rw [min_eq_val_of_two_mul_le n l hlow] at hbound exact hbound lemma val_eq_of_mod_eq_and_quot_eq (n d : ℕ) [NeZero n] [NeZero d] (b : ℕ) (_hb_lt : b < d) (l₁ l₂ : ZMod n) (h1 : ZMod.val l₁ % d = b) (h2 : ZMod.val l₂ % d = b) (heq : (ZMod.val l₁ - b) / d = (ZMod.val l₂ - b) / d) : ZMod.val l₁ = ZMod.val l₂ := by have hb1 : b ≤ ZMod.val l₁ := h1 ▸ Nat.mod_le _ _ have hb2 : b ≤ ZMod.val l₂ := h2 ▸ Nat.mod_le _ _ have hr1 := fiber_reconstruct d b (ZMod.val l₁) h1 hb1 have hr2 := fiber_reconstruct d b (ZMod.val l₂) h2 hb2 rw [heq] at hr1 linarith lemma quotient_injOn (n d : ℕ) [NeZero n] [NeZero d] (_hd_dvd : d ∣ n) (b : ℕ) (hb_lt : b < d) : Set.InjOn (fun l : ZMod n => (ZMod.val l - b) / d) (↑(Finset.univ.filter (fun l : ZMod n => ZMod.val l % d = b ∧ 2 * ZMod.val l ≤ n))) := by intro l₁ hl₁ l₂ hl₂ heq simp only [Finset.coe_filter, Finset.mem_univ, true_and, Set.mem_setOf_eq] at hl₁ hl₂ have hval := val_eq_of_mod_eq_and_quot_eq n d b hb_lt l₁ l₂ hl₁.1 hl₂.1 heq exact ZMod.val_injective n hval lemma quotient_mem_range (n d : ℕ) [NeZero n] [NeZero d] (_hd_dvd : d ∣ n) (b : ℕ) (_hb_pos : 1 ≤ b) (_hb_lt : b < d) (l : ZMod n) (hl : ZMod.val l % d = b ∧ 2 * ZMod.val l ≤ n) : (ZMod.val l - b) / d ∈ Finset.range (n / (2 * d) + 1) := by have h₁ : (ZMod.val l - b) / d < n / (2 * d) + 1 := by have h₃ : (ZMod.val l - b) / d ≤ (ZMod.val l) / d := by have h₄ : ZMod.val l - b ≤ ZMod.val l := by have h₅ : b ≤ ZMod.val l := by have h₁₂ : b ≤ ZMod.val l := by by_contra h have h₁₄ : ZMod.val l % d = ZMod.val l := by have h₁₅ : ZMod.val l < d := by omega have h₁₆ : ZMod.val l % d = ZMod.val l := by rw [Nat.mod_eq_of_lt h₁₅] exact h₁₆ omega exact h₁₂ omega have h₅ : (ZMod.val l - b) / d ≤ (ZMod.val l) / d := by apply Nat.div_le_div_right omega exact h₅ have h₄ : (ZMod.val l) / d ≤ n / (2 * d) := by have h₆ : ZMod.val l ≤ n / 2 := by omega have h₇ : (ZMod.val l) / d ≤ (n / 2) / d := by apply Nat.div_le_div_right omega have h₈ : (n / 2) / d ≤ n / (2 * d) := by have h₉ : (n / 2) / d = n / (2 * d) := by rw [← Nat.div_div_eq_div_mul] rw [h₉] calc (ZMod.val l) / d ≤ (n / 2) / d := h₇ _ ≤ n / (2 * d) := h₈ have h₅ : (ZMod.val l - b) / d ≤ n / (2 * d) := by calc (ZMod.val l - b) / d ≤ (ZMod.val l) / d := h₃ _ ≤ n / (2 * d) := h₄ omega exact Finset.mem_range.mpr h₁ lemma summand_eq (n d : ℕ) [NeZero n] [NeZero d] (b : ℕ) (_hb_pos : 1 ≤ b) (_hb_lt : b < d) (l : ZMod n) (hl : ZMod.val l % d = b ∧ 2 * ZMod.val l ≤ n) : (1 : ℝ) / (2 * (ZMod.val l : ℝ)) = (1 : ℝ) / (2 * ((b : ℝ) + ((ZMod.val l - b) / d : ℕ) * (d : ℝ))) := by have hb_le : b ≤ ZMod.val l := hl.1 ▸ Nat.mod_le _ _ have hnat := fiber_reconstruct d b (ZMod.val l) hl.1 hb_le congr 1 congr 1 exact_mod_cast hnat.symm lemma rhs_term_nonneg (b d : ℕ) (hb_pos : 1 ≤ b) (j : ℕ) : (0 : ℝ) ≤ (1 : ℝ) / (2 * ((b : ℝ) + (j : ℝ) * (d : ℝ))) := by have h₁ : (0 : ℝ) < 2 * ((b : ℝ) + (j : ℝ) * (d : ℝ)) := by have h₅ : (0 : ℝ) < 2 * ((b : ℝ) + (j : ℝ) * (d : ℝ)) := by positivity exact h₅ have h₂ : (0 : ℝ) ≤ (1 : ℝ) / (2 * ((b : ℝ) + (j : ℝ) * (d : ℝ))) := by apply div_nonneg · norm_num · linarith exact h₂ lemma sum_val_reciprocal_le_sum_range (n d : ℕ) [NeZero n] [NeZero d] (_hn : 2 ≤ n) (hd_dvd : d ∣ n) (b : ℕ) (hb_pos : 1 ≤ b) (hb_lt : b < d) : (∑ l : ZMod n, if (ZMod.val l % d = b ∧ 2 * ZMod.val l ≤ n) then (1 : ℝ) / (2 * (ZMod.val l : ℝ)) else 0) ≤ ∑ j ∈ Finset.range (n / (2 * d) + 1), (1 : ℝ) / (2 * ((b : ℝ) + (j : ℝ) * (d : ℝ))) := by rw [← Finset.sum_filter] set S := Finset.univ.filter (fun l : ZMod n => ZMod.val l % d = b ∧ 2 * ZMod.val l ≤ n) set φ := fun l : ZMod n => (ZMod.val l - b) / d set g := fun j : ℕ => (1 : ℝ) / (2 * ((b : ℝ) + (j : ℝ) * (d : ℝ))) have hsummand : ∀ l ∈ S, (1 : ℝ) / (2 * (ZMod.val l : ℝ)) = g (φ l) := by intro l hl simp only [S, Finset.mem_filter, Finset.mem_univ, true_and] at hl exact summand_eq n d b hb_pos hb_lt l hl calc ∑ l ∈ S, (1 : ℝ) / (2 * (ZMod.val l : ℝ)) = ∑ l ∈ S, g (φ l) := Finset.sum_congr rfl hsummand _ = ∑ j ∈ S.image φ, g j := by rw [Finset.sum_image] exact fun l₁ hl₁ l₂ hl₂ heq => quotient_injOn n d hd_dvd b hb_lt (Finset.mem_coe.mpr hl₁) (Finset.mem_coe.mpr hl₂) heq _ ≤ ∑ j ∈ Finset.range (n / (2 * d) + 1), g j := by apply Finset.sum_le_sum_of_subset_of_nonneg · intro j hj rw [Finset.mem_image] at hj obtain ⟨l, hl, rfl⟩ := hj simp only [S, Finset.mem_filter, Finset.mem_univ, true_and] at hl exact quotient_mem_range n d hd_dvd b hb_pos hb_lt l hl · intro j _ _ exact rhs_term_nonneg b d hb_pos j lemma low_range_le_sum_over_j (n d : ℕ) [NeZero n] [NeZero d] (hn : 2 ≤ n) (hd_dvd : d ∣ n) (mq : ℕ) (hmq_lo : 1 ≤ mq) (hmq_hi : mq < n) (b : ℕ) (hb_pos : 1 ≤ b) (hb_lt : b < d) : (∑ l : ZMod n, if (ZMod.val l % d = b ∧ 2 * ZMod.val l ≤ n) then ‖normalizedDFT n (intervalIndicator n mq) l‖ else 0) ≤ ∑ j ∈ Finset.range (n / (2 * d) + 1), (1 : ℝ) / (2 * ((b : ℝ) + (j : ℝ) * (d : ℝ))) := by calc (∑ l : ZMod n, if (ZMod.val l % d = b ∧ 2 * ZMod.val l ≤ n) then ‖normalizedDFT n (intervalIndicator n mq) l‖ else 0) ≤ (∑ l : ZMod n, if (ZMod.val l % d = b ∧ 2 * ZMod.val l ≤ n) then (1 : ℝ) / (2 * (ZMod.val l : ℝ)) else 0) := by apply Finset.sum_le_sum intro l _ split_ifs with h · exact pointwise_bound_in_low_range n d mq hmq_lo hmq_hi b hb_pos hb_lt l h.1 h.2 · exact le_refl 0 _ ≤ ∑ j ∈ Finset.range (n / (2 * d) + 1), (1 : ℝ) / (2 * ((b : ℝ) + (j : ℝ) * (d : ℝ))) := by exact sum_val_reciprocal_le_sum_range n d hn hd_dvd b hb_pos hb_lt lemma sum_range_split (J : ℕ) (f : ℕ → ℝ) : ∑ j ∈ Finset.range (J + 1), f j = f 0 + ∑ j ∈ Finset.Icc 1 J, f j := by have h : Finset.range (J + 1) = {0} ∪ Finset.Icc 1 J := by ext x; simp [Finset.mem_range, Finset.mem_Icc]; omega have hdisj : Disjoint ({0} : Finset ℕ) (Finset.Icc 1 J) := by simp [Finset.disjoint_left, Finset.mem_Icc] rw [h, Finset.sum_union hdisj, Finset.sum_singleton] lemma two_mul_add_one_le_real (M n : ℕ) (hM : M ≤ n) : (2 : ℝ) * ↑M + 1 ≤ 2 * ↑n + 1 := by norm_cast omega lemma two_mul_add_one_pos (M : ℕ) : (0 : ℝ) < 2 * ↑M + 1 := by positivity theorem log_two_n_plus_one_le_one_plus_log (n : ℕ) (hn : 2 ≤ n) : Real.log (2 * ↑n + 1) ≤ 1 + Real.log ↑n := by have h₁ : (n : ℝ) ≥ 2 := by exact_mod_cast hn have h₄ : (2 : ℝ) * ↑n + 1 ≤ (n : ℝ) * Real.exp 1 := by have h₅ : Real.exp 1 ≥ 2 + 1 / 2 := by have := Real.exp_one_gt_d9 norm_num at this ⊢ <;> linarith have h₆ : (2 : ℝ) * ↑n + 1 ≤ (n : ℝ) * Real.exp 1 := by have h₈ : (n : ℝ) * Real.exp 1 ≥ (n : ℝ) * (2 + 1 / 2) := by nlinarith linarith exact h₆ have h₅ : Real.log (2 * ↑n + 1) ≤ Real.log ((n : ℝ) * Real.exp 1) := by apply Real.log_le_log · positivity · exact h₄ have h₆ : Real.log ((n : ℝ) * Real.exp 1) = Real.log (n : ℝ) + Real.log (Real.exp 1) := by rw [Real.log_mul (by positivity) (by positivity)] have h₇ : Real.log (Real.exp 1) = 1 := by rw [Real.log_exp] linarith theorem sum_range_eq_sum_Icc (M : ℕ) : ∑ j ∈ Finset.range M, (1 : ℝ) / ((j : ℝ) + 1) = ∑ u ∈ Finset.Icc 1 M, (↑u)⁻¹ := by have h₁ : ∑ j ∈ Finset.range M, (1 : ℝ) / ((j : ℝ) + 1) = ∑ j ∈ Finset.range M, ((j + 1 : ℕ) : ℝ)⁻¹ := by apply Finset.sum_congr rfl intro j _ have h₂ : (1 : ℝ) / ((j : ℝ) + 1) = ((j + 1 : ℕ) : ℝ)⁻¹ := by field_simp [Nat.cast_add_one_ne_zero] <;> ring_nf <;> norm_cast rw [h₂] rw [h₁] have h₂ : ∑ j ∈ Finset.range M, ((j + 1 : ℕ) : ℝ)⁻¹ = ∑ u ∈ Finset.Icc 1 M, (u : ℝ)⁻¹ := by have h₃ : ∑ j ∈ Finset.range M, ((j + 1 : ℕ) : ℝ)⁻¹ = ∑ u ∈ Finset.Icc 1 M, (u : ℝ)⁻¹ := by have h₅ : Finset.sum (Finset.range M) (fun j => ((j + 1 : ℕ) : ℝ)⁻¹) = Finset.sum (Finset.Icc 1 M) (fun u => (u : ℝ)⁻¹) := by apply Eq.symm apply Finset.sum_bij' (fun (u : ℕ) _ => u - 1) (fun (j : ℕ) _ => j + 1) <;> simp_all [Finset.mem_Icc, Finset.mem_range, Nat.lt_succ_iff] <;> omega rw [h₅] rw [h₃] rw [h₂] lemma harmonic_range_le_one_plus_log (M n : ℕ) (hn : 2 ≤ n) (hM : M ≤ n) : ∑ j ∈ Finset.range M, (1 : ℝ) / ((j : ℝ) + 1) ≤ 1 + Real.log ↑n := by by_cases hM0 : M = 0 · simp [hM0] exact one_plus_log_nonneg n hn · push_neg at hM0 have hM_pos : 1 ≤ M := Nat.one_le_iff_ne_zero.mpr hM0 rw [sum_range_eq_sum_Icc M] calc ∑ u ∈ Finset.Icc 1 M, (↑u)⁻¹ ≤ Real.log (2 * ↑M + 1) := harmonic_Icc_le_log_odd M hM_pos _ ≤ Real.log (2 * ↑n + 1) := by apply Real.log_le_log (two_mul_add_one_pos M) exact two_mul_add_one_le_real M n hM _ ≤ 1 + Real.log ↑n := log_two_n_plus_one_le_one_plus_log n hn lemma summand_bound (d : ℕ) (hd_pos : 0 < d) (b : ℕ) (hb_pos : 1 ≤ b) (j : ℕ) (hj : 1 ≤ j) : (1 : ℝ) / (2 * ((b : ℝ) + (j : ℝ) * (d : ℝ))) ≤ (1 : ℝ) / (2 * ((j : ℝ) * (d : ℝ))) := by have h₃ : (0 : ℝ) < (b : ℝ) := by exact_mod_cast (by positivity) have h₉ : (1 : ℝ) / (2 * ((b : ℝ) + (j : ℝ) * (d : ℝ))) ≤ (1 : ℝ) / (2 * ((j : ℝ) * (d : ℝ))) := by apply one_div_le_one_div_of_le · positivity · linarith exact h₉ lemma sum_factor_Icc (n d : ℕ) (hd_pos : 0 < d) : ∑ j ∈ Finset.Icc 1 (n / (2 * d)), (1 : ℝ) / (2 * ((j : ℝ) * (d : ℝ))) = (∑ j ∈ Finset.Icc 1 (n / (2 * d)), (1 : ℝ) / (j : ℝ)) / (2 * (d : ℝ)) := by have h₁ : ∑ j ∈ Finset.Icc 1 (n / (2 * d)), (1 : ℝ) / (2 * ((j : ℝ) * (d : ℝ))) = ∑ j ∈ Finset.Icc 1 (n / (2 * d)), ((1 : ℝ) / (j : ℝ)) / (2 * (d : ℝ)) := by apply Finset.sum_congr rfl intro j hj have h₂ : j ∈ Finset.Icc 1 (n / (2 * d)) := hj have h₃ : 1 ≤ j := by simp [Finset.mem_Icc] at h₂ linarith have h₄ : 0 < (j : ℝ) := by norm_cast have h₅ : 0 < (d : ℝ) := by norm_cast have h₆ : 0 < (j : ℝ) * (d : ℝ) := by positivity have h₇ : 0 < 2 * ((j : ℝ) * (d : ℝ)) := by positivity field_simp [h₄.ne', h₅.ne', h₆.ne', h₇.ne'] have h₂ : ∑ j ∈ Finset.Icc 1 (n / (2 * d)), ((1 : ℝ) / (j : ℝ)) / (2 * (d : ℝ)) = (∑ j ∈ Finset.Icc 1 (n / (2 * d)), (1 : ℝ) / (j : ℝ)) / (2 * (d : ℝ)) := by calc ∑ j ∈ Finset.Icc 1 (n / (2 * d)), ((1 : ℝ) / (j : ℝ)) / (2 * (d : ℝ)) = ∑ j ∈ Finset.Icc 1 (n / (2 * d)), (1 / (j : ℝ) : ℝ) / (2 * (d : ℝ)) := by simp _ = (∑ j ∈ Finset.Icc 1 (n / (2 * d)), (1 / (j : ℝ) : ℝ)) / (2 * (d : ℝ)) := by rw [Finset.sum_div] rw [h₁, h₂] lemma sum_Icc_eq_sum_range (J : ℕ) : ∑ j ∈ Finset.Icc 1 J, (1 : ℝ) / (j : ℝ) = ∑ j ∈ Finset.range J, (1 : ℝ) / ((j : ℝ) + 1) := by induction J with | zero => simp | succ J ih => simp_all [Finset.sum_Icc_succ_top, Finset.sum_range_succ, Nat.cast_add, Nat.cast_one] lemma harmonic_sum_over_Icc_le_log_div (n d : ℕ) (hn : 2 ≤ n) (hd_pos : 0 < d) (_hd_le : d ≤ n) : ∑ j ∈ Finset.Icc 1 (n / (2 * d)), (1 : ℝ) / (2 * ((j : ℝ) * (d : ℝ))) ≤ (1 + Real.log ↑n) / (2 * ↑d) := by rw [sum_factor_Icc n d hd_pos, sum_Icc_eq_sum_range] apply div_le_div_of_nonneg_right · exact harmonic_range_le_one_plus_log _ n hn (Nat.div_le_self n (2 * d)) · positivity lemma tail_sum_le_log_div (n d : ℕ) (hn : 2 ≤ n) (hd_pos : 0 < d) (hd_le : d ≤ n) (b : ℕ) (hb_pos : 1 ≤ b) : ∑ j ∈ Finset.Icc 1 (n / (2 * d)), (1 : ℝ) / (2 * ((b : ℝ) + (j : ℝ) * (d : ℝ))) ≤ (1 + Real.log ↑n) / (2 * ↑d) := by calc ∑ j ∈ Finset.Icc 1 (n / (2 * d)), (1 : ℝ) / (2 * ((b : ℝ) + (j : ℝ) * (d : ℝ))) ≤ ∑ j ∈ Finset.Icc 1 (n / (2 * d)), (1 : ℝ) / (2 * ((j : ℝ) * (d : ℝ))) := by apply Finset.sum_le_sum intro j hj exact summand_bound d hd_pos b hb_pos j (by exact (Finset.mem_Icc.mp hj).1) _ ≤ (1 + Real.log ↑n) / (2 * ↑d) := harmonic_sum_over_Icc_le_log_div n d hn hd_pos hd_le lemma arith_prog_sum_le_low (n d : ℕ) (hn : 2 ≤ n) (hd_pos : 0 < d) (hd_le : d ≤ n) (b : ℕ) (hb_pos : 1 ≤ b) (hb_lt : b < d) : ∑ j ∈ Finset.range (n / (2 * d) + 1), (1 : ℝ) / (2 * ((b : ℝ) + (j : ℝ) * (d : ℝ))) ≤ 1 / (2 * (b : ℝ)) + (1 + Real.log ↑n) / (2 * ↑d) := by rw [sum_range_split] simp only [Nat.cast_zero, zero_mul, add_zero] gcongr exact tail_sum_le_log_div n d hn hd_pos hd_le b hb_pos lemma low_range_bound (n d : ℕ) [NeZero n] [NeZero d] (hn : 2 ≤ n) (hd_dvd : d ∣ n) (mq : ℕ) (hmq_lo : 1 ≤ mq) (hmq_hi : mq < n) (b : ℕ) (hb_pos : 1 ≤ b) (hb_lt : b < d) : (∑ l : ZMod n, if (ZMod.val l % d = b ∧ 2 * ZMod.val l ≤ n) then ‖normalizedDFT n (intervalIndicator n mq) l‖ else 0) ≤ 1 / (2 * (b : ℝ)) + (1 + Real.log ↑n) / (2 * ↑d) := by have hd_pos : (0 : ℕ) < d := Nat.pos_of_ne_zero (NeZero.ne d) have hd_le : d ≤ n := Nat.le_of_dvd (Nat.pos_of_ne_zero (NeZero.ne n)) hd_dvd have step1 := low_range_le_sum_over_j n d hn hd_dvd mq hmq_lo hmq_hi b hb_pos hb_lt have step2 := arith_prog_sum_le_low n d hn hd_pos hd_le b hb_pos hb_lt linarith lemma high_range_pointwise_bound (n : ℕ) [NeZero n] (mq : ℕ) (hmq_lo : 1 ≤ mq) (hmq_hi : mq < n) (d : ℕ) (b : ℕ) (hb_pos : 1 ≤ b) (l : ZMod n) (hl_mod : ZMod.val l % d = b) (hl_high : ¬(2 * ZMod.val l ≤ n)) : ‖normalizedDFT n (intervalIndicator n mq) l‖ ≤ 1 / (2 * ((n : ℝ) - ZMod.val l)) := by have hval_pos : 0 < ZMod.val l := by have h1 : 0 < ZMod.val l % d := by rw [hl_mod]; exact hb_pos exact Nat.pos_of_ne_zero (by intro h; simp [h] at h1) have hl_ne : l ≠ 0 := by intro h rw [h, ZMod.val_zero] at hval_pos exact Nat.lt_irrefl 0 hval_pos have hbound := normalizedDFT_intervalIndicator_nonzero_bound n mq hmq_lo hmq_hi l hl_ne have hgt : n < 2 * ZMod.val l := by omega have hmin : min (↑(ZMod.val l)) ((↑n : ℝ) - ↑(ZMod.val l)) = (↑n : ℝ) - ↑(ZMod.val l) := by apply min_eq_right have : (↑n : ℝ) < 2 * (↑(ZMod.val l) : ℝ) := by exact_mod_cast hgt linarith rwa [hmin] at hbound lemma quot_lt (n d : ℕ) (hd_dvd : d ∣ n) (b : ℕ) (hb_pos : 1 ≤ b) (hb_lt : b < d) (v : ℕ) (hv_lt : v < n) (hv_mod : v % d = b) : v / d < n / d := by have h_v_eq : v = d * (v / d) + b := by have h₁ : v = d * (v / d) + (v % d) := by have h₂ := Nat.div_add_mod v d linarith rw [hv_mod] at h₁ linarith have h_n_eq : n = d * (n / d) := by have h₁ : d * (n / d) = n := by have h₂ : d ∣ n := hd_dvd have h₃ : d * (n / d) = n := Nat.mul_div_cancel' h₂ exact h₃ linarith have h_strict_ineq : d * (v / d) + 1 < d * (n / d) := by have h₃ : d * (v / d) + 1 < d * (n / d) := by omega exact h₃ have h_final : v / d < n / d := by by_contra! h have h₂ : d * (v / d) ≥ d * (n / d) := by nlinarith omega exact h_final lemma nat_sub_mul_add (A B d b : ℕ) (hBA : B < A) (hbd : b < d) : d * A - (d * B + b) = d * (A - B - 1) + (d - b) := by have h₃ : A - B - 1 + 1 = A - B := by have h₃₂ : A - B - 1 + 1 = A - B := by have h₃₃ : A - B - 1 + 1 = A - B := by have h₃₄ : A - B - 1 + 1 = A - B := by omega exact h₃₄ exact h₃₃ exact h₃₂ have h₄ : d * A - (d * B + b) = d * (A - B - 1) + (d - b) := by have h₄₁ : d * A - (d * B + b) = d * A - (d * B + b) := rfl rw [h₄₁] have h₄₂ : d * A - (d * B + b) = d * (A - B) - b := by have h₄₃ : d * A - (d * B + b) = d * (A - B) - b := by have h₄₇ : d * A - (d * B + b) = d * (A - B) - b := by have h₄₈ : d * (A - B) = d * A - d * B := by have h₄₉ : d * (A - B) = d * A - d * B := by rw [Nat.mul_sub_left_distrib] exact h₄₉ have h₅₀ : d * (A - B) - b = (d * A - d * B) - b := by rw [h₄₈] have h₅₁ : d * A - (d * B + b) = d * (A - B) - b := by omega exact h₅₁ exact h₄₇ exact h₄₃ rw [h₄₂] have h₄₃ : d * (A - B) - b = d * (A - B - 1) + (d - b) := by have h₄₅ : d * (A - B) - b = d * (A - B - 1) + (d - b) := by have h₄₆ : d * (A - B) = d * (A - B - 1) + d := by have h₄₇ : A - B - 1 + 1 = A - B := h₃ have h₄₈ : d * (A - B) = d * (A - B - 1 + 1) := by rw [h₄₇] have h₅₀ : d * (A - B) = d * (A - B - 1) + d := by linarith exact h₅₀ have h₄₇ : d * (A - B) - b = (d * (A - B - 1) + d) - b := by rw [h₄₆] have h₄₈ : (d * (A - B - 1) + d) - b = d * (A - B - 1) + (d - b) := by have h₅₁ : (d * (A - B - 1) + d) - b = d * (A - B - 1) + (d - b) := by have h₅₄ : (d * (A - B - 1) + d) - b = d * (A - B - 1) + (d - b) := by have h₅₆ : (d * (A - B - 1) + d) - b = d * (A - B - 1) + (d - b) := by omega exact h₅₆ exact h₅₄ exact h₅₁ have h₄₉ : d * (A - B) - b = d * (A - B - 1) + (d - b) := by omega exact h₄₉ exact h₄₅ rw [h₄₃] apply h₄ lemma n_sub_v_eq (n d : ℕ) (hd_dvd : d ∣ n) (b : ℕ) (hb_pos : 1 ≤ b) (hb_lt : b < d) (v : ℕ) (hv_lt : v < n) (hv_mod : v % d = b) (hquot : v / d < n / d) : n - v = d * (n / d - v / d - 1) + (d - b) := by have hn_eq : n = d * (n / d) := by have h0 : n % d = 0 := Nat.dvd_iff_mod_eq_zero.mp hd_dvd have := Nat.div_add_mod n d omega have hv_eq : v = d * (v / d) + b := by have := Nat.div_add_mod v d omega have _hb := hb_pos have key := nat_sub_mul_add (n / d) (v / d) d b hquot hb_lt omega lemma n_sub_v_mod_eq_d_sub_b (n d : ℕ) (hd_dvd : d ∣ n) (b : ℕ) (hb_pos : 1 ≤ b) (hb_lt : b < d) (v : ℕ) (hv_lt : v < n) (hv_mod : v % d = b) : (n - v) % d = d - b := by have hquot := quot_lt n d hd_dvd b hb_pos hb_lt v hv_lt hv_mod rw [n_sub_v_eq n d hd_dvd b hb_pos hb_lt v hv_lt hv_mod hquot] have hdb : d - b < d := by omega rw [Nat.add_comm] rw [Nat.add_mul_mod_self_left] exact Nat.mod_eq_of_lt hdb lemma d_sub_b_le_n_sub_v (n d : ℕ) (hd_dvd : d ∣ n) (b : ℕ) (hb_pos : 1 ≤ b) (hb_lt : b < d) (v : ℕ) (hv_lt : v < n) (hv_mod : v % d = b) (hv_big : n < 2 * v) : d - b ≤ n - v := by by_contra h push_neg at h have hdb_lt_d : d - b < d := Nat.sub_lt (by omega) hb_pos have hnv_lt_d : n - v < d := by omega have hmod : (n - v) % d = d - b := n_sub_v_mod_eq_d_sub_b n d hd_dvd b hb_pos hb_lt v hv_lt hv_mod rw [Nat.mod_eq_of_lt hnv_lt_d] at hmod omega lemma n_modEq_d_of_dvd (n d : ℕ) (hd_dvd : d ∣ n) : n ≡ d [MOD d] := by simp [Nat.ModEq, Nat.mod_self, Nat.dvd_iff_mod_eq_zero.mp hd_dvd] lemma v_modEq_b_of_mod (d : ℕ) (b : ℕ) (hb_lt : b < d) (v : ℕ) (hv_mod : v % d = b) : v ≡ b [MOD d] := by simp [Nat.ModEq, hv_mod, Nat.mod_eq_of_lt hb_lt] lemma complement_div_d_dvd (n d : ℕ) (hd_dvd : d ∣ n) (b : ℕ) (hb_pos : 1 ≤ b) (hb_lt : b < d) (v : ℕ) (hv_lt : v < n) (hv_mod : v % d = b) (hv_big : n < 2 * v) : d ∣ (n - v - (d - b)) := by have h_le : d - b ≤ n - v := d_sub_b_le_n_sub_v n d hd_dvd b hb_pos hb_lt v hv_lt hv_mod hv_big have h1 : n ≡ d [MOD d] := n_modEq_d_of_dvd n d hd_dvd have h2 : v ≡ b [MOD d] := v_modEq_b_of_mod d b hb_lt v hv_mod have hv_le : v ≤ n := le_of_lt hv_lt have hb_le : b ≤ d := le_of_lt hb_lt have h3 : n - v ≡ d - b [MOD d] := Nat.ModEq.sub hv_le hb_le h1 h2 exact (Nat.modEq_iff_dvd' h_le).mp (Nat.ModEq.comm.mpr h3) lemma sub_d_sub_b_le_sub_v (n d : ℕ) (_hd_pos : 0 < d) (_hd_dvd : d ∣ n) (b : ℕ) (_hb_pos : 1 ≤ b) (_hb_lt : b < d) (v : ℕ) (_hv_lt : v < n) (_hv_mod : v % d = b) (_hv_big : n < 2 * v) : n - v - (d - b) ≤ n - v := by exact Nat.sub_le (n - v) (d - b) lemma n_sub_v_le_half_n (n : ℕ) (v : ℕ) (hv_lt : v < n) (hv_big : n < 2 * v) : n - v ≤ n / 2 := by omega lemma complement_j_in_range (n d : ℕ) (hd_pos : 0 < d) (hd_dvd : d ∣ n) (b : ℕ) (hb_pos : 1 ≤ b) (hb_lt : b < d) (v : ℕ) (hv_lt : v < n) (hv_mod : v % d = b) (hv_big : n < 2 * v) : (n - v - (d - b)) / d < n / (2 * d) + 1 := by calc (n - v - (d - b)) / d ≤ (n - v) / d := Nat.div_le_div_right (sub_d_sub_b_le_sub_v n d hd_pos hd_dvd b hb_pos hb_lt v hv_lt hv_mod hv_big) _ ≤ (n / 2) / d := Nat.div_le_div_right (n_sub_v_le_half_n n v hv_lt hv_big) _ = n / (2 * d) := Nat.div_div_eq_div_mul n 2 d _ < n / (2 * d) + 1 := Nat.lt_succ_of_le (le_refl _) lemma complement_eq_arith_prog (n d : ℕ) (hd_dvd : d ∣ n) (b : ℕ) (hb_pos : 1 ≤ b) (hb_lt : b < d) (v : ℕ) (hv_lt : v < n) (hv_mod : v % d = b) (hv_big : n < 2 * v) : n - v = (d - b) + ((n - v - (d - b)) / d) * d := by have h_le : d - b ≤ n - v := d_sub_b_le_n_sub_v n d hd_dvd b hb_pos hb_lt v hv_lt hv_mod hv_big have h_dvd : d ∣ (n - v - (d - b)) := complement_div_d_dvd n d hd_dvd b hb_pos hb_lt v hv_lt hv_mod hv_big have h_cancel : (n - v - (d - b)) / d * d = n - v - (d - b) := Nat.div_mul_cancel h_dvd omega lemma complement_eq_arith_prog_real (n d : ℕ) (hd_dvd : d ∣ n) (b : ℕ) (hb_pos : 1 ≤ b) (hb_lt : b < d) (v : ℕ) (hv_lt : v < n) (hv_mod : v % d = b) (hv_big : n < 2 * v) : (n : ℝ) - v = (d : ℝ) - b + ((n - v - (d - b)) / d : ℕ) * d := by have hnat := complement_eq_arith_prog n d hd_dvd b hb_pos hb_lt v hv_lt hv_mod hv_big have hvn : v ≤ n := le_of_lt hv_lt have hbd : b ≤ d := le_of_lt hb_lt have hdb_le : d - b ≤ n - v := d_sub_b_le_n_sub_v n d hd_dvd b hb_pos hb_lt v hv_lt hv_mod hv_big have hnat_cast : ((n - v : ℕ) : ℝ) = (((d - b) + ((n - v - (d - b)) / d) * d : ℕ) : ℝ) := by exact_mod_cast hnat rw [Nat.cast_sub hvn] at hnat_cast rw [Nat.cast_add, Nat.cast_sub hbd, Nat.cast_mul] at hnat_cast exact hnat_cast lemma eq_of_dvd_div_eq (a b d : ℕ) (hd : 0 < d) (ha : d ∣ a) (hb : d ∣ b) (h : a / d = b / d) : a = b := by have h₁ : a = d * (a / d) := by have h₂ : d * (a / d) = a := by apply Nat.mul_div_cancel' exact ha linarith have h₂ : b = d * (b / d) := by have h₃ : d * (b / d) = b := by apply Nat.mul_div_cancel' exact hb linarith have h₃ : a = b := by rw [h₁, h₂, h] exact h₃ lemma complement_map_injective (n d : ℕ) (hd_dvd : d ∣ n) (b : ℕ) (hb_pos : 1 ≤ b) (hb_lt : b < d) : ∀ v₁ v₂ : ℕ, v₁ < n → v₁ % d = b → n < 2 * v₁ → v₂ < n → v₂ % d = b → n < 2 * v₂ → (n - v₁ - (d - b)) / d = (n - v₂ - (d - b)) / d → v₁ = v₂ := by intro v₁ v₂ hv₁_lt hv₁_mod hv₁_big hv₂_lt hv₂_mod hv₂_big hdiv_eq have hd_pos : 0 < d := by omega have h_dvd₁ := complement_div_d_dvd n d hd_dvd b hb_pos hb_lt v₁ hv₁_lt hv₁_mod hv₁_big have h_dvd₂ := complement_div_d_dvd n d hd_dvd b hb_pos hb_lt v₂ hv₂_lt hv₂_mod hv₂_big have h_le₁ := d_sub_b_le_n_sub_v n d hd_dvd b hb_pos hb_lt v₁ hv₁_lt hv₁_mod hv₁_big have h_le₂ := d_sub_b_le_n_sub_v n d hd_dvd b hb_pos hb_lt v₂ hv₂_lt hv₂_mod hv₂_big have h_eq := eq_of_dvd_div_eq _ _ d hd_pos h_dvd₁ h_dvd₂ hdiv_eq omega lemma arith_prog_summand_nonneg (d b : ℕ) (hb_pos : 1 ≤ b) (hb_lt : b < d) (j : ℕ) : (0 : ℝ) ≤ (1 : ℝ) / (2 * ((d : ℝ) - b + j * d)) := by have h₁ : (d : ℝ) - b + j * d > 0 := by have h₂ : (d : ℝ) - b > 0 := by have h₃ : (b : ℝ) < d := by exact_mod_cast hb_lt linarith have h₄ : (j : ℝ) * d ≥ 0 := by nlinarith linarith have h₃ : (0 : ℝ) ≤ (1 : ℝ) / (2 * ((d : ℝ) - b + j * d)) := by apply (div_nonneg) <;> (try positivity) exact h₃ lemma reindex_map_injOn (n d : ℕ) [NeZero n] [NeZero d] (_hn : 2 ≤ n) (hd_dvd : d ∣ n) (b : ℕ) (hb_pos : 1 ≤ b) (hb_lt : b < d) : Set.InjOn (fun l : ZMod n => (n - ZMod.val l - (d - b)) / d) (Finset.univ.filter (fun l : ZMod n => ZMod.val l % d = b ∧ ¬(2 * ZMod.val l ≤ n)) : Set (ZMod n)) := by intro l₁ hl₁ l₂ hl₂ heq simp only [Finset.coe_filter, Finset.mem_univ, true_and, Set.mem_setOf_eq] at hl₁ hl₂ have hv₁_lt := ZMod.val_lt l₁ have hv₂_lt := ZMod.val_lt l₂ have hv₁_mod := hl₁.1 have hv₂_mod := hl₂.1 have hv₁_big : n < 2 * ZMod.val l₁ := by omega have hv₂_big : n < 2 * ZMod.val l₂ := by omega have hval_eq : ZMod.val l₁ = ZMod.val l₂ := complement_map_injective n d hd_dvd b hb_pos hb_lt (ZMod.val l₁) (ZMod.val l₂) hv₁_lt hv₁_mod hv₁_big hv₂_lt hv₂_mod hv₂_big heq exact ZMod.val_injective n hval_eq lemma reindex_filtered_sum (n d : ℕ) [NeZero n] [NeZero d] (hn : 2 ≤ n) (hd_dvd : d ∣ n) (b : ℕ) (hb_pos : 1 ≤ b) (hb_lt : b < d) : (∑ l ∈ Finset.univ.filter (fun l : ZMod n => ZMod.val l % d = b ∧ ¬(2 * ZMod.val l ≤ n)), (1 : ℝ) / (2 * ((n : ℝ) - ZMod.val l))) = ∑ j ∈ (Finset.univ.filter (fun l : ZMod n => ZMod.val l % d = b ∧ ¬(2 * ZMod.val l ≤ n))).image (fun l : ZMod n => (n - ZMod.val l - (d - b)) / d), (1 : ℝ) / (2 * ((d : ℝ) - b + j * d)) := by rw [Finset.sum_image (fun l hl l' hl' heq => reindex_map_injOn n d hn hd_dvd b hb_pos hb_lt (Finset.mem_coe.mpr hl) (Finset.mem_coe.mpr hl') heq)] apply Finset.sum_congr rfl intro l hl simp only [Finset.mem_filter, Finset.mem_univ, true_and] at hl have hv_lt := ZMod.val_lt l have hv_mod := hl.1 have hv_big : n < 2 * ZMod.val l := by omega have heq := complement_eq_arith_prog_real n d hd_dvd b hb_pos hb_lt (ZMod.val l) hv_lt hv_mod hv_big rw [show (2 : ℝ) * ((n : ℝ) - ZMod.val l) = 2 * ((d : ℝ) - b + ((n - ZMod.val l - (d - b)) / d : ℕ) * d) from by rw [heq]] lemma image_subset_range (n d : ℕ) [NeZero n] [NeZero d] (_hn : 2 ≤ n) (hd_dvd : d ∣ n) (b : ℕ) (hb_pos : 1 ≤ b) (hb_lt : b < d) : (Finset.univ.filter (fun l : ZMod n => ZMod.val l % d = b ∧ ¬(2 * ZMod.val l ≤ n))).image (fun l : ZMod n => (n - ZMod.val l - (d - b)) / d) ⊆ Finset.range (n / (2 * d) + 1) := by rw [Finset.image_subset_iff] intro l hl simp only [Finset.mem_filter, Finset.mem_univ, true_and] at hl rw [Finset.mem_range] exact complement_j_in_range n d (NeZero.pos d) hd_dvd b hb_pos hb_lt (ZMod.val l) (ZMod.val_lt l) hl.1 (by omega) lemma high_range_reindex_bound (n d : ℕ) [NeZero n] [NeZero d] (hn : 2 ≤ n) (hd_dvd : d ∣ n) (b : ℕ) (hb_pos : 1 ≤ b) (hb_lt : b < d) : (∑ l : ZMod n, if (ZMod.val l % d = b ∧ ¬(2 * ZMod.val l ≤ n)) then (1 : ℝ) / (2 * ((n : ℝ) - ZMod.val l)) else 0) ≤ ∑ j ∈ Finset.range (n / (2 * d) + 1), (1 : ℝ) / (2 * ((d : ℝ) - b + j * d)) := by rw [← Finset.sum_filter] rw [reindex_filtered_sum n d hn hd_dvd b hb_pos hb_lt] exact Finset.sum_le_sum_of_subset_of_nonneg (image_subset_range n d hn hd_dvd b hb_pos hb_lt) (fun j _ _ => arith_prog_summand_nonneg d b hb_pos hb_lt j) lemma sum_range_le_sum_Icc (n d : ℕ) (hd_pos : 0 < d) (b : ℕ) (hb_pos : 1 ≤ b) (hb_lt : b < d) : ∑ j ∈ Finset.range (n / (2 * d)), (1 : ℝ) / (2 * ((d : ℝ) - b + ((j : ℝ) + 1) * d)) ≤ ∑ j ∈ Finset.Icc 1 (n / (2 * d)), (1 : ℝ) / (2 * ((j : ℝ) * (d : ℝ))) := by have h₁ : ∑ j ∈ Finset.range (n / (2 * d)), (1 : ℝ) / (2 * ((d : ℝ) - b + ((j : ℝ) + 1) * d)) = ∑ j ∈ Finset.Icc 1 (n / (2 * d)), (1 : ℝ) / (2 * ((d : ℝ) - b + ((j : ℝ) - 1 + 1) * d)) := by have h₂ : ∑ j ∈ Finset.range (n / (2 * d)), (1 : ℝ) / (2 * ((d : ℝ) - b + ((j : ℝ) + 1) * d)) = ∑ j ∈ Finset.Icc 1 (n / (2 * d)), (1 : ℝ) / (2 * ((d : ℝ) - b + ((j : ℝ) - 1 + 1) * d)) := by apply Eq.symm apply Finset.sum_bij' (fun j _ => j - 1) (fun j _ => j + 1) <;> simp_all [Finset.mem_Icc, Finset.mem_range, Nat.lt_succ_iff] <;> omega rw [h₂] rw [h₁] have h₃ : ∑ j ∈ Finset.Icc 1 (n / (2 * d)), (1 : ℝ) / (2 * ((d : ℝ) - b + ((j : ℝ) - 1 + 1) * d)) ≤ ∑ j ∈ Finset.Icc 1 (n / (2 * d)), (1 : ℝ) / (2 * ((j : ℝ) * (d : ℝ))) := by apply Finset.sum_le_sum intro j hj have h₄ : (j : ℕ) ∈ Finset.Icc 1 (n / (2 * d)) := hj have h₅ : 1 ≤ j := by simp [Finset.mem_Icc] at h₄ exact h₄.1 have h₉ : (d : ℝ) - b ≥ 0 := by have h₁₀ : (d : ℕ) ≥ b := by omega have h₁₁ : (d : ℝ) ≥ (b : ℝ) := by exact_mod_cast h₁₀ linarith have h₁₀ : (1 : ℝ) / (2 * ((d : ℝ) - b + ((j : ℝ) - 1 + 1) * d)) ≤ (1 : ℝ) / (2 * ((j : ℝ) * (d : ℝ))) := by have h₂₁ : (2 * ((d : ℝ) - b + ((j : ℝ) - 1 + 1) * d) : ℝ) ≥ (2 * ((j : ℝ) * (d : ℝ)) : ℝ) := by nlinarith have h₂₇ : (1 : ℝ) / (2 * ((d : ℝ) - b + ((j : ℝ) - 1 + 1) * d)) ≤ (1 : ℝ) / (2 * ((j : ℝ) * (d : ℝ))) := by apply one_div_le_one_div_of_le · positivity · exact h₂₁ exact h₂₇ exact h₁₀ linarith lemma tail_sum_le (n d : ℕ) (hn : 2 ≤ n) (hd_pos : 0 < d) (hd_le : d ≤ n) (b : ℕ) (hb_pos : 1 ≤ b) (hb_lt : b < d) : ∑ j ∈ Finset.range (n / (2 * d)), (1 : ℝ) / (2 * ((d : ℝ) - b + ((j : ℝ) + 1) * d)) ≤ (1 + Real.log ↑n) / (2 * ↑d) := by calc ∑ j ∈ Finset.range (n / (2 * d)), (1 : ℝ) / (2 * ((d : ℝ) - b + ((j : ℝ) + 1) * d)) ≤ ∑ j ∈ Finset.Icc 1 (n / (2 * d)), (1 : ℝ) / (2 * ((j : ℝ) * (d : ℝ))) := sum_range_le_sum_Icc n d hd_pos b hb_pos hb_lt _ ≤ (1 + Real.log ↑n) / (2 * ↑d) := harmonic_sum_over_Icc_le_log_div n d hn hd_pos hd_le lemma arith_prog_sum_le (n d : ℕ) (hn : 2 ≤ n) (hd_pos : 0 < d) (hd_le : d ≤ n) (b : ℕ) (hb_pos : 1 ≤ b) (hb_lt : b < d) : ∑ j ∈ Finset.range (n / (2 * d) + 1), (1 : ℝ) / (2 * ((d : ℝ) - b + j * d)) ≤ 1 / (2 * ((d : ℝ) - b)) + (1 + Real.log ↑n) / (2 * ↑d) := by rw [Finset.sum_range_succ'] simp only [Nat.cast_zero, zero_mul, add_zero] have h1 : ∀ k ∈ Finset.range (n / (2 * d)), (1 : ℝ) / (2 * ((d : ℝ) - b + ↑(k + 1) * d)) = (1 : ℝ) / (2 * ((d : ℝ) - b + (↑k + 1) * d)) := by intro k _; push_cast; ring_nf rw [Finset.sum_congr rfl h1] linarith [tail_sum_le n d hn hd_pos hd_le b hb_pos hb_lt] lemma high_range_bound (n d : ℕ) [NeZero n] [NeZero d] (hn : 2 ≤ n) (hd_dvd : d ∣ n) (mq : ℕ) (hmq_lo : 1 ≤ mq) (hmq_hi : mq < n) (b : ℕ) (hb_pos : 1 ≤ b) (hb_lt : b < d) : (∑ l : ZMod n, if (ZMod.val l % d = b ∧ ¬(2 * ZMod.val l ≤ n)) then ‖normalizedDFT n (intervalIndicator n mq) l‖ else 0) ≤ 1 / (2 * ((d : ℝ) - b)) + (1 + Real.log ↑n) / (2 * ↑d) := by have hd_pos : 0 < d := NeZero.pos d have hd_le : d ≤ n := Nat.le_of_dvd (by omega) hd_dvd have step1 : (∑ l : ZMod n, if (ZMod.val l % d = b ∧ ¬(2 * ZMod.val l ≤ n)) then ‖normalizedDFT n (intervalIndicator n mq) l‖ else 0) ≤ (∑ l : ZMod n, if (ZMod.val l % d = b ∧ ¬(2 * ZMod.val l ≤ n)) then (1 : ℝ) / (2 * ((n : ℝ) - ZMod.val l)) else 0) := by apply Finset.sum_le_sum intro l _ split_ifs with h · exact high_range_pointwise_bound n mq hmq_lo hmq_hi d b hb_pos l h.1 h.2 · exact le_refl _ have step2 : (∑ l : ZMod n, if (ZMod.val l % d = b ∧ ¬(2 * ZMod.val l ≤ n)) then (1 : ℝ) / (2 * ((n : ℝ) - ZMod.val l)) else 0) ≤ ∑ j ∈ Finset.range (n / (2 * d) + 1), (1 : ℝ) / (2 * ((d : ℝ) - b + j * d)) := high_range_reindex_bound n d hn hd_dvd b hb_pos hb_lt have step3 : ∑ j ∈ Finset.range (n / (2 * d) + 1), (1 : ℝ) / (2 * ((d : ℝ) - b + j * d)) ≤ 1 / (2 * ((d : ℝ) - b)) + (1 + Real.log ↑n) / (2 * ↑d) := arith_prog_sum_le n d hn hd_pos hd_le b hb_pos hb_lt linarith lemma split_sum_low_high (n d : ℕ) [NeZero n] [NeZero d] (mq : ℕ) (b : ℕ) : (∑ l : ZMod n, if (ZMod.val l % d = b) then ‖normalizedDFT n (intervalIndicator n mq) l‖ else 0) = (∑ l : ZMod n, if (ZMod.val l % d = b ∧ 2 * ZMod.val l ≤ n) then ‖normalizedDFT n (intervalIndicator n mq) l‖ else 0) + (∑ l : ZMod n, if (ZMod.val l % d = b ∧ ¬(2 * ZMod.val l ≤ n)) then ‖normalizedDFT n (intervalIndicator n mq) l‖ else 0) := by have h₁ : (∑ l : ZMod n, (if (ZMod.val l % d = b) then ‖normalizedDFT n (intervalIndicator n mq) l‖ else 0 : ℝ)) = (∑ l : ZMod n, ((if (ZMod.val l % d = b ∧ 2 * ZMod.val l ≤ n) then ‖normalizedDFT n (intervalIndicator n mq) l‖ else 0 : ℝ) + (if (ZMod.val l % d = b ∧ ¬(2 * ZMod.val l ≤ n)) then ‖normalizedDFT n (intervalIndicator n mq) l‖ else 0 : ℝ))) := by congr 1; ext l; split_ifs with h1 h2 h3 <;> simp_all rw [h₁, Finset.sum_add_distrib] lemma half_reciprocal_sum_le_min_reciprocal (b d : ℕ) (hb_pos : 1 ≤ b) (hb_lt : b < d) : 1 / (2 * (b : ℝ)) + 1 / (2 * ((d : ℝ) - b)) ≤ 1 / min (b : ℝ) ((d : ℝ) - b) := by have h₂ : (d : ℝ) - b > 0 := by have h₃ : (b : ℝ) < (d : ℝ) := by exact_mod_cast hb_lt linarith by_cases h₄ : (b : ℝ) ≤ (d : ℝ) - b · have h₅ : min (b : ℝ) ((d : ℝ) - b) = (b : ℝ) := by rw [min_eq_left h₄] rw [h₅] have h₆ : 1 / (2 * (b : ℝ)) + 1 / (2 * ((d : ℝ) - b)) ≤ 1 / (b : ℝ) := by have h₁₁ : 1 / (2 * ((d : ℝ) - b)) ≤ 1 / (2 * (b : ℝ)) := by apply one_div_le_one_div_of_le · positivity · nlinarith have h₁₃ : 1 / (2 * (b : ℝ)) + 1 / (2 * (b : ℝ)) = 1 / (b : ℝ) := by field_simp <;> ring_nf linarith exact h₆ · have h₅ : min (b : ℝ) ((d : ℝ) - b) = (d : ℝ) - b := by rw [min_eq_right (by linarith)] rw [h₅] have h₆ : 1 / (2 * (b : ℝ)) + 1 / (2 * ((d : ℝ) - b)) ≤ 1 / ((d : ℝ) - b) := by have h₁₁ : 1 / (2 * (b : ℝ)) ≤ 1 / (2 * ((d : ℝ) - b)) := by apply one_div_le_one_div_of_le · positivity · nlinarith have h₁₃ : 1 / (2 * ((d : ℝ) - b)) + 1 / (2 * ((d : ℝ) - b)) = 1 / ((d : ℝ) - b) := by field_simp <;> ring_nf linarith exact h₆ lemma fourier_mass_residue_class_bound (n d : ℕ) [NeZero n] [NeZero d] (hn : 2 ≤ n) (hd_dvd : d ∣ n) (mq : ℕ) (hmq_lo : 1 ≤ mq) (hmq_hi : mq < n) (b : ℕ) (hb_pos : 1 ≤ b) (hb_lt : b < d) : (∑ l : ZMod n, if (ZMod.val l % d = b) then ‖normalizedDFT n (intervalIndicator n mq) l‖ else 0) ≤ 1 / min (b : ℝ) ((d : ℝ) - b) + (1 + Real.log ↑n) / ↑d := by rw [split_sum_low_high n d mq b] have hlow := low_range_bound n d hn hd_dvd mq hmq_lo hmq_hi b hb_pos hb_lt have hhigh := high_range_bound n d hn hd_dvd mq hmq_lo hmq_hi b hb_pos hb_lt have hcombine := half_reciprocal_sum_le_min_reciprocal b d hb_pos hb_lt have hlog := one_plus_log_nonneg n hn have hd_pos : (0 : ℝ) < d := Nat.cast_pos.mpr (Nat.pos_of_ne_zero (NeZero.ne d)) have hd_ne : (d : ℝ) ≠ 0 := hd_pos.ne' have hsum : (1 + Real.log ↑n) / (2 * ↑d) + (1 + Real.log ↑n) / (2 * ↑d) = (1 + Real.log ↑n) / ↑d := by field_simp; ring linarith lemma inner_sum_bound_at_residue (n d : ℕ) [NeZero n] [NeZero d] (hn : 2 ≤ n) (hd_dvd : d ∣ n) (q : ℤ) (hq_coprime_d : Int.gcd q (d : ℤ) = 1) (hq_pos : 1 ≤ q) (hq_bound : (q : ℝ) < (n : ℝ) / 2) (mq : ℕ) (hmq_lo : 1 ≤ mq) (hmq_hi : mq < n) (k : ZMod n) (hk : k ≠ 0) (hk_nd : ¬((d : ℕ) ∣ ZMod.val k)) (u : (ZMod d)ˣ) : let b := ZMod.val (-(q : ZMod d)⁻¹ * ((ZMod.val k * (u : ZMod d).val : ℕ) : ZMod d)) (∑ l : ZMod n, if ((d : ℤ) ∣ (↑(ZMod.val k) * ↑(u : ZMod d).val + ↑(ZMod.val l) * q)) then ‖normalizedDFT n (intervalIndicator n mq) l‖ else 0) ≤ 1 / min (b : ℝ) ((d : ℝ) - b) + (1 + Real.log ↑n) / ↑d := by intro b clear hq_pos hq_bound have hb := b_bounds d q hq_coprime_d (ZMod.val k) hk_nd u rw [cond_sum_eq_residue_class_sum n d hd_dvd q hq_coprime_d mq k hk u] exact fourier_mass_residue_class_bound n d hn hd_dvd mq hmq_lo hmq_hi b hb.1 hb.2 lemma zmod_expr_simplify (d : ℕ) [NeZero d] (q : ℤ) (hq_coprime_d : Int.gcd q (d : ℤ) = 1) (k_val : ℕ) (w : (ZMod d)ˣ) (hw : (w : ZMod d) = -(q : ZMod d)) (v : (ZMod d)ˣ) : (-(q : ZMod d)⁻¹ * ((k_val * (↑(w * v) : ZMod d).val : ℕ) : ZMod d) : ZMod d) = ((k_val * (↑v : ZMod d).val : ℕ) : ZMod d) := by have _h_unit := neg_inv_isUnit d q hq_coprime_d simp only [Nat.cast_mul, ZMod.natCast_zmod_val, Units.val_mul, hw] rw [neg_inv_eq_inv_neg d q hq_coprime_d, ← hw, ZMod.inv_coe_unit w] rw [show (↑(w⁻¹) : ZMod d) * ((↑k_val : ZMod d) * ((↑w : ZMod d) * (↑v : ZMod d))) = (↑(w⁻¹) : ZMod d) * ((↑w : ZMod d) * ((↑k_val : ZMod d) * (↑v : ZMod d))) from by ring] rw [Units.inv_mul_cancel_left] lemma summand_val_eq_after_bijection (d : ℕ) [NeZero d] (q : ℤ) (hq_coprime_d : Int.gcd q (d : ℤ) = 1) (k_val : ℕ) (hk_nd : ¬(d ∣ k_val)) (w : (ZMod d)ˣ) (hw : (w : ZMod d) = -(q : ZMod d)) (v : (ZMod d)ˣ) : ZMod.val (-(q : ZMod d)⁻¹ * ((k_val * (↑(w * v) : ZMod d).val : ℕ) : ZMod d)) = k_val * (↑v : ZMod d).val % d := by rw [zmod_expr_simplify d q hq_coprime_d k_val w hw v] exact ZMod.val_natCast d (k_val * (↑v : ZMod d).val) lemma neg_q_unit_exists (d : ℕ) [NeZero d] (q : ℤ) (hq_coprime_d : Int.gcd q (d : ℤ) = 1) : ∃ w : (ZMod d)ˣ, (w : ZMod d) = -(q : ZMod d) := by have hq_int_is_coprime : IsCoprime (q : ℤ) (d : ℤ) := by exact Int.isCoprime_iff_gcd_eq_one.mpr hq_coprime_d have hq_zmod_unit : IsUnit (q : ZMod d) := by rw [ZMod.coe_int_isUnit_iff_isCoprime] exact hq_int_is_coprime.symm have h_neg_q_zmod_unit : IsUnit (-(q : ZMod d)) := hq_zmod_unit.neg obtain ⟨w, hw⟩ := h_neg_q_zmod_unit exact ⟨w, hw⟩ lemma bijection_sum_eq (d : ℕ) [NeZero d] (q : ℤ) (hq_coprime_d : Int.gcd q (d : ℤ) = 1) (k_val : ℕ) (hk_nd : ¬(d ∣ k_val)) : (∑ u : (ZMod d)ˣ, let b := ZMod.val (-(q : ZMod d)⁻¹ * ((k_val * (u : ZMod d).val : ℕ) : ZMod d)) 1 / min (b : ℝ) ((d : ℝ) - b)) = (∑ u : (ZMod d)ˣ, 1 / min ((k_val * (u : ZMod d).val % d : ℕ) : ℝ) ((d : ℝ) - (k_val * (u : ZMod d).val % d : ℕ))) := by obtain ⟨w, hw⟩ := neg_q_unit_exists d q hq_coprime_d symm exact Fintype.sum_equiv (Equiv.mulLeft w) (fun v => 1 / min ((k_val * (v : ZMod d).val % d : ℕ) : ℝ) ((d : ℝ) - (k_val * (v : ZMod d).val % d : ℕ))) (fun u => let b := ZMod.val (-(q : ZMod d)⁻¹ * ((k_val * (u : ZMod d).val : ℕ) : ZMod d)) 1 / min (b : ℝ) ((d : ℝ) - b)) (fun v => by show 1 / min ((k_val * (v : ZMod d).val % d : ℕ) : ℝ) ((d : ℝ) - (k_val * (v : ZMod d).val % d : ℕ)) = (let b := ZMod.val (-(q : ZMod d)⁻¹ * ((k_val * ((Equiv.mulLeft w v : (ZMod d)ˣ) : ZMod d).val : ℕ) : ZMod d)) 1 / min (b : ℝ) ((d : ℝ) - b)) simp only [Equiv.coe_mulLeft] have h := summand_val_eq_after_bijection d q hq_coprime_d k_val hk_nd w hw v rw [← h]) end PerUnitMerge open PerUnitMerge in lemma per_unit_inner_sum_bound (n d : ℕ) [NeZero n] [NeZero d] (hn : 2 ≤ n) (hd : d = largestPrimeFactor n ^ n.factorization (largestPrimeFactor n)) (q : ℤ) (hq_coprime : Int.gcd q (largestPrimeFactor n : ℤ) = 1) (hq_pos : 1 ≤ q) (hq_bound : (q : ℝ) < (n : ℝ) / 2) (mq : ℕ) (hmq : mq = (2 * q - 1).toNat) (k : ZMod n) (hk : k ≠ 0) (hk_nd : ¬((d : ℕ) ∣ ZMod.val k)) : (∑ u : (ZMod d)ˣ, (∑ l : ZMod n, if ((d : ℤ) ∣ (↑(ZMod.val k) * ↑(u : ZMod d).val + ↑(ZMod.val l) * q)) then ‖normalizedDFT n (intervalIndicator n mq) l‖ else 0)) ≤ (∑ u : (ZMod d)ˣ, 1 / min ((ZMod.val k * (u : ZMod d).val % d : ℕ) : ℝ) ((d : ℝ) - (ZMod.val k * (u : ZMod d).val % d : ℕ))) + ↑(Fintype.card (ZMod d)ˣ) * ((1 + Real.log ↑n) / ↑d) := by have hd_dvd : d ∣ n := hd ▸ _root_.d_dvd_n n hn have hq_coprime_d : Int.gcd q (d : ℤ) = 1 := coprimality_q_d n hn q hq_coprime d hd have hmq_bounds := mq_bounds n hn q hq_pos hq_bound have hmq_lo : 1 ≤ mq := hmq ▸ hmq_bounds.1 have hmq_hi : mq < n := hmq ▸ hmq_bounds.2 calc ∑ u : (ZMod d)ˣ, (∑ l : ZMod n, if ((d : ℤ) ∣ (↑(ZMod.val k) * ↑(u : ZMod d).val + ↑(ZMod.val l) * q)) then ‖normalizedDFT n (intervalIndicator n mq) l‖ else 0) ≤ ∑ u : (ZMod d)ˣ, (let b := ZMod.val (-(q : ZMod d)⁻¹ * ((ZMod.val k * (u : ZMod d).val : ℕ) : ZMod d)) 1 / min (b : ℝ) ((d : ℝ) - b) + (1 + Real.log ↑n) / ↑d) := by exact Finset.sum_le_sum fun u _ => inner_sum_bound_at_residue n d hn hd_dvd q hq_coprime_d hq_pos hq_bound mq hmq_lo hmq_hi k hk hk_nd u _ = (∑ u : (ZMod d)ˣ, (let b := ZMod.val (-(q : ZMod d)⁻¹ * ((ZMod.val k * (u : ZMod d).val : ℕ) : ZMod d)) 1 / min (b : ℝ) ((d : ℝ) - b))) + ∑ _u : (ZMod d)ˣ, ((1 + Real.log ↑n) / ↑d) := by exact Finset.sum_add_distrib _ = (∑ u : (ZMod d)ˣ, 1 / min ((ZMod.val k * (u : ZMod d).val % d : ℕ) : ℝ) ((d : ℝ) - (ZMod.val k * (u : ZMod d).val % d : ℕ))) + ∑ _u : (ZMod d)ˣ, ((1 + Real.log ↑n) / ↑d) := by congr 1 exact bijection_sum_eq d q hq_coprime_d (ZMod.val k) hk_nd _ = (∑ u : (ZMod d)ˣ, 1 / min ((ZMod.val k * (u : ZMod d).val % d : ℕ) : ℝ) ((d : ℝ) - (ZMod.val k * (u : ZMod d).val % d : ℕ))) + ↑(Fintype.card (ZMod d)ˣ) * ((1 + Real.log ↑n) / ↑d) := by congr 1 simp [Finset.sum_const, Finset.card_univ, nsmul_eq_mul] lemma combine_orbit_and_tail_bounds (C L d_real : ℝ) (hC : 0 ≤ C) (hL : 0 ≤ L) (hd : 0 < d_real) : C * (4 * L / d_real) + C * (L / d_real) ≤ C * (5 * L / d_real) := by have h₃ : 0 < d_real := hd have h₅ : 0 < d_real := h₃ have h₆ : C * (4 * L / d_real) + C * (L / d_real) = C * (4 * L / d_real + L / d_real) := by ring rw [h₆] have h₇ : 4 * L / d_real + L / d_real = 5 * L / d_real := by field_simp [h₅.ne'] <;> ring rw [h₇] lemma orbit_average_bound (n d : ℕ) [NeZero n] [NeZero d] (hn : 2 ≤ n) (hd : d = largestPrimeFactor n ^ n.factorization (largestPrimeFactor n)) (q : ℤ) (hq_coprime : Int.gcd q (largestPrimeFactor n : ℤ) = 1) (hq_pos : 1 ≤ q) (hq_bound : (q : ℝ) < (n : ℝ) / 2) (mq : ℕ) (hmq : mq = (2 * q - 1).toNat) (k : ZMod n) (hk : k ≠ 0) (hk_nd : ¬((d : ℕ) ∣ ZMod.val k)) : (∑ u : (ZMod d)ˣ, (∑ l : ZMod n, if ((d : ℤ) ∣ (↑(ZMod.val k) * ↑(u : ZMod d).val + ↑(ZMod.val l) * q)) then ‖normalizedDFT n (intervalIndicator n mq) l‖ else 0)) ≤ ↑(Fintype.card (ZMod d)ˣ) * (5 * (1 + Real.log ↑n) / ↑d) := by have h_step1 := per_unit_inner_sum_bound n d hn hd q hq_coprime hq_pos hq_bound mq hmq k hk hk_nd have h_step2 := orbit_reciprocal_sum_bound n d hn hd k hk hk_nd calc (∑ u : (ZMod d)ˣ, (∑ l : ZMod n, if ((d : ℤ) ∣ (↑(ZMod.val k) * ↑(u : ZMod d).val + ↑(ZMod.val l) * q)) then ‖normalizedDFT n (intervalIndicator n mq) l‖ else 0)) ≤ (∑ u : (ZMod d)ˣ, 1 / min ((ZMod.val k * (u : ZMod d).val % d : ℕ) : ℝ) ((d : ℝ) - (ZMod.val k * (u : ZMod d).val % d : ℕ))) + ↑(Fintype.card (ZMod d)ˣ) * ((1 + Real.log ↑n) / ↑d) := h_step1 _ ≤ ↑(Fintype.card (ZMod d)ˣ) * (4 * (1 + Real.log ↑n) / ↑d) + ↑(Fintype.card (ZMod d)ˣ) * ((1 + Real.log ↑n) / ↑d) := by gcongr _ ≤ ↑(Fintype.card (ZMod d)ˣ) * (5 * (1 + Real.log ↑n) / ↑d) := combine_orbit_and_tail_bounds ↑(Fintype.card (ZMod d)ˣ) (1 + Real.log ↑n) ↑d (by positivity) (by positivity) (Nat.cast_pos.mpr (NeZero.pos d)) lemma nonmultiple_d_weighted_bound (n d : ℕ) [NeZero n] [NeZero d] (hn : 2 ≤ n) (hd : d = largestPrimeFactor n ^ n.factorization (largestPrimeFactor n)) (q : ℤ) (hq_coprime : Int.gcd q (largestPrimeFactor n : ℤ) = 1) (hq_pos : 1 ≤ q) (hq_bound : (q : ℝ) < (n : ℝ) / 2) (mq : ℕ) (hmq : mq = (2 * q - 1).toNat) : (∑ k ∈ Finset.univ.filter (fun k : ZMod n => k ≠ 0 ∧ ¬((d : ℕ) ∣ ZMod.val k)), ∑ u : (ZMod d)ˣ, (∑ l : ZMod n, if ((d : ℤ) ∣ (↑(ZMod.val k) * ↑(u : ZMod d).val + ↑(ZMod.val l) * q)) then ‖normalizedDFT n (intervalIndicator n mq) l‖ / (2 * min (ZMod.val k : ℝ) ((n : ℝ) - ZMod.val k)) else 0)) ≤ ↑(Fintype.card (ZMod d)ˣ) * (5 * (1 + Real.log ↑n) ^ 2 / ↑d) := by have h_rw : ∀ k ∈ Finset.univ.filter (fun k : ZMod n => k ≠ 0 ∧ ¬((d : ℕ) ∣ ZMod.val k)), (∑ u : (ZMod d)ˣ, (∑ l : ZMod n, if ((d : ℤ) ∣ (↑(ZMod.val k) * ↑(u : ZMod d).val + ↑(ZMod.val l) * q)) then ‖normalizedDFT n (intervalIndicator n mq) l‖ / (2 * min (ZMod.val k : ℝ) ((n : ℝ) - ZMod.val k)) else 0)) = (∑ u : (ZMod d)ˣ, (∑ l : ZMod n, if ((d : ℤ) ∣ (↑(ZMod.val k) * ↑(u : ZMod d).val + ↑(ZMod.val l) * q)) then ‖normalizedDFT n (intervalIndicator n mq) l‖ else 0)) / (2 * min (ZMod.val k : ℝ) ((n : ℝ) - ZMod.val k)) := by intro k hk exact factor_weight_from_double_sum n d mq q k ((Finset.mem_filter.mp hk).2.1) rw [Finset.sum_congr rfl h_rw] calc ∑ k ∈ Finset.univ.filter (fun k : ZMod n => k ≠ 0 ∧ ¬((d : ℕ) ∣ ZMod.val k)), (∑ u : (ZMod d)ˣ, (∑ l : ZMod n, if ((d : ℤ) ∣ (↑(ZMod.val k) * ↑(u : ZMod d).val + ↑(ZMod.val l) * q)) then ‖normalizedDFT n (intervalIndicator n mq) l‖ else 0)) / (2 * min (ZMod.val k : ℝ) ((n : ℝ) - ZMod.val k)) ≤ ∑ k ∈ Finset.univ.filter (fun k : ZMod n => k ≠ 0 ∧ ¬((d : ℕ) ∣ ZMod.val k)), ↑(Fintype.card (ZMod d)ˣ) * (5 * (1 + Real.log ↑n) / ↑d) / (2 * min (ZMod.val k : ℝ) ((n : ℝ) - ZMod.val k)) := by apply Finset.sum_le_sum intro k hk apply div_le_div_of_nonneg_right · exact orbit_average_bound n d hn hd q hq_coprime hq_pos hq_bound mq hmq k ((Finset.mem_filter.mp hk).2.1) ((Finset.mem_filter.mp hk).2.2) · exact weight_nonneg n k ((Finset.mem_filter.mp hk).2.1) _ = ↑(Fintype.card (ZMod d)ˣ) * (5 * (1 + Real.log ↑n) / ↑d) * ∑ k ∈ Finset.univ.filter (fun k : ZMod n => k ≠ 0 ∧ ¬((d : ℕ) ∣ ZMod.val k)), (1 : ℝ) / (2 * min (ZMod.val k : ℝ) ((n : ℝ) - ZMod.val k)) := by rw [Finset.mul_sum] congr 1 ext k ring _ ≤ ↑(Fintype.card (ZMod d)ˣ) * (5 * (1 + Real.log ↑n) / ↑d) * (1 + Real.log ↑n) := by apply mul_le_mul_of_nonneg_left (weight_sum_le_log n d hn) exact const_bound_nonneg n d hn _ = ↑(Fintype.card (ZMod d)ˣ) * (5 * (1 + Real.log ↑n) ^ 2 / ↑d) := by ring lemma weighted_orbit_total (n d : ℕ) [NeZero n] [NeZero d] (hn : 2 ≤ n) (hd : d = largestPrimeFactor n ^ n.factorization (largestPrimeFactor n)) (q : ℤ) (hq_coprime : Int.gcd q (largestPrimeFactor n : ℤ) = 1) (hq_pos : 1 ≤ q) (hq_bound : (q : ℝ) < (n : ℝ) / 2) (mq : ℕ) (hmq : mq = (2 * q - 1).toNat) : ∑ k : ZMod n, ∑ u : (ZMod d)ˣ, (∑ l : ZMod n, if k ≠ 0 ∧ ((d : ℤ) ∣ (↑(ZMod.val k) * ↑(u : ZMod d).val + ↑(ZMod.val l) * q)) then ‖normalizedDFT n (intervalIndicator n mq) l‖ / (2 * min (ZMod.val k : ℝ) ((n : ℝ) - ZMod.val k)) else 0) ≤ ↑(Fintype.card (ZMod d)ˣ) * (6 * (1 + Real.log ↑n) ^ 2 / ↑d) := by rw [k_sum_split_by_d_divisibility n d mq q] calc _ ≤ ↑(Fintype.card (ZMod d)ˣ) * (5 * (1 + Real.log ↑n) ^ 2 / ↑d) + ↑(Fintype.card (ZMod d)ˣ) * ((1 + Real.log ↑n) ^ 2 / ↑d) := add_le_add (nonmultiple_d_weighted_bound n d hn hd q hq_coprime hq_pos hq_bound mq hmq) (multiple_d_weighted_bound n d hn hd q hq_coprime hq_pos hq_bound mq hmq) _ = _ := combine_cases_arithmetic _ _ _ lemma average_S_bound (n d : ℕ) [NeZero n] [NeZero d] (hn : 2 ≤ n) (hd : d = largestPrimeFactor n ^ n.factorization (largestPrimeFactor n)) (q : ℤ) (hq_coprime : Int.gcd q (largestPrimeFactor n : ℤ) = 1) (hq_pos : 1 ≤ q) (hq_bound : (q : ℝ) < (n : ℝ) / 2) (mq : ℕ) (hmq : mq = (2 * q - 1).toNat) : ∑ u : (ZMod d)ˣ, (∑ k : ZMod n, ∑ l : ZMod n, if k ≠ 0 ∧ ((d : ℤ) ∣ (↑(ZMod.val k) * ↑(u : ZMod d).val + ↑(ZMod.val l) * q)) then ‖normalizedDFT n (intervalIndicator n mq) l‖ / (2 * min (ZMod.val k : ℝ) ((n : ℝ) - ZMod.val k)) else 0) ≤ ↑(Fintype.card (ZMod d)ˣ) * (6 * (1 + Real.log ↑n) ^ 2 / ↑d) := by rw [sum_exchange_weighted n d mq q] exact weighted_orbit_total n d hn hd q hq_coprime hq_pos hq_bound mq hmq lemma sum_filter_lower_bound (d : ℕ) [NeZero d] (f : (ZMod d)ˣ → ℝ) (hf : ∀ u, 0 ≤ f u) (avg : ℝ) (R : ℕ) (S : Finset (ZMod d)ˣ) (hS : ∀ u ∈ S, ↑R * avg < f u) : S.card • (↑R * avg) ≤ ∑ u ∈ S, f u := by exact Finset.card_nsmul_le_sum S f (↑R * avg) (fun u hu => le_of_lt (hS u hu)) lemma sum_filter_le_sum_univ (d : ℕ) [NeZero d] (f : (ZMod d)ˣ → ℝ) (hf : ∀ u, 0 ≤ f u) (avg : ℝ) (R : ℕ) : ∑ u ∈ (Finset.univ.filter (fun u : (ZMod d)ˣ => ↑R * avg < f u)), f u ≤ ∑ u : (ZMod d)ˣ, f u := by apply Finset.sum_le_sum_of_subset_of_nonneg (Finset.filter_subset _ _) intro i _ _ exact hf i lemma card_mul_R_le_of_nsmul_le (s C R : ℕ) (avg : ℝ) (havg : 0 < avg) (h : s • (↑R * avg) ≤ ↑C * avg) : s * R ≤ C := by have h₁ : (s : ℝ) * (R : ℝ) * avg ≤ (C : ℝ) * avg := by have h₂ : (s : ℝ) * (R : ℝ) * avg = s • (↑R * avg) := by simp [smul_eq_mul, mul_assoc, mul_comm, mul_left_comm] rw [h₂] at * exact h have h₂ : (s : ℝ) * (R : ℝ) ≤ (C : ℝ) := by have h₄ : 0 < (avg : ℝ) := havg have h₅ : (s : ℝ) * (R : ℝ) ≤ (C : ℝ) := by have h₆ : (s : ℝ) * (R : ℝ) * avg / avg ≤ (C : ℝ) * avg / avg := by gcongr have h₇ : (C : ℝ) * avg / avg = (C : ℝ) := by field_simp [h₄.ne'] have h₈ : (s : ℝ) * (R : ℝ) * avg / avg = (s : ℝ) * (R : ℝ) := by field_simp [h₄.ne'] linarith exact h₅ have h₃ : (s * R : ℝ) ≤ (C : ℝ) := by have h₄ : (s * R : ℝ) = (s : ℝ) * (R : ℝ) := by norm_cast rw [h₄] exact h₂ have h₄ : s * R ≤ C := by norm_cast at h₃ ⊢ exact h₄ lemma filter_empty_of_avg_zero (d : ℕ) [NeZero d] (f : (ZMod d)ˣ → ℝ) (hf : ∀ u, 0 ≤ f u) (hsum : ∑ u : (ZMod d)ˣ, f u ≤ 0) (R : ℕ) : (Finset.univ.filter (fun u : (ZMod d)ˣ => 0 < f u)) = ∅ := by have h_filter_empty : (Finset.univ.filter (fun u : (ZMod d)ˣ => 0 < f u)) = ∅ := by have h₁ : ∀ (u : (ZMod d)ˣ), f u = 0 := by intro u have h₂ : 0 ≤ f u := hf u have h₄ : f u ≤ 0 := by have h₆ : f u ≤ ∑ u : (ZMod d)ˣ, f u := by apply Finset.single_le_sum (fun i _ => hf i) (Finset.mem_univ u) linarith linarith apply Finset.filter_eq_empty_iff.mpr intro u _ have h₂ : f u = 0 := h₁ u have h₃ : ¬(0 < f u) := by rw [h₂] <;> norm_num exact h₃ exact h_filter_empty lemma markov_card_mul_le (d : ℕ) [NeZero d] (f : (ZMod d)ˣ → ℝ) (hf : ∀ u, 0 ≤ f u) (avg : ℝ) (havg : 0 ≤ avg) (hsum : ∑ u : (ZMod d)ˣ, f u ≤ ↑(Fintype.card (ZMod d)ˣ) * avg) (R : ℕ) (hR : 1 ≤ R) : (Finset.univ.filter (fun u : (ZMod d)ˣ => ↑R * avg < f u)).card * R ≤ Fintype.card (ZMod d)ˣ := by have hR_pos : (0 : ℝ) < ↑R := Nat.cast_pos.mpr (Nat.one_le_iff_ne_zero.mp hR |>.bot_lt) set S := Finset.univ.filter (fun u : (ZMod d)ˣ => ↑R * avg < f u) rcases le_or_gt avg 0 with havg0 | havg0 · have heq : avg = 0 := le_antisymm havg0 havg subst heq have hS_empty : S = ∅ := by have : Finset.univ.filter (fun u : (ZMod d)ˣ => 0 < f u) = ∅ := filter_empty_of_avg_zero d f hf (by simp_all) R convert this using 2 ext u simp [mul_zero] rw [hS_empty] simp · have hlower := sum_filter_lower_bound d f hf avg R S (fun u hu => by exact (Finset.mem_filter.mp hu).2) have hupper := sum_filter_le_sum_univ d f hf avg R have hchain : S.card • (↑R * avg) ≤ ↑(Fintype.card (ZMod d)ˣ) * avg := le_trans hlower (le_trans hupper hsum) exact card_mul_R_le_of_nsmul_le S.card (Fintype.card (ZMod d)ˣ) R avg havg0 hchain lemma markov_card_filter_le (d : ℕ) [NeZero d] (f : (ZMod d)ˣ → ℝ) (hf : ∀ u, 0 ≤ f u) (avg : ℝ) (havg : 0 ≤ avg) (hsum : ∑ u : (ZMod d)ˣ, f u ≤ ↑(Fintype.card (ZMod d)ˣ) * avg) (R : ℕ) (hR : 1 ≤ R) : (Finset.univ.filter (fun u : (ZMod d)ˣ => ↑R * avg < f u)).card ≤ Fintype.card (ZMod d)ˣ / R := by have hR_pos : 0 < R := Nat.one_le_iff_ne_zero.mp hR |>.bot_lt exact (Nat.galoisConnection_mul_div hR_pos).le_iff_le.mp (markov_card_mul_le d f hf avg havg hsum R hR) lemma image_val_card_le (d : ℕ) [NeZero d] (S : Finset (ZMod d)ˣ) (R : ℕ) (hR : 1 ≤ R) (hcard : S.card ≤ Fintype.card (ZMod d)ˣ / R) : (S.image (fun u : (ZMod d)ˣ => (u : ZMod d).val)).card ≤ d / R := by have h₁ : (S.image (fun u : (ZMod d)ˣ => (u : ZMod d).val)).card ≤ S.card := by apply Finset.card_image_le have h₂ : Fintype.card (ZMod d)ˣ ≤ d := by have h₃ : Fintype.card (ZMod d)ˣ = d.totient := by rw [ZMod.card_units_eq_totient] rw [h₃] have h₄ : d.totient ≤ d := by apply Nat.totient_le exact h₄ have h₃ : Fintype.card (ZMod d)ˣ / R ≤ d / R := by have h₄ : Fintype.card (ZMod d)ˣ ≤ d := h₂ have h₅ : Fintype.card (ZMod d)ˣ / R ≤ d / R := by apply Nat.div_le_div_right <;> (try omega) exact h₅ calc (S.image (fun u : (ZMod d)ˣ => (u : ZMod d).val)).card ≤ S.card := h₁ _ ≤ Fintype.card (ZMod d)ˣ / R := hcard _ ≤ d / R := h₃ lemma bad_set_from_average (d : ℕ) [NeZero d] (f : (ZMod d)ˣ → ℝ) (hf : ∀ u, 0 ≤ f u) (avg : ℝ) (havg : 0 ≤ avg) (hsum : ∑ u : (ZMod d)ˣ, f u ≤ ↑(Fintype.card (ZMod d)ˣ) * avg) (R : ℕ) (hR : 1 ≤ R) : ∃ B : Finset ℕ, B.card ≤ d / R ∧ ∀ u : (ZMod d)ˣ, (u : ZMod d).val ∉ B → f u ≤ ↑R * avg := by set B_units := Finset.univ.filter (fun u : (ZMod d)ˣ => ↑R * avg < f u) with hB_units_def set B := B_units.image (fun u : (ZMod d)ˣ => (u : ZMod d).val) with hB_def refine ⟨B, ?_, ?_⟩ · have hcard := markov_card_filter_le d f hf avg havg hsum R hR exact image_val_card_le d B_units R hR hcard · intro u hu by_contra h push_neg at h have : u ∈ B_units := by simp only [hB_units_def, Finset.mem_filter, Finset.mem_univ, true_and] exact h have : (u : ZMod d).val ∈ B := by simp only [hB_def] exact Finset.mem_image_of_mem _ this contradiction lemma k_zero_term_eq (n d : ℕ) [NeZero n] [NeZero d] (mp mq : ℕ) (p q : ℤ) : (∑ l : ZMod n, if ((0 : ZMod n), l) ≠ (0, 0) ∧ ((d : ℤ) ∣ (↑(ZMod.val (0 : ZMod n)) * p + ↑(ZMod.val l) * q)) then ‖normalizedDFT n (intervalIndicator n mp) (0 : ZMod n)‖ * ‖normalizedDFT n (intervalIndicator n mq) l‖ else (0 : ℝ)) = (∑ l : ZMod n, if l ≠ 0 ∧ ((d : ℤ) ∣ (↑(ZMod.val l) * q)) then ‖normalizedDFT n (intervalIndicator n mp) (0 : ZMod n)‖ * ‖normalizedDFT n (intervalIndicator n mq) l‖ else (0 : ℝ)) := by apply Finset.sum_congr rfl intro l _ simp_all lemma inner_sum_eq_of_k_ne_zero (n d : ℕ) [NeZero n] [NeZero d] (mp mq : ℕ) (p q : ℤ) (k : ZMod n) (hk : k ≠ 0) : (∑ l : ZMod n, if (k, l) ≠ (0, 0) ∧ ((d : ℤ) ∣ (↑(ZMod.val k) * p + ↑(ZMod.val l) * q)) then ‖normalizedDFT n (intervalIndicator n mp) k‖ * ‖normalizedDFT n (intervalIndicator n mq) l‖ else (0 : ℝ)) = (∑ l : ZMod n, if k ≠ 0 ∧ ((d : ℤ) ∣ (↑(ZMod.val k) * p + ↑(ZMod.val l) * q)) then ‖normalizedDFT n (intervalIndicator n mp) k‖ * ‖normalizedDFT n (intervalIndicator n mq) l‖ else (0 : ℝ)) := by simp_all lemma filtered_sum_to_full_sum (n d : ℕ) [NeZero n] [NeZero d] (mp mq : ℕ) (p q : ℤ) : (∑ k ∈ Finset.univ.filter (· ≠ (0 : ZMod n)), ∑ l : ZMod n, if (k, l) ≠ (0, 0) ∧ ((d : ℤ) ∣ (↑(ZMod.val k) * p + ↑(ZMod.val l) * q)) then ‖normalizedDFT n (intervalIndicator n mp) k‖ * ‖normalizedDFT n (intervalIndicator n mq) l‖ else (0 : ℝ)) = (∑ k : ZMod n, ∑ l : ZMod n, if k ≠ 0 ∧ ((d : ℤ) ∣ (↑(ZMod.val k) * p + ↑(ZMod.val l) * q)) then ‖normalizedDFT n (intervalIndicator n mp) k‖ * ‖normalizedDFT n (intervalIndicator n mq) l‖ else (0 : ℝ)) := by rw [Finset.sum_filter] apply Finset.sum_congr rfl intro k _ by_cases hk : k = 0 · subst hk simp · rw [if_pos hk] exact inner_sum_eq_of_k_ne_zero n d mp mq p q k hk lemma double_sum_split_k0_kneq0 (n d : ℕ) [NeZero n] [NeZero d] (mp mq : ℕ) (p q : ℤ) : (∑ k : ZMod n, ∑ l : ZMod n, if (k, l) ≠ (0, 0) ∧ ((d : ℤ)) ∣ (ZMod.val k * p + ZMod.val l * q) then ‖normalizedDFT n (intervalIndicator n mp) k‖ * ‖normalizedDFT n (intervalIndicator n mq) l‖ else (0 : ℝ)) = (∑ l : ZMod n, if l ≠ 0 ∧ ((d : ℤ) ∣ (↑(ZMod.val l) * q)) then ‖normalizedDFT n (intervalIndicator n mp) (0 : ZMod n)‖ * ‖normalizedDFT n (intervalIndicator n mq) l‖ else (0 : ℝ)) + (∑ k : ZMod n, ∑ l : ZMod n, if k ≠ 0 ∧ ((d : ℤ) ∣ (↑(ZMod.val k) * p + ↑(ZMod.val l) * q)) then ‖normalizedDFT n (intervalIndicator n mp) k‖ * ‖normalizedDFT n (intervalIndicator n mq) l‖ else (0 : ℝ)) := by rw [sum_split_zero] rw [k_zero_term_eq n d mp mq p q] rw [filtered_sum_to_full_sum n d mp mq p q] lemma int_coprime_dvd_mul_imp_dvd (d v : ℕ) (q : ℤ) (hgcd : Int.gcd q (d : ℤ) = 1) (hdvd : (d : ℤ) ∣ (↑v * q)) : d ∣ v := by have h₁ : IsCoprime (d : ℤ) q := by rw [Int.isCoprime_iff_gcd_eq_one] <;> simp_all [Int.gcd_comm] have h₂ : (d : ℤ) ∣ (v : ℤ) := by have h₃ : (d : ℤ) ∣ (v : ℤ) * q := by simpa [mul_comm] using hdvd have h₄ : IsCoprime (d : ℤ) q := h₁ exact h₄.dvd_of_dvd_mul_right h₃ have h₃ : d ∣ v := by exact Int.natCast_dvd_natCast.mp (by simpa using h₂) exact h₃ lemma dvd_val_of_dvd_val_mul_q (n d : ℕ) [NeZero n] [NeZero d] (hn : 2 ≤ n) (hd : d = largestPrimeFactor n ^ n.factorization (largestPrimeFactor n)) (q : ℤ) (hq_coprime : Int.gcd q (largestPrimeFactor n : ℤ) = 1) (l : ZMod n) (_hl : l ≠ 0) (hdvd : (d : ℤ) ∣ (↑(ZMod.val l) * q)) : (d : ℕ) ∣ ZMod.val l := by exact int_coprime_dvd_mul_imp_dvd d (ZMod.val l) q (coprimality_q_d n hn q hq_coprime d hd) hdvd lemma norm_normalizedDFT_zero_le_one (n : ℕ) [NeZero n] (m : ℕ) (hm1 : 1 ≤ m) (hm2 : m < n) : ‖normalizedDFT n (intervalIndicator n m) 0‖ ≤ 1 := by rw [normalizedDFT_intervalIndicator_zero n m hm1 hm2] rw [Complex.norm_div, Complex.norm_natCast, Complex.norm_natCast] exact div_le_one_of_le₀ (by exact_mod_cast hm2.le) (by positivity) lemma sum_nonzero_multiples_dft_bound (n d : ℕ) [NeZero n] [NeZero d] (hn : 2 ≤ n) (hd_dvd : d ∣ n) (hd_pos : 0 < d) (mq : ℕ) (hmq1 : 1 ≤ mq) (hmq2 : mq < n) : ∑ l ∈ Finset.univ.filter (fun l : ZMod n => l ≠ 0 ∧ (d : ℕ) ∣ ZMod.val l), ‖normalizedDFT n (intervalIndicator n mq) l‖ ≤ (1 + Real.log (n : ℝ)) / d := by calc ∑ l ∈ Finset.univ.filter (fun l : ZMod n => l ≠ 0 ∧ (d : ℕ) ∣ ZMod.val l), ‖normalizedDFT n (intervalIndicator n mq) l‖ ≤ ∑ l ∈ Finset.univ.filter (fun l : ZMod n => l ≠ 0 ∧ (d : ℕ) ∣ ZMod.val l), (1 : ℝ) / (2 * min (ZMod.val l : ℝ) ((n : ℝ) - ZMod.val l)) := by apply Finset.sum_le_sum intro l hl simp only [Finset.mem_filter, Finset.mem_univ, true_and] at hl exact normalizedDFT_intervalIndicator_nonzero_bound n mq hmq1 hmq2 l hl.1 _ ≤ (1 + Real.log (n : ℝ)) / d := weight_sum_multiples_of_d_bound n d hn hd_dvd hd_pos lemma filter_int_dvd_subset_filter_nat_dvd (n d : ℕ) [NeZero n] [NeZero d] (hn : 2 ≤ n) (hd : d = largestPrimeFactor n ^ n.factorization (largestPrimeFactor n)) (q : ℤ) (hq_coprime : Int.gcd q (largestPrimeFactor n : ℤ) = 1) : Finset.univ.filter (fun l : ZMod n => l ≠ 0 ∧ ((d : ℤ) ∣ (↑(ZMod.val l) * q))) ⊆ Finset.univ.filter (fun l : ZMod n => l ≠ 0 ∧ (d : ℕ) ∣ ZMod.val l) := by apply Finset.monotone_filter_right intro l _ ⟨hl_ne, hdvd⟩ exact ⟨hl_ne, dvd_val_of_dvd_val_mul_q n d hn hd q hq_coprime l hl_ne hdvd⟩ lemma sum_int_dvd_le_sum_nat_dvd (n d : ℕ) [NeZero n] [NeZero d] (hn : 2 ≤ n) (hd : d = largestPrimeFactor n ^ n.factorization (largestPrimeFactor n)) (q : ℤ) (hq_coprime : Int.gcd q (largestPrimeFactor n : ℤ) = 1) (f g : ZMod n → ℝ) (hf_nonneg : ∀ l, 0 ≤ f l) (hg_nonneg : ∀ l, 0 ≤ g l) : (∑ l : ZMod n, if l ≠ 0 ∧ ((d : ℤ) ∣ (↑(ZMod.val l) * q)) then f l * g l else (0 : ℝ)) ≤ ∑ l ∈ Finset.univ.filter (fun l : ZMod n => l ≠ 0 ∧ (d : ℕ) ∣ ZMod.val l), f l * g l := by rw [← Finset.sum_filter] exact Finset.sum_le_sum_of_subset_of_nonneg (filter_int_dvd_subset_filter_nat_dvd n d hn hd q hq_coprime) (fun l _ _ => mul_nonneg (hf_nonneg l) (hg_nonneg l)) lemma sum_mul_le_sum_of_le_one (n : ℕ) [NeZero n] (c : ℝ) (hc : c ≤ 1) (hc_nonneg : 0 ≤ c) (g : ZMod n → ℝ) (hg_nonneg : ∀ l, 0 ≤ g l) (S : Finset (ZMod n)) : ∑ l ∈ S, c * g l ≤ ∑ l ∈ S, g l := by have h_pointwise : ∀ l ∈ S, c * g l ≤ g l := by intro l _; exact mul_le_of_le_one_left (hg_nonneg l) hc have h_sum : ∑ l ∈ S, c * g l ≤ ∑ l ∈ S, g l := by exact Finset.sum_le_sum h_pointwise exact h_sum lemma k_zero_contribution_bound (n d : ℕ) [NeZero n] [NeZero d] (hn : 2 ≤ n) (hd : d = largestPrimeFactor n ^ n.factorization (largestPrimeFactor n)) (p q : ℤ) (hp_pos : 1 ≤ p) (hq_pos : 1 ≤ q) (hpq : (p : ℝ) + (q : ℝ) < (n : ℝ) / 2) (hq_coprime : Int.gcd q (largestPrimeFactor n : ℤ) = 1) : let mp := (2 * p - 1).toNat let mq := (2 * q - 1).toNat (∑ l : ZMod n, if l ≠ 0 ∧ ((d : ℤ) ∣ (↑(ZMod.val l) * q)) then ‖normalizedDFT n (intervalIndicator n mp) (0 : ZMod n)‖ * ‖normalizedDFT n (intervalIndicator n mq) l‖ else (0 : ℝ)) ≤ (1 + Real.log ↑n) / ↑d := by set mp := (2 * p - 1).toNat set mq := (2 * q - 1).toNat have hmp := mp_valid n hn p q hp_pos hq_pos hpq have hmq := mq_valid n hn p q hp_pos hq_pos hpq have hd_dvd : d ∣ n := hd ▸ d_dvd_n n hn have hd_pos' : 0 < d := hd ▸ d_pos n hn have h_step1 : (∑ l : ZMod n, if l ≠ 0 ∧ ((d : ℤ) ∣ (↑(ZMod.val l) * q)) then ‖normalizedDFT n (intervalIndicator n mp) (0 : ZMod n)‖ * ‖normalizedDFT n (intervalIndicator n mq) l‖ else (0 : ℝ)) ≤ ∑ l ∈ Finset.univ.filter (fun l : ZMod n => l ≠ 0 ∧ (d : ℕ) ∣ ZMod.val l), ‖normalizedDFT n (intervalIndicator n mp) (0 : ZMod n)‖ * ‖normalizedDFT n (intervalIndicator n mq) l‖ := sum_int_dvd_le_sum_nat_dvd n d hn hd q hq_coprime _ _ (fun _ => norm_nonneg _) (fun _ => norm_nonneg _) have h_zero_le : ‖normalizedDFT n (intervalIndicator n mp) 0‖ ≤ 1 := norm_normalizedDFT_zero_le_one n mp hmp.1 hmp.2 have h_step2 : (∑ l ∈ Finset.univ.filter (fun l : ZMod n => l ≠ 0 ∧ (d : ℕ) ∣ ZMod.val l), ‖normalizedDFT n (intervalIndicator n mp) (0 : ZMod n)‖ * ‖normalizedDFT n (intervalIndicator n mq) l‖) ≤ ∑ l ∈ Finset.univ.filter (fun l : ZMod n => l ≠ 0 ∧ (d : ℕ) ∣ ZMod.val l), ‖normalizedDFT n (intervalIndicator n mq) l‖ := sum_mul_le_sum_of_le_one n _ h_zero_le (norm_nonneg _) _ (fun _ => norm_nonneg _) _ have h_step3 : ∑ l ∈ Finset.univ.filter (fun l : ZMod n => l ≠ 0 ∧ (d : ℕ) ∣ ZMod.val l), ‖normalizedDFT n (intervalIndicator n mq) l‖ ≤ (1 + Real.log ↑n) / ↑d := sum_nonzero_multiples_dft_bound n d hn hd_dvd hd_pos' mq hmq.1 hmq.2 linarith lemma dvd_diff_from_zmod_eq (d : ℕ) [NeZero d] (p : ℤ) (u_val : ℕ) (hu : (p : ZMod d) = (u_val : ZMod d)) (k_val l_val : ℕ) (q : ℤ) : ((d : ℤ) ∣ (↑k_val * p + ↑l_val * q - (↑k_val * ↑u_val + ↑l_val * q))) := by have h₁ : (d : ℤ) ∣ (p - (u_val : ℤ)) := by have h₂ : (p : ZMod d) = (u_val : ZMod d) := hu rw [← ZMod.intCast_zmod_eq_zero_iff_dvd] norm_num [ZMod.intCast_eq_intCast_iff_dvd_sub] at h₂ ⊢ <;> (try { norm_cast at h₂ ⊢ <;> simp_all [ZMod.intCast_eq_intCast_iff_dvd_sub] }) have h₂ : (d : ℤ) ∣ (↑k_val * (p - (u_val : ℤ))) := by exact dvd_mul_of_dvd_right h₁ _ have h₃ : (↑k_val * p + ↑l_val * q - (↑k_val * ↑u_val + ↑l_val * q)) = (↑k_val * (p - (u_val : ℤ))) := by ring_nf rw [h₃] exact h₂ lemma congr_dvd_equiv (d : ℕ) [NeZero d] (p : ℤ) (u_val : ℕ) (hu : (p : ZMod d) = (u_val : ZMod d)) (k_val l_val : ℕ) (q : ℤ) : ((d : ℤ) ∣ (↑k_val * p + ↑l_val * q)) ↔ ((d : ℤ) ∣ (↑k_val * ↑u_val + ↑l_val * q)) := by exact dvd_iff_dvd_of_dvd_sub (dvd_diff_from_zmod_eq d p u_val hu k_val l_val q) lemma summand_le (n d : ℕ) [NeZero n] [NeZero d] (hn : 2 ≤ n) (p q : ℤ) (hp_pos : 1 ≤ p) (hq_pos : 1 ≤ q) (hpq : (p : ℝ) + (q : ℝ) < (n : ℝ) / 2) (u_val : ℕ) (hu_congr : (p : ZMod d) = (u_val : ZMod d)) (k l : ZMod n) : let mp := (2 * p - 1).toNat let mq := (2 * q - 1).toNat (if k ≠ 0 ∧ ((d : ℤ) ∣ (↑(ZMod.val k) * p + ↑(ZMod.val l) * q)) then ‖normalizedDFT n (intervalIndicator n mp) k‖ * ‖normalizedDFT n (intervalIndicator n mq) l‖ else (0 : ℝ)) ≤ (if k ≠ 0 ∧ ((d : ℤ) ∣ (↑(ZMod.val k) * ↑u_val + ↑(ZMod.val l) * q)) then ‖normalizedDFT n (intervalIndicator n mq) l‖ / (2 * min (ZMod.val k : ℝ) ((n : ℝ) - ZMod.val k)) else 0) := by simp only have h_equiv : ((d : ℤ) ∣ (↑(ZMod.val k) * p + ↑(ZMod.val l) * q)) ↔ ((d : ℤ) ∣ (↑(ZMod.val k) * ↑u_val + ↑(ZMod.val l) * q)) := congr_dvd_equiv d p u_val hu_congr (ZMod.val k) (ZMod.val l) q by_cases hcond : k ≠ 0 ∧ ((d : ℤ) ∣ (↑(ZMod.val k) * p + ↑(ZMod.val l) * q)) · rw [if_pos hcond, if_pos ⟨hcond.1, h_equiv.mp hcond.2⟩] have hk := hcond.1 have hmp1 : 1 ≤ (2 * p - 1).toNat := mp_lower_bound p hp_pos have hmp2 : (2 * p - 1).toNat < n := mp_upper_bound n hn p q hp_pos hq_pos hpq have hbound := normalizedDFT_intervalIndicator_nonzero_bound n (2 * p - 1).toNat hmp1 hmp2 k hk have hnorm_nonneg : 0 ≤ ‖normalizedDFT n (intervalIndicator n (2 * q - 1).toNat) l‖ := norm_nonneg _ have hmin_pos : (0 : ℝ) < min (ZMod.val k : ℝ) ((n : ℝ) - ZMod.val k) := min_val_pos n k hk calc ‖normalizedDFT n (intervalIndicator n (2 * p - 1).toNat) k‖ * ‖normalizedDFT n (intervalIndicator n (2 * q - 1).toNat) l‖ ≤ (1 / (2 * min (ZMod.val k : ℝ) ((n : ℝ) - ZMod.val k))) * ‖normalizedDFT n (intervalIndicator n (2 * q - 1).toNat) l‖ := mul_le_mul_of_nonneg_right hbound hnorm_nonneg _ = ‖normalizedDFT n (intervalIndicator n (2 * q - 1).toNat) l‖ / (2 * min (ZMod.val k : ℝ) ((n : ℝ) - ZMod.val k)) := by rw [one_div, mul_comm] rfl · rw [if_neg hcond] by_cases hcond2 : k ≠ 0 ∧ ((d : ℤ) ∣ (↑(ZMod.val k) * ↑u_val + ↑(ZMod.val l) * q)) · exfalso apply hcond exact ⟨hcond2.1, h_equiv.mpr hcond2.2⟩ · rw [if_neg hcond2] lemma k_nonzero_contribution_bound (n d : ℕ) [NeZero n] [NeZero d] (hn : 2 ≤ n) (hd : d = largestPrimeFactor n ^ n.factorization (largestPrimeFactor n)) (p q : ℤ) (hp_pos : 1 ≤ p) (hq_pos : 1 ≤ q) (hpq : (p : ℝ) + (q : ℝ) < (n : ℝ) / 2) (u_val : ℕ) (hu_congr : (p : ZMod d) = (u_val : ZMod d)) : let mp := (2 * p - 1).toNat let mq := (2 * q - 1).toNat (∑ k : ZMod n, ∑ l : ZMod n, if k ≠ 0 ∧ ((d : ℤ) ∣ (↑(ZMod.val k) * p + ↑(ZMod.val l) * q)) then ‖normalizedDFT n (intervalIndicator n mp) k‖ * ‖normalizedDFT n (intervalIndicator n mq) l‖ else (0 : ℝ)) ≤ (∑ k : ZMod n, ∑ l : ZMod n, if k ≠ 0 ∧ ((d : ℤ) ∣ (↑(ZMod.val k) * ↑u_val + ↑(ZMod.val l) * q)) then ‖normalizedDFT n (intervalIndicator n mq) l‖ / (2 * min (ZMod.val k : ℝ) ((n : ℝ) - ZMod.val k)) else 0) := by apply Finset.sum_le_sum intro k _ apply Finset.sum_le_sum intro l _ exact summand_le n d hn p q hp_pos hq_pos hpq u_val hu_congr k l lemma combine_bounds_arithmetic (R : ℕ) (P d : ℕ) (hR : 1 ≤ R) (hP : 0 < P) (hd : 0 < d) (hdP : P ≤ d) (n_real : ℝ) (hn_log : 0 ≤ Real.log n_real) (S0 Sneq0 : ℝ) (hS0 : S0 ≤ (1 + Real.log n_real) / ↑d) (hSneq0 : Sneq0 ≤ 6 * ↑R * (1 + Real.log n_real) ^ 2 / ↑d) : S0 + Sneq0 ≤ 7 * ↑R * (1 + Real.log n_real) ^ 2 / (P : ℝ) := by have h₂ : (1 + Real.log n_real : ℝ) / ↑d + 6 * ↑R * (1 + Real.log n_real) ^ 2 / ↑d = ((1 + Real.log n_real) + 6 * ↑R * (1 + Real.log n_real) ^ 2) / ↑d := by field_simp [hd.ne'] have h₅ : ((1 + Real.log n_real : ℝ) + 6 * ↑R * (1 + Real.log n_real) ^ 2) / ↑d ≤ (7 * ↑R * (1 + Real.log n_real) ^ 2 : ℝ) / ↑d := by have h₅₁ : (1 + Real.log n_real : ℝ) ≤ ↑R * (1 + Real.log n_real) ^ 2 := by have h₅₂ : (1 : ℝ) ≤ ↑R := by exact_mod_cast hR nlinarith [sq_nonneg (1 + Real.log n_real - 1)] calc ((1 + Real.log n_real : ℝ) + 6 * ↑R * (1 + Real.log n_real) ^ 2) / ↑d ≤ (↑R * (1 + Real.log n_real) ^ 2 + 6 * ↑R * (1 + Real.log n_real) ^ 2 : ℝ) / ↑d := by gcongr _ = (7 * ↑R * (1 + Real.log n_real) ^ 2 : ℝ) / ↑d := by ring_nf have h₆ : (7 * ↑R * (1 + Real.log n_real) ^ 2 : ℝ) / ↑d ≤ (7 * ↑R * (1 + Real.log n_real) ^ 2 : ℝ) / (P : ℝ) := by have h₆₁ : (P : ℝ) ≤ (d : ℝ) := by exact_mod_cast hdP have h₆₂ : 0 < (P : ℝ) := by positivity have h₆₃ : 0 < (d : ℝ) := by positivity have h₆₅ : (1 : ℝ) / (d : ℝ) ≤ (1 : ℝ) / (P : ℝ) := by apply one_div_le_one_div_of_le · positivity · exact h₆₁ calc (7 * ↑R * (1 + Real.log n_real) ^ 2 : ℝ) / ↑d = (7 * ↑R * (1 + Real.log n_real) ^ 2 : ℝ) * (1 / (d : ℝ)) := by field_simp [h₆₃.ne'] _ ≤ (7 * ↑R * (1 + Real.log n_real) ^ 2 : ℝ) * (1 / (P : ℝ)) := by gcongr _ = (7 * ↑R * (1 + Real.log n_real) ^ 2 : ℝ) / (P : ℝ) := by field_simp [h₆₂.ne'] have h₇ : (S0 : ℝ) + Sneq0 ≤ (7 * ↑R * (1 + Real.log n_real) ^ 2 : ℝ) / (P : ℝ) := by calc (S0 : ℝ) + Sneq0 ≤ ((1 + Real.log n_real) + 6 * ↑R * (1 + Real.log n_real) ^ 2) / ↑d := by linarith _ ≤ (7 * ↑R * (1 + Real.log n_real) ^ 2 : ℝ) / ↑d := by linarith _ ≤ (7 * ↑R * (1 + Real.log n_real) ^ 2 : ℝ) / (P : ℝ) := by linarith exact h₇ lemma combine_k0_kneq0_bounds (n : ℕ) (hn : 2 ≤ n) (d : ℕ) [NeZero d] (hd : d = largestPrimeFactor n ^ n.factorization (largestPrimeFactor n)) : let P := largestPrimeFactor n let R := ⌈Real.log (n : ℝ)⌉₊ ∀ (S0 Sneq0 : ℝ), S0 ≤ (1 + Real.log ↑n) / ↑d → Sneq0 ≤ 6 * ↑R * (1 + Real.log ↑n) ^ 2 / ↑d → S0 + Sneq0 ≤ 7 * ↑R * (1 + Real.log ↑n) ^ 2 / (P : ℝ) := by intro P R S0 Sneq0 hS0 hSneq0 exact combine_bounds_arithmetic R P d (ceil_log_ge_one n hn) (largestPrimeFactor_pos n hn) (Nat.pos_of_ne_zero (NeZero.ne d)) (hd ▸ d_ge_P n hn) (↑n) (Real.log_nonneg (by exact_mod_cast Nat.one_le_of_lt (by omega : 1 < n))) S0 Sneq0 hS0 hSneq0 lemma good_p_double_sum_bound (n d : ℕ) [NeZero n] [NeZero d] (hn : 2 ≤ n) (hd : d = largestPrimeFactor n ^ n.factorization (largestPrimeFactor n)) (p q : ℤ) (hp_pos : 1 ≤ p) (hq_pos : 1 ≤ q) (hpq : (p : ℝ) + (q : ℝ) < (n : ℝ) / 2) (hq_coprime : Int.gcd q (largestPrimeFactor n : ℤ) = 1) (hp_coprime : ¬ ((largestPrimeFactor n : ℤ) ∣ p)) (u_val : ℕ) (hu_congr : (p : ZMod d) = (u_val : ZMod d)) : let P := largestPrimeFactor n let R := ⌈Real.log (n : ℝ)⌉₊ let mp := (2 * p - 1).toNat let mq := (2 * q - 1).toNat (∑ k : ZMod n, ∑ l : ZMod n, if k ≠ 0 ∧ ((d : ℤ) ∣ (↑(ZMod.val k) * ↑u_val + ↑(ZMod.val l) * q)) then ‖normalizedDFT n (intervalIndicator n mq) l‖ / (2 * min (ZMod.val k : ℝ) ((n : ℝ) - ZMod.val k)) else 0) ≤ 6 * ↑R * (1 + Real.log ↑n) ^ 2 / ↑d → (∑ k : ZMod n, ∑ l : ZMod n, if (k, l) ≠ (0, 0) ∧ ((d : ℤ)) ∣ (ZMod.val k * p + ZMod.val l * q) then ‖normalizedDFT n (intervalIndicator n mp) k‖ * ‖normalizedDFT n (intervalIndicator n mq) l‖ else (0 : ℝ)) ≤ 7 * ↑R * (1 + Real.log ↑n) ^ 2 / (P : ℝ) := by intro P R mp mq hS have _ := hp_coprime have hsplit := double_sum_split_k0_kneq0 n d mp mq p q rw [hsplit] have hk0 := k_zero_contribution_bound n d hn hd p q hp_pos hq_pos hpq hq_coprime have hkneq0 := k_nonzero_contribution_bound n d hn hd p q hp_pos hq_pos hpq u_val hu_congr have hkneq0_final : (∑ k : ZMod n, ∑ l : ZMod n, if k ≠ 0 ∧ ((d : ℤ) ∣ (↑(ZMod.val k) * p + ↑(ZMod.val l) * q)) then ‖normalizedDFT n (intervalIndicator n mp) k‖ * ‖normalizedDFT n (intervalIndicator n mq) l‖ else (0 : ℝ)) ≤ 6 * ↑R * (1 + Real.log ↑n) ^ 2 / ↑d := le_trans hkneq0 hS exact combine_k0_kneq0_bounds n hn d hd _ _ hk0 hkneq0_final lemma int_not_dvd_imp_nat_not_dvd (P : ℕ) (p : ℤ) (hp_pos : 1 ≤ p) (hp_not_dvd : ¬ ((P : ℤ) ∣ p)) : ¬ P ∣ p.natAbs := by intro h have h₁ : (P : ℤ) ∣ p := by have h₂ : (P : ℕ) ∣ p.natAbs := h have h₃ : (P : ℤ) ∣ p := by rw [Int.natCast_dvd] exact h₂ exact h₃ exact hp_not_dvd h₁ lemma natAbs_mod_eq_emod_toNat (d : ℕ) (d_pos : 0 < d) (p : ℤ) (hp_pos : 1 ≤ p) : p.natAbs % d = (p % (d : ℤ)).toNat := by have hp_nn : 0 ≤ p := by omega have h₁ : p.natAbs = p.toNat := by omega rw [h₁, Int.toNat_emod hp_nn (by omega : (0 : ℤ) ≤ ↑d)] simp lemma intCast_eq_natCast_of_pos (d : ℕ) [NeZero d] (p : ℤ) (hp_pos : 1 ≤ p) : (p : ZMod d) = (p.natAbs : ZMod d) := by have h_p_nonneg : 0 ≤ (p : ℤ) := by nlinarith have h_toNat_eq_natAbs : p.toNat = p.natAbs := by grind have h_int_cast_eq_toNat_cast : (p : ZMod d) = (p.toNat : ZMod d) := by exact Eq.symm (ZMod.natCast_toNat d h_p_nonneg) have h_main : (p : ZMod d) = (p.natAbs : ZMod d) := by simp_all assumption lemma p_mod_d_unit (n d : ℕ) [NeZero d] (hn : 2 ≤ n) (hd : d = largestPrimeFactor n ^ n.factorization (largestPrimeFactor n)) (p : ℤ) (hp_pos : 1 ≤ p) (hp_coprime : ¬ ((largestPrimeFactor n : ℤ) ∣ p)) : ∃ u : (ZMod d)ˣ, (u : ZMod d).val = (p % (d : ℕ)).toNat ∧ (p : ZMod d) = (u : ZMod d) := by have hP_prime : Nat.Prime (largestPrimeFactor n) := largest_prime_factor_prime n hn have hp_not_dvd_nat : ¬ largestPrimeFactor n ∣ p.natAbs := int_not_dvd_imp_nat_not_dvd (largestPrimeFactor n) p hp_pos hp_coprime have hp_natAbs_coprime_d : p.natAbs.Coprime d := by rw [hd] exact Nat.Prime.coprime_pow_of_not_dvd hP_prime hp_not_dvd_nat exact ⟨ZMod.unitOfCoprime p.natAbs hp_natAbs_coprime_d, by rw [val_unitOfCoprime_eq_mod] exact natAbs_mod_eq_emod_toNat d (NeZero.pos d) p hp_pos, by rw [ZMod.coe_unitOfCoprime, intCast_eq_natCast_of_pos d p hp_pos]⟩ lemma double_sum_bad_set_construction (n : ℕ) [NeZero n] (hn : 2 ≤ n) (q : ℤ) (hq_coprime : Int.gcd q (largestPrimeFactor n : ℤ) = 1) (hq_pos : 1 ≤ q) (hq_bound : (q : ℝ) < (n : ℝ) / 2) : let P := largestPrimeFactor n let d := P ^ n.factorization P let R := ⌈Real.log (n : ℝ)⌉₊ ∃ B : Finset ℕ, B.card ≤ d / R ∧ ∀ p : ℤ, ¬ ((P : ℤ) ∣ p) → 1 ≤ p → (p : ℝ) + (q : ℝ) < (n : ℝ) / 2 → (p % (d : ℕ)).toNat ∉ B → (∑ k : ZMod n, ∑ l : ZMod n, if (k, l) ≠ (0, 0) ∧ ((largestPrimeFactor n ^ n.factorization (largestPrimeFactor n) : ℤ)) ∣ (ZMod.val k * p + ZMod.val l * q) then ‖normalizedDFT n (intervalIndicator n (2 * p - 1).toNat) k‖ * ‖normalizedDFT n (intervalIndicator n (2 * q - 1).toNat) l‖ else (0 : ℝ)) ≤ 7 * R * (1 + Real.log (n : ℝ)) ^ 2 / (P : ℝ) := by intro P d R haveI hd_pos : NeZero d := ⟨by positivity [d_pos n hn]⟩ have havg := average_S_bound n d hn rfl q hq_coprime hq_pos hq_bound ((2 * q - 1).toNat) rfl have hS_nonneg : ∀ u : (ZMod d)ˣ, 0 ≤ (∑ k : ZMod n, ∑ l : ZMod n, if k ≠ 0 ∧ ((d : ℤ) ∣ (↑(ZMod.val k) * ↑(u : ZMod d).val + ↑(ZMod.val l) * q)) then ‖normalizedDFT n (intervalIndicator n (2 * q - 1).toNat) l‖ / (2 * min (ZMod.val k : ℝ) ((n : ℝ) - ZMod.val k)) else 0) := by intro u; apply Finset.sum_nonneg; intro k _; apply Finset.sum_nonneg; intro l _ split_ifs with h · apply div_nonneg (norm_nonneg _) apply mul_nonneg (by norm_num : (0 : ℝ) ≤ 2) exact le_min (Nat.cast_nonneg _) (sub_nonneg.mpr (by exact_mod_cast (ZMod.val_lt k).le)) · exact le_refl _ have havg_nonneg : (0 : ℝ) ≤ 6 * (1 + Real.log ↑n) ^ 2 / ↑d := by apply div_nonneg · apply mul_nonneg (by norm_num : (0 : ℝ) ≤ 6) (sq_nonneg _) · exact Nat.cast_nonneg _ obtain ⟨B, hBcard, hBbound⟩ := bad_set_from_average d (fun u => ∑ k : ZMod n, ∑ l : ZMod n, if k ≠ 0 ∧ ((d : ℤ) ∣ (↑(ZMod.val k) * ↑(u : ZMod d).val + ↑(ZMod.val l) * q)) then ‖normalizedDFT n (intervalIndicator n (2 * q - 1).toNat) l‖ / (2 * min (ZMod.val k : ℝ) ((n : ℝ) - ZMod.val k)) else 0) hS_nonneg (6 * (1 + Real.log ↑n) ^ 2 / ↑d) havg_nonneg havg R (ceil_log_ge_one n hn) exact ⟨B, hBcard, fun p hp_cop hp_pos hpq hp_not_in_B => by obtain ⟨u, hu_val, hu_eq⟩ := p_mod_d_unit n d hn rfl p hp_pos hp_cop have hS_bound := hBbound u (hu_val ▸ hp_not_in_B) have hS_bound' : (∑ k : ZMod n, ∑ l : ZMod n, if k ≠ 0 ∧ ((d : ℤ) ∣ (↑(ZMod.val k) * ↑(u : ZMod d).val + ↑(ZMod.val l) * q)) then ‖normalizedDFT n (intervalIndicator n (2 * q - 1).toNat) l‖ / (2 * min (ZMod.val k : ℝ) ((n : ℝ) - ZMod.val k)) else 0) ≤ 6 * ↑R * (1 + Real.log ↑n) ^ 2 / ↑d := by calc _ ≤ ↑R * (6 * (1 + Real.log ↑n) ^ 2 / ↑d) := hS_bound _ = 6 * ↑R * (1 + Real.log ↑n) ^ 2 / ↑d := by ring have hu_congr : (p : ZMod d) = ((u : ZMod d).val : ZMod d) := by rw [ZMod.natCast_zmod_val]; exact hu_eq exact good_p_double_sum_bound n d hn rfl p q hp_pos hq_pos hpq hq_coprime hp_cop (u : ZMod d).val hu_congr hS_bound'⟩ lemma error_EPalpha_markov (n : ℕ) (hn : 2 ≤ n) (q : ℤ) (hq_coprime : Int.gcd q (largestPrimeFactor n : ℤ) = 1) (hq_pos : 1 ≤ q) (hq_bound : (q : ℝ) < (n : ℝ) / 2) : haveI : NeZero n := ⟨by omega⟩ let P := largestPrimeFactor n let d := P ^ n.factorization P let R := ⌈Real.log (n : ℝ)⌉₊ ∃ B : Finset ℕ, B.card ≤ d / R ∧ ∀ p : ℤ, ¬ ((P : ℤ) ∣ p) → 1 ≤ p → (p : ℝ) + (q : ℝ) < (n : ℝ) / 2 → (p % (d : ℕ)).toNat ∉ B → |(errorTermEPalpha n p q).re| ≤ 7 * R * (Nat.totient n : ℝ) * (1 + Real.log (n : ℝ)) ^ 2 / (P : ℝ) := by haveI : NeZero n := ⟨by omega⟩ obtain ⟨B, hB_card, hB_good⟩ := double_sum_bad_set_construction n hn q hq_coprime hq_pos hq_bound refine ⟨B, hB_card, fun p hp_coprime hp_pos hp_bound hp_notinB => ?_⟩ have h_ds := hB_good p hp_coprime hp_pos hp_bound hp_notinB have h_norm := errorTermEPalpha_norm_le_totient_mul n p q calc |(errorTermEPalpha n p q).re| ≤ ‖errorTermEPalpha n p q‖ := Complex.abs_re_le_norm _ _ ≤ (Nat.totient n : ℝ) * (∑ k : ZMod n, ∑ l : ZMod n, if (k, l) ≠ (0, 0) ∧ ((largestPrimeFactor n ^ n.factorization (largestPrimeFactor n) : ℤ)) ∣ (ZMod.val k * p + ZMod.val l * q) then ‖normalizedDFT n (intervalIndicator n (2 * p - 1).toNat) k‖ * ‖normalizedDFT n (intervalIndicator n (2 * q - 1).toNat) l‖ else 0) := h_norm _ ≤ (Nat.totient n : ℝ) * (7 * ⌈Real.log (n : ℝ)⌉₊ * (1 + Real.log (n : ℝ)) ^ 2 / (largestPrimeFactor n : ℝ)) := by apply mul_le_mul_of_nonneg_left h_ds exact Nat.cast_nonneg _ _ = 7 * ⌈Real.log (n : ℝ)⌉₊ * (Nat.totient n : ℝ) * (1 + Real.log (n : ℝ)) ^ 2 / (largestPrimeFactor n : ℝ) := by ring lemma error_split_bound (n : ℕ) (hn : 2 ≤ n) (q : ℤ) (hq_coprime : Int.gcd q (largestPrimeFactor n : ℤ) = 1) (hq_pos : 1 ≤ q) (hq_bound : (q : ℝ) < (n : ℝ) / 2) : ∃ B : Finset ℕ, B.card ≤ largestPrimeFactor n ^ n.factorization (largestPrimeFactor n) / ⌈Real.log (n : ℝ)⌉₊ ∧ ∀ p : ℤ, ¬ ((largestPrimeFactor n : ℤ) ∣ p) → 1 ≤ p → (p : ℝ) + (q : ℝ) < (n : ℝ) / 2 → (p % (largestPrimeFactor n ^ n.factorization (largestPrimeFactor n) : ℕ)).toNat ∉ B → |(countingFunctionS n p q : ℝ) - ((2 * p - 1).toNat : ℝ) * ((2 * q - 1).toNat : ℝ) * (Nat.totient n : ℝ) / (n : ℝ) ^ 2| ≤ (Nat.totient n : ℝ) * (1 + Real.log (n : ℝ)) ^ 2 / ((largestPrimeFactor n : ℝ) - 1) + 7 * ⌈Real.log (n : ℝ)⌉₊ * (Nat.totient n : ℝ) * (1 + Real.log (n : ℝ)) ^ 2 / (largestPrimeFactor n : ℝ) := by haveI : NeZero n := ⟨by omega⟩ obtain ⟨B, hB_card, hB_bound⟩ := error_EPalpha_markov n hn q hq_coprime hq_pos hq_bound refine ⟨B, hB_card, fun p hp_ndvd hp_pos hp_sum hp_notbad => ?_⟩ have h_decomp := error_decomposition n hn p q hp_pos hq_pos hp_sum have h_EP0 := error_EP0_universal_bound n hn p q hp_pos hq_pos hp_sum have h_EPalpha := hB_bound p hp_ndvd hp_pos hp_sum hp_notbad rw [h_decomp] calc |(@errorTermEP0 n ⟨by omega⟩ p q).re + (@errorTermEPalpha n ⟨by omega⟩ p q).re| ≤ |(@errorTermEP0 n ⟨by omega⟩ p q).re| + |(@errorTermEPalpha n ⟨by omega⟩ p q).re| := abs_add_le _ _ _ ≤ (Nat.totient n : ℝ) * (1 + Real.log (n : ℝ)) ^ 2 / ((largestPrimeFactor n : ℝ) - 1) + 7 * ⌈Real.log (n : ℝ)⌉₊ * (Nat.totient n : ℝ) * (1 + Real.log (n : ℝ)) ^ 2 / (largestPrimeFactor n : ℝ) := add_le_add h_EP0 h_EPalpha lemma combine_error_P0_Palpha (n : ℕ) (hn : 2 ≤ n) : (Nat.totient n : ℝ) * (1 + Real.log (n : ℝ)) ^ 2 / ((largestPrimeFactor n : ℝ) - 1) + 7 * ⌈Real.log (n : ℝ)⌉₊ * (Nat.totient n : ℝ) * (1 + Real.log (n : ℝ)) ^ 2 / (largestPrimeFactor n : ℝ) ≤ 9 * ⌈Real.log (n : ℝ)⌉₊ * (Nat.totient n : ℝ) * (1 + Real.log (n : ℝ)) ^ 2 / (largestPrimeFactor n : ℝ) := by have hP_ge : 2 ≤ largestPrimeFactor n := largestPrimeFactor_ge_two n hn have hR_ge : 1 ≤ ⌈Real.log (n : ℝ)⌉₊ := ceil_log_ge_one n hn have hP_real : (2 : ℝ) ≤ (largestPrimeFactor n : ℝ) := by exact_mod_cast hP_ge have hR_real : (1 : ℝ) ≤ (⌈Real.log (n : ℝ)⌉₊ : ℝ) := by exact_mod_cast hR_ge have hA : (0 : ℝ) ≤ (Nat.totient n : ℝ) * (1 + Real.log (n : ℝ)) ^ 2 := by apply mul_nonneg · exact Nat.cast_nonneg _ · positivity have key := combine_error_terms_real (largestPrimeFactor n : ℝ) (⌈Real.log (n : ℝ)⌉₊ : ℝ) ((Nat.totient n : ℝ) * (1 + Real.log (n : ℝ)) ^ 2) hP_real hR_real hA ring_nf at key ⊢ linarith lemma fourier_markov_bad_set (n : ℕ) (hn : 2 ≤ n) (q : ℤ) (hq_coprime : Int.gcd q (largestPrimeFactor n : ℤ) = 1) (hq_pos : 1 ≤ q) (hq_bound : (q : ℝ) < (n : ℝ) / 2) : ∃ B : Finset ℕ, B.card ≤ largestPrimeFactor n ^ n.factorization (largestPrimeFactor n) / ⌈Real.log (n : ℝ)⌉₊ ∧ ∀ p : ℤ, ¬ ((largestPrimeFactor n : ℤ) ∣ p) → 1 ≤ p → (p : ℝ) + (q : ℝ) < (n : ℝ) / 2 → (p % (largestPrimeFactor n ^ n.factorization (largestPrimeFactor n) : ℕ)).toNat ∉ B → |(countingFunctionS n p q : ℝ) - (2 * ↑p - 1) * (2 * ↑q - 1) * (Nat.totient n : ℝ) / (n : ℝ) ^ 2| ≤ 9 * ⌈Real.log (n : ℝ)⌉₊ * (Nat.totient n : ℝ) * (1 + Real.log (n : ℝ)) ^ 2 / (largestPrimeFactor n : ℝ) := by obtain ⟨B, hB_card, hB_bound⟩ := error_split_bound n hn q hq_coprime hq_pos hq_bound exact ⟨B, hB_card, fun p hp_coprime hp_pos hp_bound hp_not_in_B => by have h := hB_bound p hp_coprime hp_pos hp_bound hp_not_in_B rw [toNat_two_mul_sub_one p hp_pos, toNat_two_mul_sub_one q hq_pos] at h exact le_trans h (combine_error_P0_Palpha n hn)⟩ lemma ceil_log_mul_sq_le_cube' (n : ℕ) (hn : 2 ≤ n) : 9 * ⌈Real.log (n : ℝ)⌉₊ * (1 + Real.log (n : ℝ)) ^ 2 ≤ 9 * (1 + Real.log (n : ℝ)) ^ 3 := by have h₁ : (⌈Real.log (n : ℝ)⌉₊ : ℝ) ≤ 1 + Real.log (n : ℝ) := by have h₂ : (⌈Real.log (n : ℝ)⌉₊ : ℝ) < Real.log (n : ℝ) + 1 := by exact_mod_cast Nat.ceil_lt_add_one (by have h₃ : 0 ≤ Real.log (n : ℝ) := by apply Real.log_nonneg norm_cast <;> (try linarith) linarith) linarith have h₅ : 9 * ⌈Real.log (n : ℝ)⌉₊ * (1 + Real.log (n : ℝ)) ^ 2 ≤ 9 * (1 + Real.log (n : ℝ)) ^ 3 := by have h₆ : (⌈Real.log (n : ℝ)⌉₊ : ℝ) * (1 + Real.log (n : ℝ)) ^ 2 ≤ (1 + Real.log (n : ℝ)) ^ 3 := by nlinarith [sq_nonneg (1 + Real.log (n : ℝ)), sq_nonneg (Real.log (n : ℝ))] calc 9 * ⌈Real.log (n : ℝ)⌉₊ * (1 + Real.log (n : ℝ)) ^ 2 = 9 * ((⌈Real.log (n : ℝ)⌉₊ : ℝ) * (1 + Real.log (n : ℝ)) ^ 2) := by simp [mul_assoc] _ ≤ 9 * ((1 + Real.log (n : ℝ)) ^ 3) := by gcongr _ = 9 * (1 + Real.log (n : ℝ)) ^ 3 := by ring exact h₅ lemma log_cube_div_P_le_div_rpow' (θ : ℝ) (hθ_pos : 0 < θ) (n : ℕ) (hn : 2 ≤ n) (hP : (largestPrimeFactor n : ℝ) ≥ (n : ℝ) ^ θ) : 9 * (1 + Real.log (n : ℝ)) ^ 3 / (largestPrimeFactor n : ℝ) ≤ 9 * (1 + Real.log (n : ℝ)) ^ 3 / (n : ℝ) ^ θ := by have h_cube_pos : (1 + Real.log (n : ℝ)) ^ 3 > 0 := by have h₂ : (1 + Real.log (n : ℝ)) ^ 3 > 0 := by positivity exact h₂ have h_main : 9 * (1 + Real.log (n : ℝ)) ^ 3 / (largestPrimeFactor n : ℝ) ≤ 9 * (1 + Real.log (n : ℝ)) ^ 3 / (n : ℝ) ^ θ := by have h₁ : (n : ℝ) ^ θ ≤ (largestPrimeFactor n : ℝ) := by linarith have h₄ : 9 * (1 + Real.log (n : ℝ)) ^ 3 / (largestPrimeFactor n : ℝ) ≤ 9 * (1 + Real.log (n : ℝ)) ^ 3 / (n : ℝ) ^ θ := by have h₅ : (n : ℝ) ^ θ ≤ (largestPrimeFactor n : ℝ) := h₁ calc 9 * (1 + Real.log (n : ℝ)) ^ 3 / (largestPrimeFactor n : ℝ) ≤ 9 * (1 + Real.log (n : ℝ)) ^ 3 / (n : ℝ) ^ θ := by apply div_le_div_of_nonneg_left _ (by positivity) h₅ <;> linarith _ = 9 * (1 + Real.log (n : ℝ)) ^ 3 / (n : ℝ) ^ θ := by rfl exact h₄ exact h_main lemma nine_hundredths_lt_tenth' (η : ℝ) (hη_pos : 0 < η) : 9 * (η ^ 2 / 100) < η ^ 2 / 10 := by have h₁ : 0 < η ^ 2 := pow_pos hη_pos 2 have h₂ : 9 * (η ^ 2 / 100) = (9 / 100 : ℝ) * η ^ 2 := by ring have h₃ : η ^ 2 / 10 = (1 / 10 : ℝ) * η ^ 2 := by ring rw [h₂, h₃] have h₄ : (9 / 100 : ℝ) * η ^ 2 < (1 / 10 : ℝ) * η ^ 2 := by nlinarith exact h₄ theorem fourier_without_totient' (η θ : ℝ) (hη_pos : 0 < η) (hθ_pos : 0 < θ) (n : ℕ) (hn : 2 ≤ n) (hP : (largestPrimeFactor n : ℝ) ≥ (n : ℝ) ^ θ) (h_small : (1 + Real.log (n : ℝ)) ^ 3 / (n : ℝ) ^ θ < η ^ 2 / 100) : 9 * ⌈Real.log (n : ℝ)⌉₊ * (1 + Real.log (n : ℝ)) ^ 2 / (largestPrimeFactor n : ℝ) < η ^ 2 / 10 := by have hP_pos : (0 : ℝ) < (largestPrimeFactor n : ℝ) := by exact_mod_cast largestPrimeFactor_pos n hn have h1 : 9 * ↑⌈Real.log (n : ℝ)⌉₊ * (1 + Real.log (n : ℝ)) ^ 2 / (largestPrimeFactor n : ℝ) ≤ 9 * (1 + Real.log (n : ℝ)) ^ 3 / (largestPrimeFactor n : ℝ) := by apply div_le_div_of_nonneg_right (ceil_log_mul_sq_le_cube' n hn) (le_of_lt hP_pos) have h2 : 9 * (1 + Real.log (n : ℝ)) ^ 3 / (largestPrimeFactor n : ℝ) ≤ 9 * (1 + Real.log (n : ℝ)) ^ 3 / (n : ℝ) ^ θ := log_cube_div_P_le_div_rpow' θ hθ_pos n hn hP have h3 : 9 * (1 + Real.log (n : ℝ)) ^ 3 / (n : ℝ) ^ θ < 9 * (η ^ 2 / 100) := by rw [mul_div_assoc] exact mul_lt_mul_of_pos_left h_small (by positivity) have h4 : 9 * (η ^ 2 / 100) < η ^ 2 / 10 := nine_hundredths_lt_tenth' η hη_pos linarith lemma fourier_bound_lt_target (η θ : ℝ) (hη_pos : 0 < η) (hθ_pos : 0 < θ) (n : ℕ) (hn : 2 ≤ n) (hP : (largestPrimeFactor n : ℝ) ≥ (n : ℝ) ^ θ) (h_small : (1 + Real.log (n : ℝ)) ^ 3 / (n : ℝ) ^ θ < η ^ 2 / 100) : 9 * ⌈Real.log (n : ℝ)⌉₊ * (Nat.totient n : ℝ) * (1 + Real.log (n : ℝ)) ^ 2 / (largestPrimeFactor n : ℝ) < η ^ 2 / 10 * (Nat.totient n : ℝ) := by have phi_pos : (0 : ℝ) < (Nat.totient n : ℝ) := by exact_mod_cast Nat.totient_pos.mpr (by omega : 0 < n) have key := fourier_without_totient' η θ hη_pos hθ_pos n hn hP h_small calc 9 * ⌈Real.log (n : ℝ)⌉₊ * (Nat.totient n : ℝ) * (1 + Real.log (n : ℝ)) ^ 2 / (largestPrimeFactor n : ℝ) = (9 * ⌈Real.log (n : ℝ)⌉₊ * (1 + Real.log (n : ℝ)) ^ 2 / (largestPrimeFactor n : ℝ)) * (Nat.totient n : ℝ) := by ring _ < (η ^ 2 / 10) * (Nat.totient n : ℝ) := mul_lt_mul_of_pos_right key phi_pos lemma region_implies_bounds (n : ℕ) (η : ℝ) (hη_pos : 0 < η) (hn : 2 ≤ n) (p q : ℤ) (hpq : (p, q) ∈ truncatedObtuseRegion n η) : 1 ≤ p ∧ 1 ≤ q ∧ (p : ℝ) + (q : ℝ) < (n : ℝ) / 2 ∧ (q : ℝ) < (n : ℝ) / 2 := by have h₁ : (η : ℝ) * n ≤ (p : ℝ) := by simp only [truncatedObtuseRegion, Set.mem_setOf_eq, Prod.mk.injEq] at hpq exact hpq.1 have h₂ : (η : ℝ) * n ≤ (q : ℝ) := by simp only [truncatedObtuseRegion, Set.mem_setOf_eq, Prod.mk.injEq] at hpq exact hpq.2.1 have h₃ : (p : ℝ) + (q : ℝ) < (n : ℝ) / 2 := by simp only [truncatedObtuseRegion, Set.mem_setOf_eq, Prod.mk.injEq] at hpq exact hpq.2.2.1 have hηn_pos : 0 < (η : ℝ) * n := by positivity have hp_pos : 1 ≤ p := by by_contra h have h₅ : p ≤ 0 := by linarith have h₆ : (p : ℝ) ≤ 0 := by exact_mod_cast h₅ linarith have hq_pos : 1 ≤ q := by by_contra h have h₅ : q ≤ 0 := by linarith have h₆ : (q : ℝ) ≤ 0 := by exact_mod_cast h₅ linarith have hq_bound : (q : ℝ) < (n : ℝ) / 2 := by linarith exact ⟨hp_pos, hq_pos, h₃, hq_bound⟩ lemma error_bound_with_bad_set (η : ℝ) (θ : ℝ) (hη_pos : 0 < η) (hη_lt : η < 1 / 6) (hθ_pos : 0 < θ) (hθ_lt : θ < 1) (n : ℕ) (hn : 2 ≤ n) (hP : (largestPrimeFactor n : ℝ) ≥ (n : ℝ) ^ θ) (h_small : (1 + Real.log (n : ℝ)) ^ 3 / (n : ℝ) ^ θ < η ^ 2 / 100) (q : ℤ) (hq_coprime : Int.gcd q (largestPrimeFactor n : ℤ) = 1) : ∃ B : Finset ℕ, B.card ≤ largestPrimeFactor n ^ n.factorization (largestPrimeFactor n) / ⌈Real.log (n : ℝ)⌉₊ ∧ ∀ p : ℤ, ¬ ((largestPrimeFactor n : ℤ) ∣ p) → (p, q) ∈ truncatedObtuseRegion n η → (p % (largestPrimeFactor n ^ n.factorization (largestPrimeFactor n) : ℕ)).toNat ∉ B → |(countingFunctionS n p q : ℝ) - (2 * ↑p - 1) * (2 * ↑q - 1) * (Nat.totient n : ℝ) / (n : ℝ) ^ 2| < η ^ 2 / 10 * (Nat.totient n : ℝ) := by by_cases hq : 1 ≤ q ∧ (q : ℝ) < (n : ℝ) / 2 · obtain ⟨hq_pos, hq_bound⟩ := hq obtain ⟨B, hB_card, hB_bound⟩ := fourier_markov_bad_set n hn q hq_coprime hq_pos hq_bound exact ⟨B, hB_card, fun p hp_coprime hpq hp_good => lt_of_le_of_lt (hB_bound p hp_coprime (region_implies_bounds n η hη_pos hn p q hpq).1 (region_implies_bounds n η hη_pos hn p q hpq).2.2.1 hp_good) (fourier_bound_lt_target η θ hη_pos hθ_pos n hn hP h_small)⟩ · push_neg at hq exact ⟨∅, by simp, fun p _ hpq _ => by exfalso have hbds := region_implies_bounds n η hη_pos hn p q hpq exact not_lt.mpr (hq hbds.2.1) hbds.2.2.2⟩ lemma combine_main_and_error (η : ℝ) (hη_pos : 0 < η) (n : ℕ) (S_val : ℝ) (M_val : ℝ) (hM : η ^ 2 * (Nat.totient n : ℝ) ≤ M_val) (hE : |S_val - M_val| < η ^ 2 / 10 * (Nat.totient n : ℝ)) : η ^ 2 / 2 * (Nat.totient n : ℝ) ≤ S_val := by have h4 : (η ^ 2 : ℝ) * (Nat.totient n : ℝ) ≥ 0 := by positivity have h6 : S_val ≥ M_val - |S_val - M_val| := by cases' abs_cases (S_val - M_val) with h6 h6 <;> linarith have h7 : S_val ≥ η ^ 2 * (Nat.totient n : ℝ) - η ^ 2 / 10 * (Nat.totient n : ℝ) := by linarith [h6, hE, hM] have h8 : η ^ 2 * (Nat.totient n : ℝ) - η ^ 2 / 10 * (Nat.totient n : ℝ) = (9 : ℝ) / 10 * η ^ 2 * (Nat.totient n : ℝ) := by ring_nf rw [h8] at h7 linarith lemma fourier_markov_residue_bound (η : ℝ) (θ : ℝ) (hη_pos : 0 < η) (hη_lt : η < 1 / 6) (hθ_pos : 0 < θ) (hθ_lt : θ < 1) (n : ℕ) (hn : 2 ≤ n) (hP : (largestPrimeFactor n : ℝ) ≥ (n : ℝ) ^ θ) (h_small : (1 + Real.log (n : ℝ)) ^ 3 / (n : ℝ) ^ θ < η ^ 2 / 100) (q : ℤ) (hq_coprime : Int.gcd q (largestPrimeFactor n : ℤ) = 1) : ∃ B : Finset ℕ, B.card ≤ largestPrimeFactor n ^ n.factorization (largestPrimeFactor n) / ⌈Real.log (n : ℝ)⌉₊ ∧ ∀ p : ℤ, ¬ ((largestPrimeFactor n : ℤ) ∣ p) → (p, q) ∈ truncatedObtuseRegion n η → (p % (largestPrimeFactor n ^ n.factorization (largestPrimeFactor n) : ℕ)).toNat ∉ B → (η ^ 2 / 2 : ℝ) * (Nat.totient n : ℝ) ≤ (countingFunctionS n p q : ℝ) := by obtain ⟨B, hB_card, hB_error⟩ := error_bound_with_bad_set η θ hη_pos hη_lt hθ_pos hθ_lt n hn hP h_small q hq_coprime exact ⟨B, hB_card, fun p hp_coprime hpq hp_notinB => by have hE := hB_error p hp_coprime hpq hp_notinB have hM := main_term_lower_bound η hη_pos n hn p q hpq exact combine_main_and_error η hη_pos n (countingFunctionS n p q : ℝ) ((2 * ↑p - 1) * (2 * ↑q - 1) * (Nat.totient n : ℝ) / (n : ℝ) ^ 2) hM hE⟩ lemma bad_residues_bound (η : ℝ) (θ : ℝ) (hη_pos : 0 < η) (hη_lt : η < 1 / 6) (hθ_pos : 0 < θ) (hθ_lt : θ < 1) (n : ℕ) (hn : 2 ≤ n) (hP : (largestPrimeFactor n : ℝ) ≥ (n : ℝ) ^ θ) (h_small : (1 + Real.log (n : ℝ)) ^ 3 / (n : ℝ) ^ θ < η ^ 2 / 100) (q : ℤ) (hq_coprime : Int.gcd q (largestPrimeFactor n : ℤ) = 1) : ∃ B : Finset ℕ, B.card ≤ largestPrimeFactor n ^ n.factorization (largestPrimeFactor n) / ⌈Real.log (n : ℝ)⌉₊ ∧ ∀ p : ℤ, (p, q) ∈ residueBadPairs n η → (p % (largestPrimeFactor n ^ n.factorization (largestPrimeFactor n) : ℕ)).toNat ∈ B := by obtain ⟨B, hB_card, hB_good⟩ := fourier_markov_residue_bound η θ hη_pos hη_lt hθ_pos hθ_lt n hn hP h_small q hq_coprime exact ⟨B, hB_card, fun p hp => by by_contra hp_not_mem have hp_mem : (p, q) ∈ badPairsE n η := hp.1 have hp_not_dvd : ¬ ((largestPrimeFactor n : ℤ) ∣ p) := hp.2 have hp_tor : (p, q) ∈ truncatedObtuseRegion n η := hp_mem.1 have hS_large := hB_good p hp_not_dvd hp_tor hp_not_mem exact counting_large_implies_not_badPairsE n η p q hS_large hp_mem⟩ lemma residue_class_fiber_ncard_le (n d : ℕ) (hd_pos : 0 < d) (b : ℕ) (S : Set ℤ) (hS_sub : S ⊆ Set.Ico (0 : ℤ) (↑n / 2)) (hS_fin : S.Finite) : {x ∈ S | (x % (d : ℤ)).toNat = b}.ncard ≤ n / (2 * d) + 1 := by calc {x ∈ S | (x % (d : ℤ)).toNat = b}.ncard ≤ (↑(Finset.range (n / (2 * d) + 1)) : Set ℕ).ncard := by apply Set.ncard_le_ncard_of_injOn (fun x : ℤ => (x / (d : ℤ)).toNat) · intro x hx simp only [Finset.mem_coe] exact fiber_div_mem_range n d hd_pos b S hS_sub x hx · exact fiber_div_injOn n d hd_pos b S hS_sub _ = (Finset.range (n / (2 * d) + 1)).card := Set.ncard_coe_finset _ _ = n / (2 * d) + 1 := Finset.card_range _ lemma subset_biUnion_residue_fibers (d : ℕ) (B : Finset ℕ) (S : Set ℤ) (hS_res : ∀ x ∈ S, (x % (d : ℤ)).toNat ∈ B) : S ⊆ ⋃ b ∈ B, {x ∈ S | (x % (d : ℤ)).toNat = b} := by have h_main : ∀ (x : ℤ), x ∈ S → x ∈ ⋃ b ∈ B, {x ∈ S | (x % (d : ℤ)).toNat = b} := by simp_all have h_final : S ⊆ ⋃ b ∈ B, {x ∈ S | (x % (d : ℤ)).toNat = b} := by assumption exact h_final lemma ncard_union_residue_classes_bound (n d K : ℕ) (hd_pos : 0 < d) (B : Finset ℕ) (hB_card : B.card ≤ K) (S : Set ℤ) (hS_sub : S ⊆ Set.Ico (0 : ℤ) (↑n / 2)) (hS_fin : S.Finite) (hS_res : ∀ x ∈ S, (x % (d : ℤ)).toNat ∈ B) : S.ncard ≤ K * (n / (2 * d) + 1) := by have h_subset : S ⊆ ⋃ b ∈ B, {x ∈ S | (x % (d : ℤ)).toNat = b} := subset_biUnion_residue_fibers d B S hS_res have h_union_fin : (⋃ b ∈ B, {x ∈ S | (x % (d : ℤ)).toNat = b}).Finite := Set.Finite.biUnion B.finite_toSet (fun b _ => hS_fin.subset (fun x hx => hx.1)) have h1 : S.ncard ≤ (⋃ b ∈ B, {x ∈ S | (x % (d : ℤ)).toNat = b}).ncard := Set.ncard_le_ncard h_subset h_union_fin have h2 : (⋃ b ∈ B, {x ∈ S | (x % (d : ℤ)).toNat = b}).ncard ≤ ∑ b ∈ B, {x ∈ S | (x % (d : ℤ)).toNat = b}.ncard := Finset.set_ncard_biUnion_le B _ have h3 : ∑ b ∈ B, {x ∈ S | (x % (d : ℤ)).toNat = b}.ncard ≤ ∑ _b ∈ B, (n / (2 * d) + 1) := Finset.sum_le_sum (fun b _ => residue_class_fiber_ncard_le n d hd_pos b S hS_sub hS_fin) have h4 : ∑ _b ∈ B, (n / (2 * d) + 1) = B.card * (n / (2 * d) + 1) := Finset.sum_const_nat (fun _ _ => rfl) calc S.ncard ≤ (⋃ b ∈ B, {x ∈ S | (x % (d : ℤ)).toNat = b}).ncard := h1 _ ≤ ∑ b ∈ B, {x ∈ S | (x % (d : ℤ)).toNat = b}.ncard := h2 _ ≤ ∑ _b ∈ B, (n / (2 * d) + 1) := h3 _ = B.card * (n / (2 * d) + 1) := h4 _ ≤ K * (n / (2 * d) + 1) := Nat.mul_le_mul_right _ hB_card lemma fiber_ncard_bound_coprime (η : ℝ) (θ : ℝ) (hη_pos : 0 < η) (hη_lt : η < 1 / 6) (hθ_pos : 0 < θ) (hθ_lt : θ < 1) (n : ℕ) (hn : 2 ≤ n) (hP : (largestPrimeFactor n : ℝ) ≥ (n : ℝ) ^ θ) (h_small : (1 + Real.log (n : ℝ)) ^ 3 / (n : ℝ) ^ θ < η ^ 2 / 100) (q : ℤ) (hq_coprime : Int.gcd q (largestPrimeFactor n : ℤ) = 1) : {p : ℤ | (p, q) ∈ residueBadPairs n η}.ncard ≤ (largestPrimeFactor n ^ n.factorization (largestPrimeFactor n) / ⌈Real.log (n : ℝ)⌉₊) * (n / (2 * largestPrimeFactor n ^ n.factorization (largestPrimeFactor n)) + 1) := by obtain ⟨B, hB_card, hB_mem⟩ := bad_residues_bound η θ hη_pos hη_lt hθ_pos hθ_lt n hn hP h_small q hq_coprime exact ncard_union_residue_classes_bound n (largestPrimeFactor n ^ n.factorization (largestPrimeFactor n)) (largestPrimeFactor n ^ n.factorization (largestPrimeFactor n) / ⌈Real.log (n : ℝ)⌉₊) (by apply Nat.pos_of_ne_zero intro h simp [Nat.pow_eq_zero] at h have : largestPrimeFactor n ≠ 0 := by intro h0 have : (largestPrimeFactor n : ℝ) = 0 := by exact_mod_cast h0 rw [this] at hP have : (n : ℝ) ^ θ ≤ 0 := le_trans (le_of_eq rfl) hP have : (0 : ℝ) < (n : ℝ) ^ θ := by positivity linarith exact this h.1) B hB_card {p : ℤ | (p, q) ∈ residueBadPairs n η} (fiber_subset_range n η hη_pos q) (fiber_finite n η hη_pos q) (fun x hx => hB_mem x hx) lemma fiber_ncard_bound (η : ℝ) (θ : ℝ) (hη_pos : 0 < η) (hη_lt : η < 1 / 6) (hθ_pos : 0 < θ) (hθ_lt : θ < 1) (n : ℕ) (hn : 2 ≤ n) (hP : (largestPrimeFactor n : ℝ) ≥ (n : ℝ) ^ θ) (h_small : (1 + Real.log (n : ℝ)) ^ 3 / (n : ℝ) ^ θ < η ^ 2 / 100) (q : ℤ) : {p : ℤ | (p, q) ∈ residueBadPairs n η}.ncard ≤ (largestPrimeFactor n ^ n.factorization (largestPrimeFactor n) / ⌈Real.log (n : ℝ)⌉₊) * (n / (2 * largestPrimeFactor n ^ n.factorization (largestPrimeFactor n)) + 1) := by by_cases hq_coprime : Int.gcd q (largestPrimeFactor n : ℤ) = 1 · exact fiber_ncard_bound_coprime η θ hη_pos hη_lt hθ_pos hθ_lt n hn hP h_small q hq_coprime · have h_empty := fiber_empty_of_gcd_ne_one n η q hq_coprime simp [h_empty] lemma pos_of_mem_truncatedObtuseRegion_snd (n : ℕ) (η : ℝ) (hη_pos : 0 < η) (pq : ℤ × ℤ) (h : pq ∈ truncatedObtuseRegion n η) : 0 < pq.2 := by have h₂ : (η * (n : ℝ) : ℝ) ≤ (pq.2 : ℝ) := by simpa [truncatedObtuseRegion] using h.2.1 have h₃ : (0 : ℝ) < η * (n : ℝ) := by by_cases hn : n = 0 · have h₆ : (n : ℝ) = 0 := by simp [hn] have h₇ : η * (n : ℝ) = 0 := by rw [h₆]; ring have h₉ : (pq.1 : ℝ) + (pq.2 : ℝ) < (n : ℝ) / 2 := by simpa [truncatedObtuseRegion] using h.2.2.1 have h₁₁ : (pq.1 : ℝ) + (pq.2 : ℝ) < 0 := by linarith have h₁₂ : (η * (n : ℝ) : ℝ) ≤ (pq.1 : ℝ) := by simpa [truncatedObtuseRegion] using h.1 linarith · have h₇ : (0 : ℝ) < η * (n : ℝ) := by positivity linarith have h₅ : 0 < pq.2 := by by_contra h₆ have h₇ : pq.2 ≤ 0 := by linarith have h₈ : (pq.2 : ℝ) ≤ 0 := by exact_mod_cast h₇ linarith exact h₅ lemma pos_of_mem_truncatedObtuseRegion_fst (n : ℕ) (η : ℝ) (hη_pos : 0 < η) (pq : ℤ × ℤ) (h : pq ∈ truncatedObtuseRegion n η) : 0 < pq.1 := by have h₁ : η * (n : ℝ) ≤ (pq.1 : ℝ) := h.1 have h₂ : η * (n : ℝ) ≤ (pq.2 : ℝ) := h.2.1 have h₃ : (pq.1 : ℝ) + (pq.2 : ℝ) < (n : ℝ) / 2 := h.2.2.1 by_cases hn : n = 0 · have h₅ : (n : ℝ) = 0 := by norm_cast have h₆ : η * (n : ℝ) = 0 := by rw [h₅]; ring have h₈ : (pq.1 : ℝ) > 0 := by by_contra _ linarith have h₉ : 0 < (pq.1 : ℤ) := by norm_cast at h₈ ⊢ exact h₉ · have h₇ : 0 < η * (n : ℝ) := by positivity have h₉ : (pq.1 : ℝ) > 0 := by linarith have h₁₀ : 0 < (pq.1 : ℤ) := by norm_cast at h₉ ⊢ exact h₁₀ lemma snd_lt_half_of_mem_truncatedObtuseRegion' (n : ℕ) (η : ℝ) (pq : ℤ × ℤ) (h : pq ∈ truncatedObtuseRegion n η) (hp_pos : 0 < pq.1) : (pq.2 : ℝ) < (n : ℝ) / 2 := by simp only [truncatedObtuseRegion] at h have h₁ : (pq.1 : ℝ) + (pq.2 : ℝ) < (n : ℝ) / 2 := by exact h.2.2.1 have h₂ : 0 < (pq.1 : ℝ) := by exact_mod_cast hp_pos linarith lemma int_le_half_of_real_lt_half (n : ℕ) (q : ℤ) (hq : (q : ℝ) < (n : ℝ) / 2) : q ≤ ↑n / 2 := by have h₂ : (2 : ℝ) * (q : ℝ) < (n : ℝ) := by linarith have h₃ : (2 : ℤ) * q < (n : ℤ) := by norm_cast at h₂ ⊢ have h₅ : q ≤ (n : ℤ) / 2 := by omega simpa [Int.ediv_eq_zero_of_lt] using h₅ lemma snd_mem_Icc_of_mem_residueBadPairs (n : ℕ) (η : ℝ) (hη : 0 < η) (hn : 2 ≤ n) (pq : ℤ × ℤ) (hpq : pq ∈ residueBadPairs n η) : pq.2 ∈ Finset.Icc (1 : ℤ) (↑n / 2) := by have hbad : pq ∈ badPairsE n η := hpq.1 have htor : pq ∈ truncatedObtuseRegion n η := hbad.1 have hq_pos : 0 < pq.2 := pos_of_mem_truncatedObtuseRegion_snd n η hη pq htor have h1 : 1 ≤ pq.2 := hq_pos have hp_pos : 0 < pq.1 := pos_of_mem_truncatedObtuseRegion_fst n η hη pq htor have hq_lt : (pq.2 : ℝ) < (n : ℝ) / 2 := snd_lt_half_of_mem_truncatedObtuseRegion' n η pq htor hp_pos have h2 : pq.2 ≤ ↑n / 2 := int_le_half_of_real_lt_half n pq.2 hq_lt exact Finset.mem_Icc.mpr ⟨h1, h2⟩ lemma fiber_pair_ncard_le (S : Set (ℤ × ℤ)) (q : ℤ) : {pq ∈ S | pq.2 = q}.ncard ≤ {p : ℤ | (p, q) ∈ S}.ncard := by have h₁ : {pq ∈ S | pq.2 = q} = Set.image (fun p : ℤ => (p, q)) {p : ℤ | (p, q) ∈ S} := by ext ⟨a, b⟩; simp only [Set.mem_sep_iff, Set.mem_setOf_eq, Set.mem_image, Prod.mk.injEq] constructor · rintro ⟨ha, rfl⟩; exact ⟨a, ha, rfl, rfl⟩ · rintro ⟨_, hp, rfl, rfl⟩; exact ⟨hp, rfl⟩ have h₂ : Function.Injective (fun p : ℤ => (p, q)) := by exact fun a b hab => (Prod.mk.inj hab).1 have h₃ : {pq ∈ S | pq.2 = q}.ncard ≤ {p : ℤ | (p, q) ∈ S}.ncard := by rw [h₁]; exact (Set.ncard_image_of_injective _ h₂).le exact h₃ lemma card_Icc_one_half_le (n : ℕ) (hn : 2 ≤ n) : (Finset.Icc (1 : ℤ) (↑n / 2)).card ≤ n / 2 := by have h₁ : (Finset.Icc (1 : ℤ) (↑n / 2)).card = ((↑n / 2 : ℤ) + 1 - 1).toNat := by simp [Finset.Icc_eq_empty, Finset.card_eq_zero] rw [h₁] have h₂ : ((↑n / 2 : ℤ) + 1 - 1 : ℤ) = ↑n / 2 := by ring_nf rw [h₂] have h₃ : (↑n / 2 : ℤ).toNat = n / 2 := by have h₄ : (n : ℤ) / 2 ≥ 0 := by omega have h₅ : (↑n / 2 : ℤ).toNat = (n / 2 : ℕ) := by have h₇ : (↑n / 2 : ℤ) = ↑(n / 2 : ℕ) := by have h₉ : (n : ℤ) % 2 = 0 ∨ (n : ℤ) % 2 = 1 := by omega rcases h₉ with (h₉ | h₉) · have h₁₁ : (n : ℤ) / 2 * 2 = (n : ℤ) := by omega norm_cast at h₁₁ ⊢ · have h₁₁ : (n : ℤ) / 2 * 2 + 1 = (n : ℤ) := by omega norm_cast at h₁₁ ⊢ rw [h₇] <;> simp [Int.toNat_of_nonneg (by omega : (0 : ℤ) ≤ (n : ℤ) / 2)] <;> norm_cast rw [h₅] rw [h₃] lemma residueBadPairs_ncard_from_fibers (η : ℝ) (θ : ℝ) (hη_pos : 0 < η) (_hη_lt : η < 1 / 6) (_hθ_pos : 0 < θ) (_hθ_lt : θ < 1) (n : ℕ) (hn : 2 ≤ n) (_hP : (largestPrimeFactor n : ℝ) ≥ (n : ℝ) ^ θ) (_h_small : (1 + Real.log (n : ℝ)) ^ 3 / (n : ℝ) ^ θ < η ^ 2 / 100) (hfiber : ∀ q : ℤ, {p : ℤ | (p, q) ∈ residueBadPairs n η}.ncard ≤ (largestPrimeFactor n ^ n.factorization (largestPrimeFactor n) / ⌈Real.log (n : ℝ)⌉₊) * (n / (2 * largestPrimeFactor n ^ n.factorization (largestPrimeFactor n)) + 1)) : (residueBadPairs n η).ncard ≤ n / 2 * ((largestPrimeFactor n ^ n.factorization (largestPrimeFactor n) / ⌈Real.log (n : ℝ)⌉₊) * (n / (2 * largestPrimeFactor n ^ n.factorization (largestPrimeFactor n)) + 1)) := by set M := (largestPrimeFactor n ^ n.factorization (largestPrimeFactor n) / ⌈Real.log (n : ℝ)⌉₊) * (n / (2 * largestPrimeFactor n ^ n.factorization (largestPrimeFactor n)) + 1) with hM_def set Q := Finset.Icc (1 : ℤ) (↑n / 2) with hQ_def have hsub : residueBadPairs n η ⊆ ⋃ q ∈ Q, {pq : ℤ × ℤ | pq ∈ residueBadPairs n η ∧ pq.2 = q} := by intro pq hpq simp only [Set.mem_iUnion, Set.mem_setOf_eq] exact ⟨pq.2, snd_mem_Icc_of_mem_residueBadPairs n η hη_pos hn pq hpq, hpq, rfl⟩ calc (residueBadPairs n η).ncard ≤ (⋃ q ∈ Q, {pq : ℤ × ℤ | pq ∈ residueBadPairs n η ∧ pq.2 = q}).ncard := Set.ncard_le_ncard hsub (Finset.finite_toSet Q |>.biUnion (fun _ _ => (residueBadPairs_finite n η).subset (fun _ h => h.1))) _ ≤ ∑ q ∈ Q, ({pq : ℤ × ℤ | pq ∈ residueBadPairs n η ∧ pq.2 = q}).ncard := Finset.set_ncard_biUnion_le Q _ _ ≤ ∑ q ∈ Q, {p : ℤ | (p, q) ∈ residueBadPairs n η}.ncard := by apply Finset.sum_le_sum intro q _ exact fiber_pair_ncard_le (residueBadPairs n η) q _ ≤ ∑ _q ∈ Q, M := by apply Finset.sum_le_sum intro q _ exact hfiber q _ = Q.card * M := by rw [Finset.sum_const, smul_eq_mul] _ ≤ (n / 2) * M := by apply Nat.mul_le_mul_right exact card_Icc_one_half_le n hn lemma residueBadPairs_ncard_le_counting (η : ℝ) (θ : ℝ) (hη_pos : 0 < η) (hη_lt : η < 1 / 6) (hθ_pos : 0 < θ) (hθ_lt : θ < 1) (n : ℕ) (hn : 2 ≤ n) (hP : (largestPrimeFactor n : ℝ) ≥ (n : ℝ) ^ θ) (h_small : (1 + Real.log (n : ℝ)) ^ 3 / (n : ℝ) ^ θ < η ^ 2 / 100) : (residueBadPairs n η).ncard ≤ n / 2 * (largestPrimeFactor n ^ n.factorization (largestPrimeFactor n) / ⌈Real.log (n : ℝ)⌉₊) * (n / (2 * largestPrimeFactor n ^ n.factorization (largestPrimeFactor n)) + 1) := by have hfibers := residueBadPairs_ncard_from_fibers η θ hη_pos hη_lt hθ_pos hθ_lt n hn hP h_small (fiber_ncard_bound η θ hη_pos hη_lt hθ_pos hθ_lt n hn hP h_small) linarith [Nat.mul_assoc (n / 2) (largestPrimeFactor n ^ n.factorization (largestPrimeFactor n) / ⌈Real.log ↑n⌉₊) (n / (2 * largestPrimeFactor n ^ n.factorization (largestPrimeFactor n)) + 1)] lemma nat_div_le_mul_div_mul (a b : ℕ) : a / b ≤ 2 * a / (2 * b) := by by_cases h : b = 0 · simp_all · have h₁ : a / b * b ≤ a := by exact Nat.div_mul_le_self _ _ have h₂ : a / b * (2 * b) ≤ 2 * a := by nlinarith have h₃ : 2 * b > 0 := by omega have h₄ : a / b ≤ 2 * a / (2 * b) := by exact Nat.le_div_iff_mul_le h₃ |>.mpr h₂ assumption lemma nat_div_prod_le (a b c d : ℕ) (hc : 0 < c) (hd : 0 < d) : (a / c) * (b / d) ≤ (a * b) / (c * d) := by have h₁ : (a / c) * c ≤ a := Nat.div_mul_le_self a c have h₂ : (b / d) * d ≤ b := Nat.div_mul_le_self b d have h₃ : (a / c) * (b / d) * (c * d) ≤ a * b := by have h₄ : (a / c) * (b / d) * (c * d) = ((a / c) * c) * ((b / d) * d) := by ring rw [h₄] have h₅ : ((a / c) * c) * ((b / d) * d) ≤ a * b := by calc ((a / c) * c) * ((b / d) * d) = (a / c * c) * (b / d * d) := by rfl _ ≤ a * (b / d * d) := by gcongr _ ≤ a * b := by gcongr exact h₅ have h₆ : (a / c) * (b / d) ≤ (a * b) / (c * d) := by have h₉ : (a / c) * (b / d) ≤ (a * b) / (c * d) := by apply Nat.le_div_iff_mul_le (by positivity) |>.mpr nlinarith exact h₉ exact h₆ lemma dR_mul_n2d_le_n2R (n d R : ℕ) (hd_pos : 0 < d) (hR_pos : 0 < R) (hd_dvd : d ∣ n) : d / R * (n / (2 * d)) ≤ n / (2 * R) := by have h2d_pos : 0 < 2 * d := Nat.mul_pos (by norm_num) hd_pos calc d / R * (n / (2 * d)) ≤ (d * n) / (R * (2 * d)) := nat_div_prod_le d n R (2 * d) hR_pos h2d_pos _ = (d * n) / (d * (2 * R)) := by ring_nf _ = n / (2 * R) := by obtain ⟨k, hk⟩ := hd_dvd subst hk show d * (d * k) / (d * (2 * R)) = d * k / (2 * R) rw [Nat.mul_div_mul_left _ _ hd_pos] lemma n2_mul_n2R_le_nsq_4R (n R : ℕ) (hR_pos : 0 < R) : n / 2 * (n / (2 * R)) ≤ n ^ 2 / (4 * R) := by have h2R_pos : 0 < 2 * R := Nat.mul_pos (by norm_num) hR_pos calc n / 2 * (n / (2 * R)) ≤ (n * n) / (2 * (2 * R)) := nat_div_prod_le n n 2 (2 * R) (by norm_num) h2R_pos _ = n ^ 2 / (4 * R) := by ring_nf theorem product_bound_first_term (n d R : ℕ) (hd_pos : 0 < d) (hR_pos : 0 < R) (hd_dvd : d ∣ n) : n / 2 * (d / R) * (n / (2 * d)) ≤ n ^ 2 / (4 * R) := by calc n / 2 * (d / R) * (n / (2 * d)) = n / 2 * (d / R * (n / (2 * d))) := by ring _ ≤ n / 2 * (n / (2 * R)) := by apply Nat.mul_le_mul_left exact dR_mul_n2d_le_n2R n d R hd_pos hR_pos hd_dvd _ ≤ n ^ 2 / (4 * R) := n2_mul_n2R_le_nsq_4R n R hR_pos lemma product_bound_second_term (n d R : ℕ) (hR_pos : 0 < R) (hd_le : d ≤ n) : n / 2 * (d / R) ≤ n ^ 2 / (2 * R) := by have h₁ : n / 2 * (d / R) ≤ n / 2 * (n / R) := by have h₂ : d / R ≤ n / R := by apply Nat.div_le_div_right <;> linarith have h₃ : 0 ≤ n / 2 := by positivity nlinarith have h₂ : n / 2 * (n / R) ≤ n ^ 2 / (2 * R) := by have h₄ : n / 2 * (n / R) ≤ n ^ 2 / (2 * R) := by have h₅ : n / 2 * (n / R) ≤ n ^ 2 / (2 * R) := by calc n / 2 * (n / R) ≤ n / 2 * (n / R) := le_refl _ _ ≤ n ^ 2 / (2 * R) := by have h₆ : (n / 2) * (n / R) * (2 * R) ≤ n ^ 2 := by have h₇ : (n / 2) * 2 ≤ n := by have h₇₁ : n / 2 * 2 ≤ n := by have h₇₂ : n / 2 * 2 ≤ n := by apply Nat.div_mul_le_self exact h₇₂ exact h₇₁ have h₈ : (n / R) * R ≤ n := by have h₈₁ : (n / R) * R ≤ n := by apply Nat.div_mul_le_self exact h₈₁ calc (n / 2) * (n / R) * (2 * R) = ((n / 2) * (n / R)) * (2 * R) := by ring _ = (n / 2) * 2 * ((n / R) * R) := by ring _ ≤ n * ((n / R) * R) := by gcongr _ ≤ n * n := by gcongr _ = n ^ 2 := by ring have h₁₀ : (n / 2) * (n / R) ≤ n ^ 2 / (2 * R) := by apply Nat.le_div_iff_mul_le (by positivity) |>.mpr <;> nlinarith exact h₁₀ exact h₅ exact h₄ calc n / 2 * (d / R) ≤ n / 2 * (n / R) := h₁ _ ≤ n ^ 2 / (2 * R) := h₂ lemma combine_frac_bounds (n R : ℕ) (hR_pos : 0 < R) : n ^ 2 / (4 * R) + n ^ 2 / (2 * R) ≤ 3 * n ^ 2 / (4 * R) := by have h₁ : (n ^ 2 / (4 * R)) * (4 * R) ≤ n ^ 2 := by have h₂ : (n ^ 2 / (4 * R)) * (4 * R) ≤ n ^ 2 := Nat.div_mul_le_self (n ^ 2) (4 * R) exact h₂ have h₂ : (n ^ 2 / (2 * R)) * (2 * R) ≤ n ^ 2 := by have h₃ : (n ^ 2 / (2 * R)) * (2 * R) ≤ n ^ 2 := Nat.div_mul_le_self (n ^ 2) (2 * R) exact h₃ have h₄ : (n ^ 2 / (4 * R) + n ^ 2 / (2 * R)) * (4 * R) ≤ 3 * n ^ 2 := by have h₅ : (n ^ 2 / (4 * R) + n ^ 2 / (2 * R)) * (4 * R) = (n ^ 2 / (4 * R)) * (4 * R) + (n ^ 2 / (2 * R)) * (4 * R) := by ring_nf rw [h₅] linarith have h₅ : n ^ 2 / (4 * R) + n ^ 2 / (2 * R) ≤ 3 * n ^ 2 / (4 * R) := by have h₇ : (n ^ 2 / (4 * R) + n ^ 2 / (2 * R)) * (4 * R) ≤ 3 * n ^ 2 := h₄ have h₈ : n ^ 2 / (4 * R) + n ^ 2 / (2 * R) ≤ 3 * n ^ 2 / (4 * R) := by apply Nat.le_div_iff_mul_le (by positivity) |>.mpr <;> (try omega) exact h₈ exact h₅ lemma counting_bound_simplify (n : ℕ) (hn : 2 ≤ n) (hP_pos : 0 < largestPrimeFactor n) : n / 2 * (largestPrimeFactor n ^ n.factorization (largestPrimeFactor n) / ⌈Real.log (n : ℝ)⌉₊) * (n / (2 * largestPrimeFactor n ^ n.factorization (largestPrimeFactor n)) + 1) ≤ 3 * n ^ 2 / (4 * ⌈Real.log (n : ℝ)⌉₊) := by set P := largestPrimeFactor n set d := P ^ n.factorization P set R := ⌈Real.log (n : ℝ)⌉₊ have hd_pos : 0 < d := Nat.pos_of_ne_zero (pow_ne_zero _ (by omega)) have hR_pos : 0 < R := by apply Nat.ceil_pos.mpr apply Real.log_pos exact_mod_cast hn have hd_dvd : d ∣ n := Nat.ordProj_dvd n P have hd_le : d ≤ n := Nat.le_of_dvd (by omega) hd_dvd rw [Nat.mul_add] simp only [Nat.mul_one] calc n / 2 * (d / R) * (n / (2 * d)) + n / 2 * (d / R) ≤ n ^ 2 / (4 * R) + n ^ 2 / (2 * R) := Nat.add_le_add (product_bound_first_term n d R hd_pos hR_pos hd_dvd) (product_bound_second_term n d R hR_pos hd_le) _ ≤ 3 * n ^ 2 / (4 * R) := combine_frac_bounds n R hR_pos lemma residueBadPairs_ncard_le_nat (η : ℝ) (θ : ℝ) (hη_pos : 0 < η) (hη_lt : η < 1 / 6) (hθ_pos : 0 < θ) (hθ_lt : θ < 1) (n : ℕ) (hn : 2 ≤ n) (hP : (largestPrimeFactor n : ℝ) ≥ (n : ℝ) ^ θ) (h_small : (1 + Real.log (n : ℝ)) ^ 3 / (n : ℝ) ^ θ < η ^ 2 / 100) : (residueBadPairs n η).ncard ≤ 3 * n ^ 2 / (4 * ⌈Real.log (n : ℝ)⌉₊) := by calc (residueBadPairs n η).ncard ≤ n / 2 * (largestPrimeFactor n ^ n.factorization (largestPrimeFactor n) / ⌈Real.log (n : ℝ)⌉₊) * (n / (2 * largestPrimeFactor n ^ n.factorization (largestPrimeFactor n)) + 1) := residueBadPairs_ncard_le_counting η θ hη_pos hη_lt hθ_pos hθ_lt n hn hP h_small _ ≤ 3 * n ^ 2 / (4 * ⌈Real.log (n : ℝ)⌉₊) := counting_bound_simplify n hn (largestPrimeFactor_pos n hn) lemma ncard_nat_to_real_bound (ncard_val n : ℕ) (_hn : 2 ≤ n) (h : ncard_val ≤ 3 * n ^ 2 / (4 * ⌈Real.log (n : ℝ)⌉₊)) : (ncard_val : ℝ) ≤ 3 / 4 * (n : ℝ) ^ 2 / ⌈Real.log (n : ℝ)⌉₊ := by have h₁ : (ncard_val : ℝ) ≤ ( (3 * n ^ 2 / (4 * ⌈Real.log (n : ℝ)⌉₊) : ℕ) : ℝ ) := by simp_all have h₂ : ( (3 * n ^ 2 / (4 * ⌈Real.log (n : ℝ)⌉₊) : ℕ) : ℝ ) ≤ ( (3 * n ^ 2 : ℕ) : ℝ ) / ( (4 * ⌈Real.log (n : ℝ)⌉₊ : ℕ) : ℝ ) := by exact Nat.cast_div_le have h₃ : ( (3 * n ^ 2 : ℕ) : ℝ ) / ( (4 * ⌈Real.log (n : ℝ)⌉₊ : ℕ) : ℝ ) = (3 : ℝ) / 4 * (n : ℝ) ^ 2 / ⌈Real.log (n : ℝ)⌉₊ := by push_cast; ring have h₄ : (ncard_val : ℝ) ≤ 3 / 4 * (n : ℝ) ^ 2 / ⌈Real.log (n : ℝ)⌉₊ := by nlinarith exact h₄ lemma residueBadPairs_ncard_le (η : ℝ) (θ : ℝ) (hη_pos : 0 < η) (hη_lt : η < 1 / 6) (hθ_pos : 0 < θ) (hθ_lt : θ < 1) (n : ℕ) (hn : 2 ≤ n) (hP : (largestPrimeFactor n : ℝ) ≥ (n : ℝ) ^ θ) (h_small : (1 + Real.log (n : ℝ)) ^ 3 / (n : ℝ) ^ θ < η ^ 2 / 100) : ((residueBadPairs n η).ncard : ℝ) ≤ 3 / 4 * (n : ℝ) ^ 2 / ⌈Real.log (n : ℝ)⌉₊ := by exact ncard_nat_to_real_bound _ n hn (residueBadPairs_ncard_le_nat η θ hη_pos hη_lt hθ_pos hθ_lt n hn hP h_small) lemma three_fourths_ceil_le_inv_log (n : ℕ) (hn : 2 ≤ n) : 3 / 4 * (n : ℝ) ^ 2 / ⌈Real.log (n : ℝ)⌉₊ ≤ (n : ℝ) ^ 2 / Real.log (n : ℝ) := by have h₁ : (n : ℝ) ≥ 2 := by exact_mod_cast hn have h₂ : Real.log (n : ℝ) > 0 := by have h₂₁ : (1 : ℝ) < (n : ℝ) := by linarith exact Real.log_pos h₂₁ have h₃ : (⌈Real.log (n : ℝ)⌉₊ : ℝ) ≥ Real.log (n : ℝ) := by exact Nat.le_ceil _ have h₆ : (3 / 4 : ℝ) * ((n : ℝ) ^ 2 / ⌈Real.log (n : ℝ)⌉₊) ≤ ((n : ℝ) ^ 2 / ⌈Real.log (n : ℝ)⌉₊) := by have h₆₁ : (n : ℝ) ^ 2 / ⌈Real.log (n : ℝ)⌉₊ ≥ 0 := by positivity nlinarith have h₇ : ((n : ℝ) ^ 2 / ⌈Real.log (n : ℝ)⌉₊) ≤ ((n : ℝ) ^ 2 / Real.log (n : ℝ)) := by have h₇₇ : 1 / (⌈Real.log (n : ℝ)⌉₊ : ℝ) ≤ 1 / Real.log (n : ℝ) := by apply one_div_le_one_div_of_le · positivity · exact_mod_cast h₃ calc ((n : ℝ) ^ 2 / ⌈Real.log (n : ℝ)⌉₊) = (n : ℝ) ^ 2 * (1 / (⌈Real.log (n : ℝ)⌉₊ : ℝ)) := by field_simp _ ≤ (n : ℝ) ^ 2 * (1 / Real.log (n : ℝ)) := by gcongr _ = ((n : ℝ) ^ 2 / Real.log (n : ℝ)) := by field_simp have h₈ : (3 / 4 : ℝ) * ((n : ℝ) ^ 2 / ⌈Real.log (n : ℝ)⌉₊) ≤ ((n : ℝ) ^ 2 / Real.log (n : ℝ)) := by linarith have h₉ : 3 / 4 * (n : ℝ) ^ 2 / ⌈Real.log (n : ℝ)⌉₊ = (3 / 4 : ℝ) * ((n : ℝ) ^ 2 / ⌈Real.log (n : ℝ)⌉₊) := by ring_nf rw [h₉] exact h₈ lemma residueBadPairs_ncard_bound (η : ℝ) (θ : ℝ) (hη_pos : 0 < η) (hη_lt : η < 1 / 6) (hθ_pos : 0 < θ) (hθ_lt : θ < 1) (n : ℕ) (hn : 2 ≤ n) (hP : (largestPrimeFactor n : ℝ) ≥ (n : ℝ) ^ θ) (h_small : (1 + Real.log (n : ℝ)) ^ 3 / (n : ℝ) ^ θ < η ^ 2 / 100) : ((residueBadPairs n η).ncard : ℝ) ≤ (n : ℝ) ^ 2 / Real.log n := le_trans (residueBadPairs_ncard_le η θ hη_pos hη_lt hθ_pos hθ_lt n hn hP h_small) (three_fourths_ceil_le_inv_log n hn) lemma pos_of_mem_truncatedObtuseRegion_fst_pd (n : ℕ) (η : ℝ) (hη_pos : 0 < η) (pq : ℤ × ℤ) (h : pq ∈ truncatedObtuseRegion n η) : 0 < pq.1 := by have h₁ : η * (n : ℝ) ≤ (pq.1 : ℝ) := h.1 have h₂ : η * (n : ℝ) ≤ (pq.2 : ℝ) := h.2.1 have h₃ : (pq.1 : ℝ) + (pq.2 : ℝ) < (n : ℝ) / 2 := h.2.2.1 by_cases hn : n = 0 · have h₅ : (n : ℝ) = 0 := by norm_cast have h₆ : η * (n : ℝ) = 0 := by rw [h₅]; ring have h₈ : (pq.1 : ℝ) > 0 := by by_contra _ linarith have h₉ : 0 < (pq.1 : ℤ) := by norm_cast at h₈ ⊢ exact h₉ · have h₇ : 0 < η * (n : ℝ) := by positivity have h₉ : (pq.1 : ℝ) > 0 := by linarith have h₁₀ : 0 < (pq.1 : ℤ) := by norm_cast at h₉ ⊢ exact h₁₀ lemma pos_of_mem_truncatedObtuseRegion_snd_pd (n : ℕ) (η : ℝ) (hη_pos : 0 < η) (pq : ℤ × ℤ) (h : pq ∈ truncatedObtuseRegion n η) : 0 < pq.2 := by have h₂ : (η * (n : ℝ) : ℝ) ≤ (pq.2 : ℝ) := by simpa [truncatedObtuseRegion] using h.2.1 have h₃ : (0 : ℝ) < η * (n : ℝ) := by by_cases hn : n = 0 · have h₆ : (n : ℝ) = 0 := by simp [hn] have h₇ : η * (n : ℝ) = 0 := by rw [h₆]; ring have h₉ : (pq.1 : ℝ) + (pq.2 : ℝ) < (n : ℝ) / 2 := by simpa [truncatedObtuseRegion] using h.2.2.1 have h₁₁ : (pq.1 : ℝ) + (pq.2 : ℝ) < 0 := by linarith have h₁₂ : (η * (n : ℝ) : ℝ) ≤ (pq.1 : ℝ) := by simpa [truncatedObtuseRegion] using h.1 linarith · have h₇ : (0 : ℝ) < η * (n : ℝ) := by positivity linarith have h₅ : 0 < pq.2 := by by_contra h₆ have h₇ : pq.2 ≤ 0 := by linarith have h₈ : (pq.2 : ℝ) ≤ 0 := by exact_mod_cast h₇ linarith exact h₅ lemma fst_lt_half_of_mem_truncatedObtuseRegion (n : ℕ) (η : ℝ) (pq : ℤ × ℤ) (h : pq ∈ truncatedObtuseRegion n η) (hq_pos : 0 < pq.2) : (pq.1 : ℝ) < (n : ℝ) / 2 := by have h₃ : ((pq.1 : ℝ) + (pq.2 : ℝ) : ℝ) < (n : ℝ) / 2 := h.2.2.1 have h₄ : (pq.2 : ℝ) > 0 := by exact_mod_cast hq_pos have h₅ : (pq.1 : ℝ) < (n : ℝ) / 2 := by linarith exact h₅ lemma largestPrimeFactor_le_of_dvd_pos (P : ℕ) (p : ℤ) (hp_pos : 0 < p) (hdvd : (P : ℤ) ∣ p) : (P : ℤ) ≤ p := by have h₁ : (P : ℤ) ≤ p := by by_cases h₅ : (P : ℤ) = 0 · exfalso have h₇ : (0 : ℤ) ∣ p := by simpa [h₅] using hdvd have h₈ : p = 0 := by simpa [h₅] using h₇ linarith · have h₈ : (P : ℤ) ≤ p := by have h₉ : (P : ℤ) ∣ p := hdvd exact Int.le_of_dvd (by positivity) h₉ exact h₈ exact h₁ lemma pdivPairs_empty_of_large_P (n : ℕ) (η : ℝ) (hη_pos : 0 < η) (hP_large : n < 2 * largestPrimeFactor n) : pdivPairs n η = ∅ := by ext pq simp only [Set.mem_empty_iff_false, iff_false] intro hpq have hmem : pq ∈ truncatedObtuseRegion n η := hpq.1 have hdvd : (largestPrimeFactor n : ℤ) ∣ pq.1 := hpq.2.2 have hp_pos : 0 < pq.1 := pos_of_mem_truncatedObtuseRegion_fst_pd n η hη_pos pq hmem have hq_pos : 0 < pq.2 := pos_of_mem_truncatedObtuseRegion_snd_pd n η hη_pos pq hmem have hPle : (largestPrimeFactor n : ℤ) ≤ pq.1 := largestPrimeFactor_le_of_dvd_pos (largestPrimeFactor n) pq.1 hp_pos hdvd have hp_lt : (pq.1 : ℝ) < (n : ℝ) / 2 := fst_lt_half_of_mem_truncatedObtuseRegion n η pq hmem hq_pos have hPle_real : (largestPrimeFactor n : ℝ) ≤ (pq.1 : ℝ) := by exact_mod_cast hPle have hP_large_real : (n : ℝ) < 2 * (largestPrimeFactor n : ℝ) := by exact_mod_cast hP_large linarith lemma pdivPairs_subset_prod_half (n : ℕ) (η : ℝ) (hη_pos : 0 < η) : pdivPairs n η ⊆ {x : ℤ | 0 ≤ x ∧ x ≤ (n / 2 : ℤ) ∧ (largestPrimeFactor n : ℤ) ∣ x} ×ˢ Set.Icc (0 : ℤ) (n / 2 : ℤ) := by intro ⟨a, b⟩ h simp only [pdivPairs, truncatedObtuseRegion, Set.mem_setOf_eq, Set.mem_prod] at h ⊢ have h₁ : (η : ℝ) * (n : ℝ) ≤ (a : ℝ) := by exact h.1.1 have h₂ : (η : ℝ) * (n : ℝ) ≤ (b : ℝ) := by exact h.1.2.1 have h₃ : (a : ℝ) + (b : ℝ) < (n : ℝ) / 2 := by exact h.1.2.2.1 have h₄ : Int.gcd (Int.gcd a b) (n : ℤ) = 1 := by exact h.1.2.2.2 have h₆ : (largestPrimeFactor n : ℤ) ∣ a := by exact h.2.2 have h₇ : 0 ≤ a := by have h₇₂ : 0 ≤ (η : ℝ) * (n : ℝ) := by positivity have h₇₃ : 0 ≤ (a : ℝ) := by linarith exact_mod_cast h₇₃ have h₈ : 0 ≤ b := by have h₈₂ : 0 ≤ (η : ℝ) * (n : ℝ) := by positivity have h₈₃ : 0 ≤ (b : ℝ) := by linarith exact_mod_cast h₈₃ have h₉ : (a : ℝ) + (b : ℝ) < (n : ℝ) / 2 := h₃ have h₁₀ : (a : ℝ) < (n : ℝ) / 2 := by have h₁₀₂ : 0 ≤ (b : ℝ) := by positivity linarith have h₁₁ : (a : ℤ) ≤ (n / 2 : ℤ) := by have h₁₁₁ : (a : ℝ) < (n : ℝ) / 2 := h₁₀ have h₁₁₂ : (a : ℝ) ≤ (n : ℝ) / 2 := by linarith have h₁₁₃ : (a : ℤ) ≤ (n : ℕ) / 2 := by have h₁₁₄ : (a : ℝ) ≤ (n : ℝ) / 2 := by linarith have h₁₁₅ : (a : ℤ) ≤ (n : ℕ) / 2 := by have h₁₁₆ : (a : ℝ) ≤ (n : ℝ) / 2 := by linarith have h₁₁₇ : (a : ℤ) ≤ ⌊(n : ℝ) / 2⌋ := by apply Int.le_floor.mpr norm_num at h₁₁₆ ⊢ <;> simp_all [Int.cast_le] have h₁₁₈ : ⌊(n : ℝ) / 2⌋ = (n : ℕ) / 2 := by rw [Int.floor_eq_iff] (try norm_cast) <;> (try { field_simp at * <;> ring_nf at * <;> norm_cast at * <;> (try omega) }) rw [h₁₁₈] at h₁₁₇ exact_mod_cast h₁₁₇ exact h₁₁₅ exact_mod_cast h₁₁₃ have h₁₂ : (b : ℤ) ≤ (n / 2 : ℤ) := by have h₁₂₁ : (a : ℝ) + (b : ℝ) < (n : ℝ) / 2 := h₃ have h₁₂₂ : (a : ℝ) ≥ 0 := by positivity have h₁₂₃ : (b : ℝ) < (n : ℝ) / 2 := by linarith have h₁₂₄ : (b : ℝ) ≤ (n : ℝ) / 2 := by linarith have h₁₂₅ : (b : ℤ) ≤ (n : ℕ) / 2 := by have h₁₂₆ : (b : ℝ) ≤ (n : ℝ) / 2 := by linarith have h₁₂₇ : (b : ℤ) ≤ ⌊(n : ℝ) / 2⌋ := by apply Int.le_floor.mpr norm_num at h₁₂₆ ⊢ <;> simp_all [Int.cast_le] have h₁₂₈ : ⌊(n : ℝ) / 2⌋ = (n : ℕ) / 2 := by rw [Int.floor_eq_iff] (try norm_cast) <;> (try { field_simp at * <;> ring_nf at * <;> norm_cast at * <;> (try omega) }) rw [h₁₂₈] at h₁₂₇ exact_mod_cast h₁₂₇ exact_mod_cast h₁₂₅ refine' ⟨_, _⟩ · refine' ⟨h₇, h₁₁, _⟩ exact h₆ · refine' ⟨h₈, _⟩ exact h₁₂ lemma ncard_nonneg_multiples_eq (B : ℤ) (P : ℕ) (hP : 0 < P) (hB : 0 ≤ B) : ({x : ℤ | 0 ≤ x ∧ x ≤ B ∧ (P : ℤ) ∣ x}).ncard = B.toNat / P + 1 := Nat.le_antisymm (ncard_nonneg_multiples_le B P hP hB) (ncard_nonneg_multiples_ge B P hP hB) lemma div_two_add_one_le_1 (a : ℕ) (ha : 2 ≤ a) : a / 2 + 1 ≤ a := by have h₁ : a / 2 + 1 ≤ a := by omega exact h₁ lemma ncard_multiples_half_le (n P : ℕ) (hP_pos : 0 < P) (h2P : 2 * P ≤ n) : ({x : ℤ | 0 ≤ x ∧ x ≤ (n / 2 : ℤ) ∧ (P : ℤ) ∣ x}).ncard ≤ n / P := by have hB : (0 : ℤ) ≤ (n : ℤ) / 2 := by omega rw [ncard_nonneg_multiples_eq ((n : ℤ) / 2) P hP_pos hB] have h1 : ((n : ℤ) / 2).toNat = n / 2 := by have hnn : (0 : ℤ) ≤ ↑n := Int.natCast_nonneg n have h2 : (0 : ℤ) < 2 := by omega rw [show (2 : ℤ) = ↑(2 : ℕ) from rfl] exact int_toNat_ediv_eq (↑n) 2 (by omega) hnn rw [h1] rw [Nat.div_right_comm] apply div_two_add_one_le_1 rwa [Nat.le_div_iff_mul_le hP_pos] lemma ncard_Icc_zero_half_le (n : ℕ) (hn : 2 ≤ n) : (Set.Icc (0 : ℤ) (n / 2 : ℤ)).ncard ≤ n := by rw [Int_Icc_ncard] exact div_two_add_one_le_1 n hn lemma multiples_in_half_finite (n P : ℕ) : {x : ℤ | 0 ≤ x ∧ x ≤ (n / 2 : ℤ) ∧ (P : ℤ) ∣ x}.Finite := multiples_finite 0 (n / 2 : ℤ) P lemma Icc_zero_half_finite (n : ℕ) : (Set.Icc (0 : ℤ) (n / 2 : ℤ)).Finite := Set.finite_Icc _ _ lemma prod_half_finite (n P : ℕ) : ({x : ℤ | 0 ≤ x ∧ x ≤ (n / 2 : ℤ) ∧ (P : ℤ) ∣ x} ×ˢ Set.Icc (0 : ℤ) (n / 2 : ℤ)).Finite := Set.Finite.prod (multiples_in_half_finite n P) (Icc_zero_half_finite n) lemma nat_div_mul_le_mul_div (n P : ℕ) (hP_pos : 0 < P) : (n / P) * n ≤ n * n / P := by rw [Nat.le_div_iff_mul_le hP_pos] calc (n / P) * n * P = (n / P) * P * n := by ring _ ≤ n * n := Nat.mul_le_mul_right n (Nat.div_mul_le_self n P) lemma pdivPairs_ncard_le_when_small_P (n : ℕ) (η : ℝ) (hη_pos : 0 < η) (hn : 2 ≤ n) (hP_pos : 0 < largestPrimeFactor n) (h2P : 2 * largestPrimeFactor n ≤ n) : (pdivPairs n η).ncard ≤ n * n / largestPrimeFactor n := by let multiples := {x : ℤ | 0 ≤ x ∧ x ≤ (n / 2 : ℤ) ∧ (largestPrimeFactor n : ℤ) ∣ x} let interval := Set.Icc (0 : ℤ) (n / 2 : ℤ) let prod_set := multiples ×ˢ interval have prod_finite : prod_set.Finite := prod_half_finite n (largestPrimeFactor n) have subset : pdivPairs n η ⊆ prod_set := pdivPairs_subset_prod_half n η hη_pos have ncard_mono : (pdivPairs n η).ncard ≤ prod_set.ncard := Set.ncard_le_ncard subset prod_finite have ncard_prod_eq : prod_set.ncard = multiples.ncard * interval.ncard := Set.ncard_prod have ncard_multiples := ncard_multiples_half_le n (largestPrimeFactor n) hP_pos h2P have ncard_interval := ncard_Icc_zero_half_le n hn have ncard_prod_le : prod_set.ncard ≤ (n / largestPrimeFactor n) * n := by rw [ncard_prod_eq] exact Nat.mul_le_mul ncard_multiples ncard_interval have arith_bound := nat_div_mul_le_mul_div n (largestPrimeFactor n) hP_pos calc (pdivPairs n η).ncard ≤ prod_set.ncard := ncard_mono _ ≤ (n / largestPrimeFactor n) * n := ncard_prod_le _ ≤ n * n / largestPrimeFactor n := arith_bound lemma nat_sq_div_le_real (n : ℕ) (P : ℕ) (θ : ℝ) (hn : 2 ≤ n) (hP_pos : 0 < P) (hP : (P : ℝ) ≥ (n : ℝ) ^ θ) : (↑(n * n / P) : ℝ) ≤ (n : ℝ) ^ 2 / (n : ℝ) ^ θ := by calc (↑(n * n / P) : ℝ) ≤ ↑(n * n) / ↑P := Nat.cast_div_le _ = (n : ℝ) ^ 2 / (P : ℝ) := by rw [Nat.cast_mul, sq] _ ≤ (n : ℝ) ^ 2 / (n : ℝ) ^ θ := real_sq_div_mono n P θ hn hP_pos hP lemma pdivPairs_ncard_bound (η : ℝ) (θ : ℝ) (hη_pos : 0 < η) (hη_lt : η < 1 / 6) (hθ_pos : 0 < θ) (hθ_lt : θ < 1) (n : ℕ) (hn : 2 ≤ n) (hP : (largestPrimeFactor n : ℝ) ≥ (n : ℝ) ^ θ) : ((pdivPairs n η).ncard : ℝ) ≤ (n : ℝ) ^ 2 / (n : ℝ) ^ θ := by by_cases h2P : 2 * largestPrimeFactor n ≤ n · have hP_pos : 0 < largestPrimeFactor n := by rcases Nat.eq_zero_or_pos (largestPrimeFactor n) with h | h · exfalso; rw [h] at hP; simp at hP have : (0 : ℝ) < (n : ℝ) ^ θ := by positivity linarith · exact h calc ((pdivPairs n η).ncard : ℝ) ≤ ↑(n * n / largestPrimeFactor n) := by exact_mod_cast pdivPairs_ncard_le_when_small_P n η hη_pos hn hP_pos h2P _ ≤ (n : ℝ) ^ 2 / (n : ℝ) ^ θ := nat_sq_div_le_real n (largestPrimeFactor n) θ hn hP_pos hP · push_neg at h2P have : pdivPairs n η = ∅ := pdivPairs_empty_of_large_P n η hη_pos h2P rw [this, Set.ncard_empty] simp apply div_nonneg · positivity · positivity lemma badPairsE_subset_union (n : ℕ) (η : ℝ) : badPairsE n η ⊆ pdivPairs n η ∪ residueBadPairs n η := by intro ⟨p, q⟩ hpq simp only [badPairsE, pdivPairs, residueBadPairs, Set.mem_setOf_eq, Set.mem_sep_iff, Set.mem_union] at hpq ⊢ by_cases h : (largestPrimeFactor n : ℤ) ∣ p · left exact ⟨hpq.1, hpq.2.1, h⟩ · right exact ⟨hpq, h⟩ lemma badPairsE_ncard_le (η : ℝ) (θ : ℝ) (hη_pos : 0 < η) (hη_lt : η < 1 / 6) (hθ_pos : 0 < θ) (hθ_lt : θ < 1) (n : ℕ) (hn : 2 ≤ n) (hP : (largestPrimeFactor n : ℝ) ≥ (n : ℝ) ^ θ) (h_small : (1 + Real.log (n : ℝ)) ^ 3 / (n : ℝ) ^ θ < η ^ 2 / 100) : ((badPairsE n η).ncard : ℝ) ≤ (n : ℝ) ^ 2 * (1 / (n : ℝ) ^ θ + 1 / Real.log n) := by have h_subset := badPairsE_subset_union n η have h_finite_pdiv : (pdivPairs n η).Finite := (truncatedObtuseRegion_finite n η).subset (fun _ h => h.1) have h_finite_residue : (residueBadPairs n η).Finite := residueBadPairs_finite n η have h_finite_union : (pdivPairs n η ∪ residueBadPairs n η).Finite := Set.Finite.union h_finite_pdiv h_finite_residue have h_ncard_mono : (badPairsE n η).ncard ≤ (pdivPairs n η ∪ residueBadPairs n η).ncard := Set.ncard_le_ncard h_subset h_finite_union have h_ncard_union : ((pdivPairs n η ∪ residueBadPairs n η).ncard : ℝ) ≤ ((pdivPairs n η).ncard : ℝ) + ((residueBadPairs n η).ncard : ℝ) := by have := Set.ncard_union_le (pdivPairs n η) (residueBadPairs n η) exact_mod_cast this have h_pdiv_bound := pdivPairs_ncard_bound η θ hη_pos hη_lt hθ_pos hθ_lt n hn hP have h_residue_bound := residueBadPairs_ncard_bound η θ hη_pos hη_lt hθ_pos hθ_lt n hn hP h_small calc ((badPairsE n η).ncard : ℝ) ≤ ((pdivPairs n η ∪ residueBadPairs n η).ncard : ℝ) := by exact_mod_cast h_ncard_mono _ ≤ ((pdivPairs n η).ncard : ℝ) + ((residueBadPairs n η).ncard : ℝ) := h_ncard_union _ ≤ (n : ℝ) ^ 2 / (n : ℝ) ^ θ + (n : ℝ) ^ 2 / Real.log n := by linarith _ = (n : ℝ) ^ 2 * (1 / (n : ℝ) ^ θ) + (n : ℝ) ^ 2 * (1 / Real.log n) := by field_simp _ = (n : ℝ) ^ 2 * (1 / (n : ℝ) ^ θ + 1 / Real.log n) := by ring lemma exists_fourier_exceptional_superset (η : ℝ) (θ : ℝ) (hη_pos : 0 < η) (hη_lt : η < 1 / 6) (hθ_pos : 0 < θ) (hθ_lt : θ < 1) (n : ℕ) (hn : 2 ≤ n) (hP : (largestPrimeFactor n : ℝ) ≥ (n : ℝ) ^ θ) (h_small : (1 + Real.log (n : ℝ)) ^ 3 / (n : ℝ) ^ θ < η ^ 2 / 100) : ∃ E' : Set (ℤ × ℤ), E'.Finite ∧ badPairsE n η ⊆ E' ∧ (E'.ncard : ℝ) ≤ (n : ℝ) ^ 2 * (1 / (n : ℝ) ^ θ + 1 / Real.log n) := by use badPairsE n η refine ⟨?_, Set.Subset.rfl, ?_⟩ · exact (truncatedObtuseRegion_finite n η).subset (fun _ h => h.1) · exact badPairsE_ncard_le η θ hη_pos hη_lt hθ_pos hθ_lt n hn hP h_small lemma badPairsE_ncard_bound (η : ℝ) (θ : ℝ) (hη_pos : 0 < η) (hη_lt : η < 1 / 6) (hθ_pos : 0 < θ) (hθ_lt : θ < 1) (n : ℕ) (hn : 2 ≤ n) (hP : (largestPrimeFactor n : ℝ) ≥ (n : ℝ) ^ θ) (h_small : (1 + Real.log (n : ℝ)) ^ 3 / (n : ℝ) ^ θ < η ^ 2 / 100) : ((badPairsE n η).ncard : ℝ) ≤ (n : ℝ) ^ 2 * (1 / (n : ℝ) ^ θ + 1 / Real.log n) := by obtain ⟨E', hE'_fin, hE'_sub, hE'_card⟩ := exists_fourier_exceptional_superset η θ hη_pos hη_lt hθ_pos hθ_lt n hn hP h_small calc ((badPairsE n η).ncard : ℝ) ≤ (E'.ncard : ℝ) := by exact_mod_cast Set.ncard_le_ncard hE'_sub hE'_fin _ ≤ (n : ℝ) ^ 2 * (1 / (n : ℝ) ^ θ + 1 / Real.log n) := hE'_card lemma exceptional_set_construction_single_n (η : ℝ) (θ : ℝ) (hη_pos : 0 < η) (hη_lt : η < 1 / 6) (hθ_pos : 0 < θ) (hθ_lt : θ < 1) (n : ℕ) (hn : 2 ≤ n) (hP : (largestPrimeFactor n : ℝ) ≥ (n : ℝ) ^ θ) (h_small : (1 + Real.log (n : ℝ)) ^ 3 / (n : ℝ) ^ θ < η ^ 2 / 100) : ∃ (E : Set (ℤ × ℤ)), E ⊆ truncatedObtuseRegion n η ∧ E.Finite ∧ (E.ncard : ℝ) ≤ (n : ℝ) ^ 2 * (1 / (n : ℝ) ^ θ + 1 / Real.log n) ∧ ∀ pq ∈ truncatedObtuseRegion n η, Int.gcd pq.2 (largestPrimeFactor n : ℤ) = 1 → pq ∉ E → (η ^ 2 / 2 : ℝ) * (Nat.totient n : ℝ) ≤ (countingFunctionS n pq.1 pq.2 : ℝ) := by refine ⟨badPairsE n η, ?_, ?_, ?_, ?_⟩ · intro pq hpq; exact hpq.1 · exact (truncatedObtuseRegion_finite n η).subset (fun pq hpq => hpq.1) · exact badPairsE_ncard_bound η θ hη_pos hη_lt hθ_pos hθ_lt n hn hP h_small · intro pq hpq hgcd hnotE by_contra h push_neg at h exact hnotE ⟨hpq, hgcd, h⟩ lemma log_ge_one_of_ge_three (n : ℕ) (hn : 3 ≤ n) : 1 ≤ Real.log (n : ℝ) := by have h₀ : Real.exp 1 < 3 := by have := Real.exp_one_lt_d9 norm_num at this ⊢ <;> linarith have h₁ : Real.log 3 > 1 := by have h₄ : 1 < Real.log 3 := by by_contra h have h₅ : Real.log 3 ≤ 1 := by linarith have h₆ : Real.exp (Real.log 3) ≤ Real.exp 1 := Real.exp_le_exp.mpr h₅ have h₇ : Real.exp (Real.log 3) = 3 := by rw [Real.exp_log (by positivity : (0 : ℝ) < 3)] rw [h₇] at h₆ linarith linarith have h₃ : Real.log (n : ℝ) ≥ Real.log 3 := by apply Real.log_le_log · positivity · exact_mod_cast hn have h₄ : 1 ≤ Real.log (n : ℝ) := by linarith exact h₄ lemma one_plus_log_pow_le (n : ℕ) (hn : 3 ≤ n) : (1 + Real.log (n : ℝ)) ^ 3 ≤ 8 * Real.log (n : ℝ) ^ 3 := by have hlog : 1 ≤ Real.log (n : ℝ) := log_ge_one_of_ge_three n hn have h1 : 1 + Real.log (n : ℝ) ≤ 2 * Real.log (n : ℝ) := by linarith have h2 : 0 ≤ 1 + Real.log (n : ℝ) := by linarith calc (1 + Real.log (n : ℝ)) ^ 3 ≤ (2 * Real.log (n : ℝ)) ^ 3 := pow_le_pow_left₀ h2 h1 3 _ = 8 * Real.log (n : ℝ) ^ 3 := by ring lemma norm_log_pow_le_mul_norm_rpow (θ : ℝ) (hθ : 0 < θ) (c : ℝ) (hc : 0 < c) : ∃ N : ℕ, ∀ n : ℕ, N ≤ n → ‖Real.log (n : ℝ) ^ 3‖ ≤ c * ‖(n : ℝ) ^ θ‖ := by simp only [← Real.rpow_natCast (Real.log _) 3] have h1 : (fun x => Real.log x ^ (3 : ℝ)) =o[Filter.atTop] fun x => x ^ θ := isLittleO_log_rpow_rpow_atTop 3 hθ have h2 : ∀ᶠ (x : ℝ) in Filter.atTop, ‖Real.log x ^ (3 : ℝ)‖ ≤ c * ‖x ^ θ‖ := h1.def hc exact (tendsto_natCast_atTop_atTop.eventually h2).exists_forall_of_atTop theorem norm_bound_implies_div_lt (θ : ℝ) (ε : ℝ) (hε : 0 < ε) (n : ℕ) (hn : 1 ≤ n) (hbound : ‖Real.log (n : ℝ) ^ 3‖ ≤ (ε / 2) * ‖(n : ℝ) ^ θ‖) : Real.log (n : ℝ) ^ 3 / (n : ℝ) ^ θ < ε := by have h_log_cube_nonneg : 0 ≤ Real.log (n : ℝ) ^ 3 := by positivity have h_norm_log_cube : ‖(Real.log (n : ℝ) : ℝ) ^ 3‖ = (Real.log (n : ℝ) : ℝ) ^ 3 := by rw [Real.norm_eq_abs] rw [abs_of_nonneg h_log_cube_nonneg] have h_n_rpow_pos : 0 < (n : ℝ) ^ θ := by exact Real.rpow_pos_of_pos (by positivity) θ have h_norm_n_rpow : ‖(n : ℝ) ^ θ‖ = (n : ℝ) ^ θ := by rw [Real.norm_eq_abs] rw [abs_of_nonneg (le_of_lt h_n_rpow_pos)] have h_main_ineq : (Real.log (n : ℝ) : ℝ) ^ 3 ≤ (ε / 2) * (n : ℝ) ^ θ := by have h₁ : ‖(Real.log (n : ℝ) : ℝ) ^ 3‖ ≤ (ε / 2) * ‖(n : ℝ) ^ θ‖ := hbound have h₂ : ‖(Real.log (n : ℝ) : ℝ) ^ 3‖ = (Real.log (n : ℝ) : ℝ) ^ 3 := h_norm_log_cube have h₃ : ‖(n : ℝ) ^ θ‖ = (n : ℝ) ^ θ := h_norm_n_rpow rw [h₂] at h₁ rw [h₃] at h₁ linarith have h_div_ineq : (Real.log (n : ℝ) : ℝ) ^ 3 / (n : ℝ) ^ θ ≤ ε / 2 := by have h₂ : 0 < (n : ℝ) ^ θ := h_n_rpow_pos have h₃ : (Real.log (n : ℝ) : ℝ) ^ 3 / (n : ℝ) ^ θ ≤ (ε / 2) * (n : ℝ) ^ θ / (n : ℝ) ^ θ := by gcongr have h₄ : (ε / 2) * (n : ℝ) ^ θ / (n : ℝ) ^ θ = ε / 2 := by field_simp [h₂.ne'] rw [h₄] at h₃ linarith have h_final : (Real.log (n : ℝ) : ℝ) ^ 3 / (n : ℝ) ^ θ < ε := by linarith simpa [div_eq_mul_inv] using h_final lemma norm_bound_to_div_lt (θ : ℝ) (hθ : 0 < θ) (ε : ℝ) (hε : 0 < ε) (N : ℕ) (hN : ∀ n : ℕ, N ≤ n → ‖Real.log (n : ℝ) ^ 3‖ ≤ (ε / 2) * ‖(n : ℝ) ^ θ‖) : ∃ N' : ℕ, ∀ n : ℕ, N' ≤ n → Real.log (n : ℝ) ^ 3 / (n : ℝ) ^ θ < ε := by exact ⟨max N 1, fun n hn => norm_bound_implies_div_lt θ ε hε n (le_of_max_le_right hn) (hN n (le_of_max_le_left hn))⟩ lemma log_pow_three_div_rpow_eventually_lt (θ : ℝ) (hθ : 0 < θ) (ε : ℝ) (hε : 0 < ε) : ∃ N : ℕ, ∀ n : ℕ, N ≤ n → Real.log (n : ℝ) ^ 3 / (n : ℝ) ^ θ < ε := by obtain ⟨N, hN⟩ := norm_log_pow_le_mul_norm_rpow θ hθ (ε / 2) (by linarith) exact norm_bound_to_div_lt θ hθ ε hε N hN lemma log_pow_over_rpow_eventually_lt (θ : ℝ) (hθ_pos : 0 < θ) (ε : ℝ) (hε : 0 < ε) : ∃ N : ℕ, ∀ n : ℕ, N ≤ n → (1 + Real.log (n : ℝ)) ^ 3 / (n : ℝ) ^ θ < ε := by obtain ⟨N₁, hN₁⟩ := log_pow_three_div_rpow_eventually_lt θ hθ_pos (ε / 8) (by linarith) refine ⟨max N₁ 3, fun n hn => ?_⟩ have hn₁ : N₁ ≤ n := by omega have hn₃ : 3 ≤ n := by omega have h_n_pos : (0 : ℝ) < (n : ℝ) := by positivity have h_rpow_pos : (0 : ℝ) < (n : ℝ) ^ θ := Real.rpow_pos_of_pos h_n_pos θ calc (1 + Real.log (n : ℝ)) ^ 3 / (n : ℝ) ^ θ ≤ 8 * Real.log (n : ℝ) ^ 3 / (n : ℝ) ^ θ := by apply div_le_div_of_nonneg_right (one_plus_log_pow_le n hn₃) (le_of_lt h_rpow_pos) _ = 8 * (Real.log (n : ℝ) ^ 3 / (n : ℝ) ^ θ) := by ring _ < 8 * (ε / 8) := by apply mul_lt_mul_of_pos_left (hN₁ n hn₁) (by norm_num : (0 : ℝ) < 8) _ = ε := by ring lemma exceptional_set_with_counting_bound (η : ℝ) (θ : ℝ) (hη_pos : 0 < η) (hη_lt : η < 1 / 6) (hθ_pos : 0 < θ) (hθ_lt : θ < 1) : ∃ N₁ : ℕ, ∀ n : ℕ, N₁ ≤ n → (largestPrimeFactor n : ℝ) ≥ (n : ℝ) ^ θ → ∃ (E : Set (ℤ × ℤ)), E ⊆ truncatedObtuseRegion n η ∧ E.Finite ∧ (E.ncard : ℝ) ≤ (n : ℝ) ^ 2 * (1 / (n : ℝ) ^ θ + 1 / Real.log n) ∧ ∀ pq ∈ truncatedObtuseRegion n η, Int.gcd pq.2 (largestPrimeFactor n : ℤ) = 1 → pq ∉ E → (η ^ 2 / 2 : ℝ) * (Nat.totient n : ℝ) ≤ (countingFunctionS n pq.1 pq.2 : ℝ) := by have hε : (0 : ℝ) < η ^ 2 / 100 := by positivity obtain ⟨N, hN⟩ := log_pow_over_rpow_eventually_lt θ hθ_pos (η ^ 2 / 100) hε refine ⟨max N 2, fun n hn hP => ?_⟩ have hn_ge_N : N ≤ n := le_of_max_le_left hn have hn_ge_2 : 2 ≤ n := le_of_max_le_right hn have h_small := hN n hn_ge_N exact exceptional_set_construction_single_n η θ hη_pos hη_lt hθ_pos hθ_lt n hn_ge_2 hP h_small lemma pred_sq_ge (p : ℕ) (hp : 3 ≤ p) : p ≤ (p - 1) ^ 2 := by have h₁ : p ≤ (p - 1) ^ 2 := by cases p with | zero => exfalso linarith | succ p' => cases p' with | zero => exfalso linarith | succ p'' => cases p'' with | zero => exfalso linarith | succ p''' => simp_all [Nat.succ_eq_add_one, Nat.pow_succ, Nat.mul_sub_left_distrib, Nat.mul_sub_right_distrib, Nat.add_assoc] <;> ring_nf at * <;> nlinarith exact h₁ lemma odd_prime_pow_le_totient_sq (p k : ℕ) (hp : Nat.Prime p) (hodd : p ≠ 2) (hk : 1 ≤ k) : p ^ k ≤ (p ^ k).totient ^ 2 := by obtain ⟨m, rfl⟩ : ∃ m, k = m + 1 := Nat.exists_eq_succ_of_ne_zero (by omega) rw [Nat.totient_prime_pow_succ hp, mul_pow] have hp3 : 3 ≤ p := by have := hp.two_le omega calc p ^ (m + 1) = p ^ m * p := pow_succ p m _ ≤ p ^ m * (p - 1) ^ 2 := Nat.mul_le_mul_left _ (pred_sq_ge p hp3) _ ≤ (p ^ m) ^ 2 * (p - 1) ^ 2 := by apply Nat.mul_le_mul_right exact Nat.le_self_pow (by omega) _ lemma ordCompl_lt_of_dvd (n p : ℕ) (hn : 0 < n) (hp : Nat.Prime p) (hdvd : p ∣ n) : n / p ^ n.factorization p < n := by apply Nat.div_lt_self hn have hpos : 0 < n.factorization p := hp.factorization_pos_of_dvd (by omega) hdvd exact one_lt_pow' hp.one_lt (by omega) lemma not_two_dvd_of_dvd_odd (n d : ℕ) (hodd : ¬ 2 ∣ n) (hdvd : d ∣ n) : ¬ 2 ∣ d := by intro h have h₁ : 2 ∣ d := h have h₂ : 2 ∣ n := dvd_trans h₁ hdvd contradiction lemma totient_sq_mul_of_coprime (a b : ℕ) (hcop : a.Coprime b) (ha : a ≤ a.totient ^ 2) (hb : b ≤ b.totient ^ 2) : a * b ≤ (a * b).totient ^ 2 := by have h₁ : (a * b).totient = a.totient * b.totient := Nat.totient_mul hcop have h₃ : (a.totient * b.totient) ^ 2 = a.totient ^ 2 * b.totient ^ 2 := by nlinarith have h₄ : a * b ≤ a.totient ^ 2 * b.totient ^ 2 := by nlinarith have h₅ : a * b ≤ (a * b).totient ^ 2 := by simp_all exact h₅ lemma odd_le_totient_sq (n : ℕ) (hn : 1 ≤ n) (hodd : ¬ 2 ∣ n) : n ≤ n.totient ^ 2 := by induction n using Nat.strongRec' with | _ n ih => obtain rfl | hn2 := eq_or_lt_of_le hn · simp [Nat.totient_one] · set p := n.minFac with hp_def have hp : p.Prime := Nat.minFac_prime (by omega) have hpdvd : p ∣ n := Nat.minFac_dvd n have hpodd : p ≠ 2 := fun heq => hodd (heq ▸ hpdvd) set v := n.factorization p set m := n / p ^ v have hm_lt : m < n := ordCompl_lt_of_dvd n p (by omega) hp hpdvd have hm_pos : 0 < m := Nat.ordCompl_pos p (by omega) have hm_odd : ¬ 2 ∣ m := not_two_dvd_of_dvd_odd n m hodd (Nat.ordCompl_dvd n p) have hn_eq : p ^ v * m = n := Nat.ordProj_mul_ordCompl_eq_self n p have hv_pos : 1 ≤ v := hp.factorization_pos_of_dvd (by omega) hpdvd have hcop : (p ^ v).Coprime m := (Nat.coprime_pow_left_iff hv_pos p m).mpr (Nat.coprime_ordCompl hp (by omega)) have hpv : p ^ v ≤ (p ^ v).totient ^ 2 := odd_prime_pow_le_totient_sq p v hp hpodd hv_pos have hm_ih : m ≤ m.totient ^ 2 := ih m hm_lt hm_pos hm_odd calc n = p ^ v * m := hn_eq.symm _ ≤ (p ^ v * m).totient ^ 2 := totient_sq_mul_of_coprime _ _ hcop hpv hm_ih _ = n.totient ^ 2 := by rw [hn_eq] lemma pow_two_le_two_mul_totient_sq (k : ℕ) (hk : 1 ≤ k) : 2 ^ k ≤ 2 * (2 ^ k).totient ^ 2 := by have h₁ : (2 ^ k).totient = 2 ^ (k - 1) := by have h₂ : (2 ^ k).totient = 2 ^ (k - 1) := by rw [Nat.totient_prime_pow (by decide : Nat.Prime 2)] <;> cases k with | zero => contradiction | succ k => simp [Nat.succ_eq_add_one, pow_add, pow_one, mul_comm] exact h₂ rw [h₁] have h₂ : 2 ^ k ≤ 2 * (2 ^ (k - 1)) ^ 2 := by have h₃ : k ≥ 1 := hk have h₄ : 2 ^ k ≤ 2 * (2 ^ (k - 1)) ^ 2 := by have h₅ : ∀ n : ℕ, n ≥ 1 → 2 ^ n ≤ 2 * (2 ^ (n - 1)) ^ 2 := by intro n hn induction' hn with n hn IH · norm_num · cases n with | zero => norm_num at hn | succ n => simp_all [Nat.pow_succ, Nat.mul_assoc] <;> nlinarith [pow_pos (by norm_num : (0 : ℕ) < 2) n] exact h₅ k h₃ exact h₄ exact h₂ lemma totient_sq_lower_bound (n : ℕ) (hn : 1 ≤ n) : n ≤ 2 * n.totient ^ 2 := by set v := n.factorization 2 with hv_def set m := n / 2 ^ v with hm_def have hn_eq : 2 ^ v * m = n := Nat.ordProj_mul_ordCompl_eq_self n 2 have hn0 : n ≠ 0 := by omega have hm_odd : ¬ 2 ∣ m := Nat.not_dvd_ordCompl Nat.prime_two hn0 have hm_pos : 1 ≤ m := by by_contra h push_neg at h interval_cases m simp at hn_eq; omega rcases v.eq_zero_or_pos with hv0 | hv_pos · rw [hv0] at hn_eq simp at hn_eq rw [← hn_eq] have := odd_le_totient_sq m hm_pos hm_odd linarith [Nat.totient_pos.mpr (by omega : 0 < m)] · have h2v := pow_two_le_two_mul_totient_sq v hv_pos have hm_bound := odd_le_totient_sq m hm_pos hm_odd have hsuper := Nat.totient_super_multiplicative (2 ^ v) m rw [hn_eq] at hsuper have : n = 2 ^ v * m := hn_eq.symm calc n = 2 ^ v * m := this _ ≤ (2 * (2 ^ v).totient ^ 2) * m.totient ^ 2 := by apply Nat.mul_le_mul h2v hm_bound _ = 2 * ((2 ^ v).totient * m.totient) ^ 2 := by ring _ ≤ 2 * n.totient ^ 2 := by apply Nat.mul_le_mul_left exact Nat.pow_le_pow_left hsuper 2 lemma totient_tendsto_atTop : ∀ K : ℕ, ∃ N : ℕ, ∀ n : ℕ, N ≤ n → K ≤ Nat.totient n := by intro K use 2 * K ^ 2 + 1 intro n hn by_contra h push_neg at h have hn1 : 1 ≤ n := by omega have hbound := totient_sq_lower_bound n hn1 have hlt : n.totient ≤ K - 1 := by omega have hsq : n.totient ^ 2 ≤ (K - 1) ^ 2 := Nat.pow_le_pow_left hlt 2 have : (K - 1) ^ 2 < K ^ 2 := by rcases K with _ | K · omega · simp; nlinarith [Nat.pos_of_ne_zero (by omega : K.succ ≠ 0)] nlinarith lemma totient_large_enough (η : ℝ) (hη_pos : 0 < η) : ∃ N : ℕ, ∀ n : ℕ, N ≤ n → 5 ≤ (η ^ 2 / 2 : ℝ) * (Nat.totient n : ℝ) := by obtain ⟨N, hN⟩ := totient_tendsto_atTop ⌈10 / η ^ 2⌉₊ exact ⟨N, fun n hn => by have h1 : (⌈10 / η ^ 2⌉₊ : ℝ) ≤ (Nat.totient n : ℝ) := by exact_mod_cast hN n hn have h2 : 10 / η ^ 2 ≤ (⌈10 / η ^ 2⌉₊ : ℝ) := Nat.le_ceil _ have hη2 : (0 : ℝ) < η ^ 2 := by positivity calc (5 : ℝ) = η ^ 2 / 2 * (10 / η ^ 2) := by field_simp; ring _ ≤ η ^ 2 / 2 * (Nat.totient n : ℝ) := by apply mul_le_mul_of_nonneg_left _ (by positivity) linarith⟩ lemma countingFunctionS_ge_five_outside_exceptional (η : ℝ) (θ : ℝ) (hη_pos : 0 < η) (hη_lt : η < 1 / 6) (hθ_pos : 0 < θ) (hθ_lt : θ < 1) : ∃ N₀ : ℕ, ∀ n : ℕ, N₀ ≤ n → (largestPrimeFactor n : ℝ) ≥ (n : ℝ) ^ θ → ∃ (exceptionalPairs : Set (ℤ × ℤ)), exceptionalPairs.Finite ∧ (exceptionalPairs.ncard : ℝ) ≤ (n : ℝ) ^ 2 * (1 / (n : ℝ) ^ θ + 1 / Real.log n) ∧ ∀ pq ∈ truncatedObtuseRegion n η, Int.gcd pq.2 (largestPrimeFactor n : ℤ) = 1 → pq ∉ exceptionalPairs → 5 ≤ countingFunctionS n pq.1 pq.2 := by obtain ⟨N₁, hN₁⟩ := exceptional_set_with_counting_bound η θ hη_pos hη_lt hθ_pos hθ_lt obtain ⟨N₂, hN₂⟩ := totient_large_enough η hη_pos refine ⟨max N₁ N₂, fun n hn hP => ?_⟩ have hn1 : N₁ ≤ n := le_of_max_le_left hn have hn2 : N₂ ≤ n := le_of_max_le_right hn obtain ⟨E, hEsub, hEfin, hEcard, hEprop⟩ := hN₁ n hn1 hP refine ⟨E, hEfin, hEcard, fun pq hpq hgcd hnotE => ?_⟩ have h_lower := hEprop pq hpq hgcd hnotE have h_totient := hN₂ n hn2 have h5 : (5 : ℝ) ≤ (countingFunctionS n pq.1 pq.2 : ℝ) := le_trans h_totient h_lower exact_mod_cast h5 lemma badPairsSet_ncard_upper_bound (η : ℝ) (θ : ℝ) (hη_pos : 0 < η) (hη_lt : η < 1 / 6) (hθ_pos : 0 < θ) (hθ_lt : θ < 1) : ∃ (C : ℝ) (N₂ : ℕ), 0 < C ∧ ∀ n : ℕ, N₂ ≤ n → (largestPrimeFactor n : ℝ) ≥ (n : ℝ) ^ θ → ((badPairsSet n η).ncard : ℝ) ≤ C * (n : ℝ) ^ 2 * (1 / (n : ℝ) ^ θ + 1 / Real.log n) := by obtain ⟨N₀, hN₀⟩ := countingFunctionS_ge_five_outside_exceptional η θ hη_pos hη_lt hθ_pos hθ_lt refine ⟨1, N₀, one_pos, fun n hn hP => ?_⟩ obtain ⟨E, hE_fin, hE_card, hE_good⟩ := hN₀ n hn hP have hbad_sub : badPairsSet n η ⊆ E := by intro pq hpq by_contra hpqE have hpq_mem := hpq.1 have hpq_gcd := hpq.2.1 have hpq_lt := hpq.2.2 have hge := hE_good pq hpq_mem hpq_gcd hpqE omega calc ((badPairsSet n η).ncard : ℝ) ≤ (E.ncard : ℝ) := by exact_mod_cast Set.ncard_le_ncard hbad_sub hE_fin _ ≤ (n : ℝ) ^ 2 * (1 / (n : ℝ) ^ θ + 1 / Real.log n) := hE_card _ = 1 * (n : ℝ) ^ 2 * (1 / (n : ℝ) ^ θ + 1 / Real.log n) := by ring lemma inv_rpow_tendsto_zero (θ : ℝ) (hθ_pos : 0 < θ) : Filter.Tendsto (fun n : ℕ => 1 / (n : ℝ) ^ θ) Filter.atTop (nhds 0) := by have h1 : Filter.Tendsto (fun n : ℕ => (n : ℝ)) Filter.atTop Filter.atTop := by simpa using tendsto_natCast_atTop_atTop have h2 : Filter.Tendsto (fun x : ℝ => x ^ θ) Filter.atTop Filter.atTop := by apply tendsto_rpow_atTop linarith have h3 : Filter.Tendsto (fun n : ℕ => (n : ℝ) ^ θ) Filter.atTop Filter.atTop := by have h4 : Filter.Tendsto (fun n : ℕ => (n : ℝ)) Filter.atTop Filter.atTop := h1 have h5 : Filter.Tendsto (fun x : ℝ => x ^ θ) Filter.atTop Filter.atTop := h2 have h6 : Filter.Tendsto (fun n : ℕ => (n : ℝ)) Filter.atTop Filter.atTop := h4 have h7 : Filter.Tendsto (fun x : ℝ => x ^ θ) Filter.atTop Filter.atTop := h5 have h8 : Filter.Tendsto (fun n : ℕ => (n : ℝ) ^ θ) Filter.atTop Filter.atTop := h7.comp h6 exact h8 have h4 : Filter.Tendsto (fun n : ℕ => 1 / (n : ℝ) ^ θ) Filter.atTop (nhds 0) := by have h5 : Filter.Tendsto (fun n : ℕ => (n : ℝ) ^ θ) Filter.atTop Filter.atTop := h3 have h6 : Filter.Tendsto (fun n : ℕ => (1 : ℝ) / (n : ℝ) ^ θ) Filter.atTop (nhds 0) := by have h7 : Filter.Tendsto (fun n : ℕ => (n : ℝ) ^ θ) Filter.atTop Filter.atTop := h5 have h8 : Filter.Tendsto (fun x : ℝ => (1 : ℝ) / x) (Filter.atTop : Filter ℝ) (nhds 0) := by have h9 : Filter.Tendsto (fun x : ℝ => (1 : ℝ) / x) (Filter.atTop : Filter ℝ) (nhds 0) := by simpa using tendsto_inv_atTop_zero exact h9 have h9 : Filter.Tendsto (fun n : ℕ => (n : ℝ) ^ θ) Filter.atTop Filter.atTop := h7 have h10 : Filter.Tendsto (fun x : ℝ => (1 : ℝ) / x) (Filter.atTop : Filter ℝ) (nhds 0) := h8 have h11 : Filter.Tendsto (fun n : ℕ => (1 : ℝ) / (n : ℝ) ^ θ) Filter.atTop (nhds 0) := h10.comp (h9) exact h11 exact h6 exact h4 lemma dist_to_ineq (θ : ℝ) (hθ_pos : 0 < θ) (ε : ℝ) (hε : 0 < ε) : (∃ N : ℕ, ∀ n : ℕ, N ≤ n → dist (1 / (n : ℝ) ^ θ) 0 < ε) → ∃ N : ℕ, ∀ n : ℕ, N ≤ n → 1 / (n : ℝ) ^ θ < ε := by intro h have h_main : ∀ (n : ℕ), 1 / (n : ℝ) ^ θ ≥ 0 := by intro n by_cases hn : n = 0 · rw [hn] simp [hθ_pos.le] <;> positivity · have h₃ : 1 / (n : ℝ) ^ θ ≥ 0 := by positivity exact h₃ have h_dist_eq : ∀ (n : ℕ), dist (1 / (n : ℝ) ^ θ) 0 = 1 / (n : ℝ) ^ θ := by intro n have h₁ : 1 / (n : ℝ) ^ θ ≥ 0 := h_main n have h₂ : dist (1 / (n : ℝ) ^ θ) 0 = |(1 / (n : ℝ) ^ θ : ℝ)| := by simp [Real.dist_eq, abs_sub_comm] rw [h₂] have h₃ : |(1 / (n : ℝ) ^ θ : ℝ)| = 1 / (n : ℝ) ^ θ := by rw [abs_of_nonneg h₁] rw [h₃] have h_final : ∃ N : ℕ, ∀ n : ℕ, N ≤ n → 1 / (n : ℝ) ^ θ < ε := by obtain ⟨N, hN⟩ := h refine' ⟨N, fun n hn => _⟩ have h₁ : dist (1 / (n : ℝ) ^ θ) 0 < ε := hN n hn have h₂ : dist (1 / (n : ℝ) ^ θ) 0 = 1 / (n : ℝ) ^ θ := h_dist_eq n rw [h₂] at h₁ exact h₁ exact h_final lemma inv_rpow_eventually_lt (θ : ℝ) (hθ_pos : 0 < θ) : ∀ ε : ℝ, 0 < ε → ∃ N : ℕ, ∀ n : ℕ, N ≤ n → 1 / (n : ℝ) ^ θ < ε := by intro ε hε have htendsto := inv_rpow_tendsto_zero θ hθ_pos rw [Metric.tendsto_atTop] at htendsto exact dist_to_ineq θ hθ_pos ε hε (htendsto ε hε) lemma inv_log_eventually_lt : ∀ ε : ℝ, 0 < ε → ∃ N : ℕ, ∀ n : ℕ, N ≤ n → 1 / Real.log n < ε := by intro ε hε have h₁ : Filter.Tendsto (fun n : ℕ => (1 : ℝ) / Real.log n) Filter.atTop (nhds 0) := by have h₂ : Filter.Tendsto (fun n : ℕ => (n : ℝ)) Filter.atTop Filter.atTop := by simpa using tendsto_natCast_atTop_atTop have h₃ : Filter.Tendsto (fun x : ℝ => Real.log x) Filter.atTop Filter.atTop := Real.tendsto_log_atTop have h₄ : Filter.Tendsto (fun n : ℕ => Real.log (n : ℝ)) Filter.atTop Filter.atTop := by have h₅ : Filter.Tendsto (fun n : ℕ => (n : ℝ)) Filter.atTop Filter.atTop := h₂ have h₆ : Filter.Tendsto (fun x : ℝ => Real.log x) Filter.atTop Filter.atTop := h₃ exact h₆.comp h₅ have h₅ : Filter.Tendsto (fun n : ℕ => (1 : ℝ) / Real.log n) Filter.atTop (nhds 0) := by have h₇ : Filter.Tendsto (fun n : ℕ => (1 : ℝ) / Real.log (n : ℝ)) Filter.atTop (nhds 0) := by have h₈ : Filter.Tendsto (fun n : ℕ => Real.log (n : ℝ)) Filter.atTop Filter.atTop := h₄ have h₉ : Filter.Tendsto (fun x : ℝ => (1 : ℝ) / x) Filter.atTop (nhds 0) := by simpa using tendsto_inv_atTop_zero have h₁₀ : Filter.Tendsto (fun n : ℕ => (1 : ℝ) / Real.log (n : ℝ)) Filter.atTop (nhds 0) := h₉.comp h₈ exact h₁₀ convert h₇ using 1 exact h₅ have h₂ : ∀ ε : ℝ, 0 < ε → (∃ N : ℕ, ∀ n : ℕ, N ≤ n → 1 / Real.log n < ε) := by intro ε hε have h₅ : ∃ (N : ℕ), ∀ (n : ℕ), N ≤ n → (1 : ℝ) / Real.log n < ε := by have h₆ : ∀ᶠ (n : ℕ) in Filter.atTop, (1 : ℝ) / Real.log n < ε := by have h₉ : ∀ᶠ (n : ℕ) in Filter.atTop, (1 : ℝ) / Real.log n < ε := by have h₁₃ : ∀ᶠ (n : ℕ) in Filter.atTop, (1 : ℝ) / Real.log n < ε := by have h₁₆ : ∀ᶠ (n : ℕ) in Filter.atTop, (1 : ℝ) / Real.log n ∈ Set.Iio ε := by have h₁₉ : Set.Iio ε ∈ nhds (0 : ℝ) := by apply Iio_mem_nhds linarith have h₂₀ : ∀ᶠ (n : ℕ) in Filter.atTop, (1 : ℝ) / Real.log n ∈ Set.Iio ε := by have h₂₁ : Filter.Tendsto (fun n : ℕ => (1 : ℝ) / Real.log n) Filter.atTop (nhds 0) := h₁ have h₂₂ : Set.Iio ε ∈ nhds (0 : ℝ) := h₁₉ exact h₂₁ h₂₂ exact h₂₀ have h₂₁ : ∀ᶠ (n : ℕ) in Filter.atTop, (1 : ℝ) / Real.log n ∈ Set.Iio ε := h₁₆ filter_upwards [h₂₁] with n hn exact hn exact h₁₃ exact h₉ have h₇ : ∃ (N : ℕ), ∀ (n : ℕ), N ≤ n → (1 : ℝ) / Real.log n < ε := by have h₈ : ∀ᶠ (n : ℕ) in Filter.atTop, (1 : ℝ) / Real.log n < ε := h₆ have h₉ : ∃ (N : ℕ), ∀ (n : ℕ), N ≤ n → (1 : ℝ) / Real.log n < ε := by have h₁₀ : ∃ (N : ℕ), ∀ (n : ℕ), N ≤ n → (1 : ℝ) / Real.log n < ε := by simp only [Filter.eventually_atTop] at h₈ obtain ⟨N, hN⟩ := h₈ refine' ⟨N, _⟩ intro n hn exact hN n hn exact h₁₀ exact h₉ exact h₇ exact h₅ exact h₂ ε hε lemma asymptotic_decay (θ : ℝ) (hθ_pos : 0 < θ) : ∀ ε : ℝ, 0 < ε → ∃ N : ℕ, ∀ n : ℕ, N ≤ n → 1 / (n : ℝ) ^ θ + 1 / Real.log n < ε := by intro ε hε have hε2 : 0 < ε / 2 := by linarith obtain ⟨N₁, hN₁⟩ := inv_rpow_eventually_lt θ hθ_pos (ε / 2) hε2 obtain ⟨N₂, hN₂⟩ := inv_log_eventually_lt (ε / 2) hε2 exact ⟨max N₁ N₂, fun n hn => by have h1 := hN₁ n (le_of_max_le_left hn) have h2 := hN₂ n (le_of_max_le_right hn) linarith⟩ lemma ratio_bound_core (bad Hn c C n2 decay ε : ℝ) (hc_pos : 0 < c) (hC_pos : 0 < C) (hε_pos : 0 < ε) (hn2_pos : 0 < n2) (h_bad_nonneg : 0 ≤ bad) (h_upper : bad ≤ C * n2 * decay) (h_lower : c * n2 ≤ Hn) (h_decay : decay < c * ε / C) : bad / Hn < ε := by have h_C_decay_lt_cε : C * decay < c * ε := by exact (lt_div_iff₀' hC_pos).mp h_decay have h_Cn2_decay_lt_cεn2 : C * n2 * decay < c * ε * n2 := by nlinarith have h_cεn2_le_εHn : c * ε * n2 ≤ ε * Hn := by nlinarith have h_bad_lt_εHn : bad < ε * Hn := by nlinarith have h_Hn_pos : 0 < Hn := by nlinarith exact (div_lt_iff₀ h_Hn_pos).mpr h_bad_lt_εHn lemma ratio_bound_from_three_lemmas (c C : ℝ) (N₁ N₂ : ℕ) (η θ : ℝ) (hc_pos : 0 < c) (hC_pos : 0 < C) (h_lower : ∀ n : ℕ, N₁ ≤ n → c * (n : ℝ) ^ 2 ≤ ((truncatedObtuseRegion n η).ncard : ℝ)) (h_upper : ∀ n : ℕ, N₂ ≤ n → (largestPrimeFactor n : ℝ) ≥ (n : ℝ) ^ θ → ((badPairsSet n η).ncard : ℝ) ≤ C * (n : ℝ) ^ 2 * (1 / (n : ℝ) ^ θ + 1 / Real.log n)) (hη_pos : 0 < η) (hη_lt : η < 1 / 6) (hθ_pos : 0 < θ) : ∀ ε : ℝ, 0 < ε → ∃ N₀ : ℕ, ∀ n : ℕ, N₀ ≤ n → (largestPrimeFactor n : ℝ) ≥ (n : ℝ) ^ θ → ((badPairsSet n η).ncard : ℝ) / ((truncatedObtuseRegion n η).ncard : ℝ) < ε := by intro ε hε_pos have hδ_pos : 0 < c * ε / C := by positivity obtain ⟨N₃, hN₃⟩ := asymptotic_decay θ hθ_pos (c * ε / C) hδ_pos refine ⟨max N₁ (max N₂ (max N₃ 1)), fun n hn hP => ?_⟩ have hn_N₁ : N₁ ≤ n := le_trans (le_max_left _ _) hn have hn_N₂ : N₂ ≤ n := le_trans (le_trans (le_max_left _ _) (le_max_right _ _)) hn have hn_N₃ : N₃ ≤ n := le_trans (le_trans (le_max_left _ _) (le_max_right _ _)) (le_trans (le_max_right N₁ _) hn) have hn_ge_one : 1 ≤ n := le_trans (le_trans (le_max_right _ _) (le_max_right _ _)) (le_trans (le_max_right N₁ _) hn) have hn_pos : 0 < (n : ℝ) := by exact_mod_cast (show 0 < n by omega) have hn2_pos : 0 < (n : ℝ) ^ 2 := pow_pos hn_pos 2 have h_low := h_lower n hn_N₁ have h_up := h_upper n hn_N₂ hP have h_dec := hN₃ n hn_N₃ have h_bad_nonneg : (0 : ℝ) ≤ ((badPairsSet n η).ncard : ℝ) := Nat.cast_nonneg _ exact ratio_bound_core ((badPairsSet n η).ncard : ℝ) ((truncatedObtuseRegion n η).ncard : ℝ) c C ((n : ℝ) ^ 2) (1 / (n : ℝ) ^ θ + 1 / Real.log n) ε hc_pos hC_pos hε_pos hn2_pos h_bad_nonneg h_up h_low h_dec theorem analyticEngine_lower_bound (η : ℝ) (θ : ℝ) (hη_pos : 0 < η) (hη_lt : η < 1 / 6) (hθ_pos : 0 < θ) (hθ_lt : θ < 1) : ∀ ε : ℝ, 0 < ε → ∃ N₀ : ℕ, ∀ n : ℕ, N₀ ≤ n → (largestPrimeFactor n : ℝ) ≥ (n : ℝ) ^ θ → ((badPairsSet n η).ncard : ℝ) / ((truncatedObtuseRegion n η).ncard : ℝ) < ε := by obtain ⟨c, N₁, hc_pos, h_lower⟩ := truncatedObtuseRegion_ncard_lower_bound η hη_pos hη_lt obtain ⟨C, N₂, hC_pos, h_upper⟩ := badPairsSet_ncard_upper_bound η θ hη_pos hη_lt hθ_pos hθ_lt exact ratio_bound_from_three_lemmas c C N₁ N₂ η θ hc_pos hC_pos h_lower h_upper hη_pos hη_lt hθ_pos