|
| 1 | +/- |
| 2 | +Copyright (c) 2018 Chris Hughes. All rights reserved. |
| 3 | +Released under Apache 2.0 license as described in the file LICENSE. |
| 4 | +Authors: Chris Hughes |
| 5 | +-/ |
| 6 | +import field_theory.finite.basic |
| 7 | +import data.zmod.basic |
| 8 | + |
| 9 | +/-! |
| 10 | +# Lemmas of Gauss and Eisenstein |
| 11 | +
|
| 12 | +This file contains code for the proof of the Lemmas of Gauss and Eisenstein |
| 13 | +on the Legendre symbol. The main results are `gauss_lemma_aux` and |
| 14 | +`eisenstein_lemma_aux`; they are used in `quadratic_reciprocity.lean` |
| 15 | +to prove `gauss_lemma` and `eisenstein_lemma`, respectively. |
| 16 | +-/ |
| 17 | + |
| 18 | +open function finset nat finite_field zmod |
| 19 | +open_locale big_operators nat |
| 20 | + |
| 21 | +namespace zmod |
| 22 | + |
| 23 | +section wilson |
| 24 | + |
| 25 | +variables (p : ℕ) [fact p.prime] |
| 26 | + |
| 27 | +-- One can probably deduce the following from `finite_field.prod_univ_units_id_eq_neg_one` |
| 28 | +/-- **Wilson's Lemma**: the product of `1`, ..., `p-1` is `-1` modulo `p`. -/ |
| 29 | +@[simp] lemma wilsons_lemma : ((p - 1)! : zmod p) = -1 := |
| 30 | +begin |
| 31 | + refine |
| 32 | + calc ((p - 1)! : zmod p) = (∏ x in Ico 1 (succ (p - 1)), x) : |
| 33 | + by rw [← finset.prod_Ico_id_eq_factorial, prod_nat_cast] |
| 34 | + ... = (∏ x : (zmod p)ˣ, x) : _ |
| 35 | + ... = -1 : by simp_rw [← units.coe_hom_apply, |
| 36 | + ← (units.coe_hom (zmod p)).map_prod, prod_univ_units_id_eq_neg_one, units.coe_hom_apply, |
| 37 | + units.coe_neg, units.coe_one], |
| 38 | + have hp : 0 < p := (fact.out p.prime).pos, |
| 39 | + symmetry, |
| 40 | + refine prod_bij (λ a _, (a : zmod p).val) _ _ _ _, |
| 41 | + { intros a ha, |
| 42 | + rw [mem_Ico, ← nat.succ_sub hp, nat.succ_sub_one], |
| 43 | + split, |
| 44 | + { apply nat.pos_of_ne_zero, rw ← @val_zero p, |
| 45 | + assume h, apply units.ne_zero a (val_injective p h) }, |
| 46 | + { exact val_lt _ } }, |
| 47 | + { intros a ha, simp only [cast_id, nat_cast_val], }, |
| 48 | + { intros _ _ _ _ h, rw units.ext_iff, exact val_injective p h }, |
| 49 | + { intros b hb, |
| 50 | + rw [mem_Ico, nat.succ_le_iff, ← succ_sub hp, succ_sub_one, pos_iff_ne_zero] at hb, |
| 51 | + refine ⟨units.mk0 b _, finset.mem_univ _, _⟩, |
| 52 | + { assume h, apply hb.1, apply_fun val at h, |
| 53 | + simpa only [val_cast_of_lt hb.right, val_zero] using h }, |
| 54 | + { simp only [val_cast_of_lt hb.right, units.coe_mk0], } } |
| 55 | +end |
| 56 | + |
| 57 | +@[simp] lemma prod_Ico_one_prime : (∏ x in Ico 1 p, (x : zmod p)) = -1 := |
| 58 | +begin |
| 59 | + conv in (Ico 1 p) { rw [← succ_sub_one p, succ_sub (fact.out p.prime).pos] }, |
| 60 | + rw [← prod_nat_cast, finset.prod_Ico_id_eq_factorial, wilsons_lemma] |
| 61 | +end |
| 62 | + |
| 63 | +end wilson |
| 64 | + |
| 65 | +end zmod |
| 66 | + |
| 67 | +section gauss_eisenstein |
| 68 | + |
| 69 | +namespace legendre_symbol |
| 70 | + |
| 71 | +/-- The image of the map sending a non zero natural number `x ≤ p / 2` to the absolute value |
| 72 | + of the element of interger in the interval `(-p/2, p/2]` congruent to `a * x` mod p is the set |
| 73 | + of non zero natural numbers `x` such that `x ≤ p / 2` -/ |
| 74 | +lemma Ico_map_val_min_abs_nat_abs_eq_Ico_map_id |
| 75 | + (p : ℕ) [hp : fact p.prime] (a : zmod p) (hap : a ≠ 0) : |
| 76 | + (Ico 1 (p / 2).succ).1.map (λ x, (a * x).val_min_abs.nat_abs) = |
| 77 | + (Ico 1 (p / 2).succ).1.map (λ a, a) := |
| 78 | +begin |
| 79 | + have he : ∀ {x}, x ∈ Ico 1 (p / 2).succ → x ≠ 0 ∧ x ≤ p / 2, |
| 80 | + by simp [nat.lt_succ_iff, nat.succ_le_iff, pos_iff_ne_zero] {contextual := tt}, |
| 81 | + have hep : ∀ {x}, x ∈ Ico 1 (p / 2).succ → x < p, |
| 82 | + from λ x hx, lt_of_le_of_lt (he hx).2 (nat.div_lt_self hp.1.pos dec_trivial), |
| 83 | + have hpe : ∀ {x}, x ∈ Ico 1 (p / 2).succ → ¬ p ∣ x, |
| 84 | + from λ x hx hpx, not_lt_of_ge (le_of_dvd (nat.pos_of_ne_zero (he hx).1) hpx) (hep hx), |
| 85 | + have hmem : ∀ (x : ℕ) (hx : x ∈ Ico 1 (p / 2).succ), |
| 86 | + (a * x : zmod p).val_min_abs.nat_abs ∈ Ico 1 (p / 2).succ, |
| 87 | + { assume x hx, |
| 88 | + simp [hap, char_p.cast_eq_zero_iff (zmod p) p, hpe hx, lt_succ_iff, succ_le_iff, |
| 89 | + pos_iff_ne_zero, nat_abs_val_min_abs_le _], }, |
| 90 | + have hsurj : ∀ (b : ℕ) (hb : b ∈ Ico 1 (p / 2).succ), |
| 91 | + ∃ x ∈ Ico 1 (p / 2).succ, b = (a * x : zmod p).val_min_abs.nat_abs, |
| 92 | + { assume b hb, |
| 93 | + refine ⟨(b / a : zmod p).val_min_abs.nat_abs, mem_Ico.mpr ⟨_, _⟩, _⟩, |
| 94 | + { apply nat.pos_of_ne_zero, |
| 95 | + simp only [div_eq_mul_inv, hap, char_p.cast_eq_zero_iff (zmod p) p, hpe hb, not_false_iff, |
| 96 | + val_min_abs_eq_zero, inv_eq_zero, int.nat_abs_eq_zero, ne.def, mul_eq_zero, or_self] }, |
| 97 | + { apply lt_succ_of_le, apply nat_abs_val_min_abs_le }, |
| 98 | + { rw nat_cast_nat_abs_val_min_abs, |
| 99 | + split_ifs, |
| 100 | + { erw [mul_div_cancel' _ hap, val_min_abs_def_pos, val_cast_of_lt (hep hb), |
| 101 | + if_pos (le_of_lt_succ (mem_Ico.1 hb).2), int.nat_abs_of_nat], }, |
| 102 | + { erw [mul_neg, mul_div_cancel' _ hap, nat_abs_val_min_abs_neg, |
| 103 | + val_min_abs_def_pos, val_cast_of_lt (hep hb), if_pos (le_of_lt_succ (mem_Ico.1 hb).2), |
| 104 | + int.nat_abs_of_nat] } } }, |
| 105 | + exact multiset.map_eq_map_of_bij_of_nodup _ _ (finset.nodup _) (finset.nodup _) |
| 106 | + (λ x _, (a * x : zmod p).val_min_abs.nat_abs) hmem (λ _ _, rfl) |
| 107 | + (inj_on_of_surj_on_of_card_le _ hmem hsurj le_rfl) hsurj |
| 108 | +end |
| 109 | + |
| 110 | +private lemma gauss_lemma_aux₁ (p : ℕ) [fact p.prime] [fact (p % 2 = 1)] |
| 111 | + {a : ℤ} (hap : (a : zmod p) ≠ 0) : |
| 112 | + (a^(p / 2) * (p / 2)! : zmod p) = |
| 113 | + (-1)^((Ico 1 (p / 2).succ).filter |
| 114 | + (λ x : ℕ, ¬(a * x : zmod p).val ≤ p / 2)).card * (p / 2)! := |
| 115 | +calc (a ^ (p / 2) * (p / 2)! : zmod p) = |
| 116 | + (∏ x in Ico 1 (p / 2).succ, a * x) : |
| 117 | + by rw [prod_mul_distrib, ← prod_nat_cast, prod_Ico_id_eq_factorial, |
| 118 | + prod_const, card_Ico, succ_sub_one]; simp |
| 119 | +... = (∏ x in Ico 1 (p / 2).succ, (a * x : zmod p).val) : by simp |
| 120 | +... = (∏ x in Ico 1 (p / 2).succ, |
| 121 | + (if (a * x : zmod p).val ≤ p / 2 then 1 else -1) * |
| 122 | + (a * x : zmod p).val_min_abs.nat_abs) : |
| 123 | + prod_congr rfl $ λ _ _, begin |
| 124 | + simp only [nat_cast_nat_abs_val_min_abs], |
| 125 | + split_ifs; simp |
| 126 | + end |
| 127 | +... = (-1)^((Ico 1 (p / 2).succ).filter |
| 128 | + (λ x : ℕ, ¬(a * x : zmod p).val ≤ p / 2)).card * |
| 129 | + (∏ x in Ico 1 (p / 2).succ, (a * x : zmod p).val_min_abs.nat_abs) : |
| 130 | + have (∏ x in Ico 1 (p / 2).succ, |
| 131 | + if (a * x : zmod p).val ≤ p / 2 then (1 : zmod p) else -1) = |
| 132 | + (∏ x in (Ico 1 (p / 2).succ).filter |
| 133 | + (λ x : ℕ, ¬(a * x : zmod p).val ≤ p / 2), -1), |
| 134 | + from prod_bij_ne_one (λ x _ _, x) |
| 135 | + (λ x, by split_ifs; simp * at * {contextual := tt}) |
| 136 | + (λ _ _ _ _ _ _, id) |
| 137 | + (λ b h _, ⟨b, by simp [-not_le, *] at *⟩) |
| 138 | + (by intros; split_ifs at *; simp * at *), |
| 139 | + by rw [prod_mul_distrib, this]; simp |
| 140 | +... = (-1)^((Ico 1 (p / 2).succ).filter |
| 141 | + (λ x : ℕ, ¬(a * x : zmod p).val ≤ p / 2)).card * (p / 2)! : |
| 142 | + by rw [← prod_nat_cast, finset.prod_eq_multiset_prod, |
| 143 | + Ico_map_val_min_abs_nat_abs_eq_Ico_map_id p a hap, |
| 144 | + ← finset.prod_eq_multiset_prod, prod_Ico_id_eq_factorial] |
| 145 | + |
| 146 | +lemma gauss_lemma_aux (p : ℕ) [hp : fact p.prime] [fact (p % 2 = 1)] |
| 147 | + {a : ℤ} (hap : (a : zmod p) ≠ 0) : |
| 148 | + (a^(p / 2) : zmod p) = (-1)^((Ico 1 (p / 2).succ).filter |
| 149 | + (λ x : ℕ, p / 2 < (a * x : zmod p).val)).card := |
| 150 | +(mul_left_inj' |
| 151 | + (show ((p / 2)! : zmod p) ≠ 0, |
| 152 | + by rw [ne.def, char_p.cast_eq_zero_iff (zmod p) p, hp.1.dvd_factorial, not_le]; |
| 153 | + exact nat.div_lt_self hp.1.pos dec_trivial)).1 $ |
| 154 | + by simpa using gauss_lemma_aux₁ p hap |
| 155 | + |
| 156 | +private lemma eisenstein_lemma_aux₁ (p : ℕ) [fact p.prime] [hp2 : fact (p % 2 = 1)] |
| 157 | + {a : ℕ} (hap : (a : zmod p) ≠ 0) : |
| 158 | + ((∑ x in Ico 1 (p / 2).succ, a * x : ℕ) : zmod 2) = |
| 159 | + ((Ico 1 (p / 2).succ).filter |
| 160 | + ((λ x : ℕ, p / 2 < (a * x : zmod p).val))).card + |
| 161 | + ∑ x in Ico 1 (p / 2).succ, x |
| 162 | + + (∑ x in Ico 1 (p / 2).succ, (a * x) / p : ℕ) := |
| 163 | +have hp2 : (p : zmod 2) = (1 : ℕ), from (eq_iff_modeq_nat _).2 hp2.1, |
| 164 | +calc ((∑ x in Ico 1 (p / 2).succ, a * x : ℕ) : zmod 2) |
| 165 | + = ((∑ x in Ico 1 (p / 2).succ, ((a * x) % p + p * ((a * x) / p)) : ℕ) : zmod 2) : |
| 166 | + by simp only [mod_add_div] |
| 167 | +... = (∑ x in Ico 1 (p / 2).succ, ((a * x : ℕ) : zmod p).val : ℕ) + |
| 168 | + (∑ x in Ico 1 (p / 2).succ, (a * x) / p : ℕ) : |
| 169 | + by simp only [val_nat_cast]; |
| 170 | + simp [sum_add_distrib, mul_sum.symm, nat.cast_add, nat.cast_mul, nat.cast_sum, hp2] |
| 171 | +... = _ : congr_arg2 (+) |
| 172 | + (calc ((∑ x in Ico 1 (p / 2).succ, ((a * x : ℕ) : zmod p).val : ℕ) : zmod 2) |
| 173 | + = ∑ x in Ico 1 (p / 2).succ, |
| 174 | + ((((a * x : zmod p).val_min_abs + |
| 175 | + (if (a * x : zmod p).val ≤ p / 2 then 0 else p)) : ℤ) : zmod 2) : |
| 176 | + by simp only [(val_eq_ite_val_min_abs _).symm]; simp [nat.cast_sum] |
| 177 | + ... = ((Ico 1 (p / 2).succ).filter |
| 178 | + (λ x : ℕ, p / 2 < (a * x : zmod p).val)).card + |
| 179 | + ((∑ x in Ico 1 (p / 2).succ, (a * x : zmod p).val_min_abs.nat_abs) : ℕ) : |
| 180 | + by { simp [ite_cast, add_comm, sum_add_distrib, finset.sum_ite, hp2, nat.cast_sum], } |
| 181 | + ... = _ : by rw [finset.sum_eq_multiset_sum, |
| 182 | + Ico_map_val_min_abs_nat_abs_eq_Ico_map_id p a hap, |
| 183 | + ← finset.sum_eq_multiset_sum]; |
| 184 | + simp [nat.cast_sum]) rfl |
| 185 | + |
| 186 | +lemma eisenstein_lemma_aux (p : ℕ) [fact p.prime] [fact (p % 2 = 1)] |
| 187 | + {a : ℕ} (ha2 : a % 2 = 1) (hap : (a : zmod p) ≠ 0) : |
| 188 | + ((Ico 1 (p / 2).succ).filter |
| 189 | + ((λ x : ℕ, p / 2 < (a * x : zmod p).val))).card |
| 190 | + ≡ ∑ x in Ico 1 (p / 2).succ, (x * a) / p [MOD 2] := |
| 191 | +have ha2 : (a : zmod 2) = (1 : ℕ), from (eq_iff_modeq_nat _).2 ha2, |
| 192 | +(eq_iff_modeq_nat 2).1 $ sub_eq_zero.1 $ |
| 193 | + by simpa [add_left_comm, sub_eq_add_neg, finset.mul_sum.symm, mul_comm, ha2, nat.cast_sum, |
| 194 | + add_neg_eq_iff_eq_add.symm, neg_eq_self_mod_two, add_assoc] |
| 195 | + using eq.symm (eisenstein_lemma_aux₁ p hap) |
| 196 | + |
| 197 | +lemma div_eq_filter_card {a b c : ℕ} (hb0 : 0 < b) (hc : a / b ≤ c) : a / b = |
| 198 | + ((Ico 1 c.succ).filter (λ x, x * b ≤ a)).card := |
| 199 | +calc a / b = (Ico 1 (a / b).succ).card : by simp |
| 200 | +... = ((Ico 1 c.succ).filter (λ x, x * b ≤ a)).card : |
| 201 | + congr_arg _ $ finset.ext $ λ x, |
| 202 | + have x * b ≤ a → x ≤ c, |
| 203 | + from λ h, le_trans (by rwa [le_div_iff_mul_le _ _ hb0]) hc, |
| 204 | + by simp [lt_succ_iff, le_div_iff_mul_le _ _ hb0]; tauto |
| 205 | + |
| 206 | +/-- The given sum is the number of integer points in the triangle formed by the diagonal of the |
| 207 | + rectangle `(0, p/2) × (0, q/2)` -/ |
| 208 | +private lemma sum_Ico_eq_card_lt {p q : ℕ} : |
| 209 | + ∑ a in Ico 1 (p / 2).succ, (a * q) / p = |
| 210 | + (((Ico 1 (p / 2).succ).product (Ico 1 (q / 2).succ)).filter |
| 211 | + (λ x : ℕ × ℕ, x.2 * p ≤ x.1 * q)).card := |
| 212 | +if hp0 : p = 0 then by simp [hp0, finset.ext_iff] |
| 213 | +else |
| 214 | + calc ∑ a in Ico 1 (p / 2).succ, (a * q) / p = |
| 215 | + ∑ a in Ico 1 (p / 2).succ, |
| 216 | + ((Ico 1 (q / 2).succ).filter (λ x, x * p ≤ a * q)).card : |
| 217 | + finset.sum_congr rfl $ λ x hx, |
| 218 | + div_eq_filter_card (nat.pos_of_ne_zero hp0) |
| 219 | + (calc x * q / p ≤ (p / 2) * q / p : |
| 220 | + nat.div_le_div_right (mul_le_mul_of_nonneg_right |
| 221 | + (le_of_lt_succ $ (mem_Ico.mp hx).2) |
| 222 | + (nat.zero_le _)) |
| 223 | + ... ≤ _ : nat.div_mul_div_le_div _ _ _) |
| 224 | + ... = _ : by rw [← card_sigma]; |
| 225 | + exact card_congr (λ a _, ⟨a.1, a.2⟩) |
| 226 | + (by simp only [mem_filter, mem_sigma, and_self, forall_true_iff, mem_product] |
| 227 | + {contextual := tt}) |
| 228 | + (λ ⟨_, _⟩ ⟨_, _⟩, by simp only [prod.mk.inj_iff, eq_self_iff_true, and_self, heq_iff_eq, |
| 229 | + forall_true_iff] {contextual := tt}) |
| 230 | + (λ ⟨b₁, b₂⟩ h, ⟨⟨b₁, b₂⟩, |
| 231 | + by revert h; simp only [mem_filter, eq_self_iff_true, exists_prop_of_true, mem_sigma, |
| 232 | + and_self, forall_true_iff, mem_product] {contextual := tt}⟩) |
| 233 | + |
| 234 | +/-- Each of the sums in this lemma is the cardinality of the set integer points in each of the |
| 235 | + two triangles formed by the diagonal of the rectangle `(0, p/2) × (0, q/2)`. Adding them |
| 236 | + gives the number of points in the rectangle. -/ |
| 237 | +lemma sum_mul_div_add_sum_mul_div_eq_mul (p q : ℕ) [hp : fact p.prime] |
| 238 | + (hq0 : (q : zmod p) ≠ 0) : |
| 239 | + ∑ a in Ico 1 (p / 2).succ, (a * q) / p + |
| 240 | + ∑ a in Ico 1 (q / 2).succ, (a * p) / q = |
| 241 | + (p / 2) * (q / 2) := |
| 242 | +begin |
| 243 | + have hswap : (((Ico 1 (q / 2).succ).product (Ico 1 (p / 2).succ)).filter |
| 244 | + (λ x : ℕ × ℕ, x.2 * q ≤ x.1 * p)).card = |
| 245 | + (((Ico 1 (p / 2).succ).product (Ico 1 (q / 2).succ)).filter |
| 246 | + (λ x : ℕ × ℕ, x.1 * q ≤ x.2 * p)).card := |
| 247 | + card_congr (λ x _, prod.swap x) |
| 248 | + (λ ⟨_, _⟩, by simp only [mem_filter, and_self, prod.swap_prod_mk, forall_true_iff, mem_product] |
| 249 | + {contextual := tt}) |
| 250 | + (λ ⟨_, _⟩ ⟨_, _⟩, by simp only [prod.mk.inj_iff, eq_self_iff_true, and_self, prod.swap_prod_mk, |
| 251 | + forall_true_iff] {contextual := tt}) |
| 252 | + (λ ⟨x₁, x₂⟩ h, ⟨⟨x₂, x₁⟩, by revert h; simp only [mem_filter, eq_self_iff_true, and_self, |
| 253 | + exists_prop_of_true, prod.swap_prod_mk, forall_true_iff, mem_product] {contextual := tt}⟩), |
| 254 | + have hdisj : disjoint |
| 255 | + (((Ico 1 (p / 2).succ).product (Ico 1 (q / 2).succ)).filter |
| 256 | + (λ x : ℕ × ℕ, x.2 * p ≤ x.1 * q)) |
| 257 | + (((Ico 1 (p / 2).succ).product (Ico 1 (q / 2).succ)).filter |
| 258 | + (λ x : ℕ × ℕ, x.1 * q ≤ x.2 * p)), |
| 259 | + { apply disjoint_filter.2 (λ x hx hpq hqp, _), |
| 260 | + have hxp : x.1 < p, from lt_of_le_of_lt |
| 261 | + (show x.1 ≤ p / 2, by simp only [*, lt_succ_iff, mem_Ico, mem_product] at *; tauto) |
| 262 | + (nat.div_lt_self hp.1.pos dec_trivial), |
| 263 | + have : (x.1 : zmod p) = 0, |
| 264 | + { simpa [hq0] using congr_arg (coe : ℕ → zmod p) (le_antisymm hpq hqp) }, |
| 265 | + apply_fun zmod.val at this, |
| 266 | + rw [val_cast_of_lt hxp, val_zero] at this, |
| 267 | + simpa only [this, nonpos_iff_eq_zero, mem_Ico, one_ne_zero, false_and, mem_product] using hx }, |
| 268 | + have hunion : ((Ico 1 (p / 2).succ).product (Ico 1 (q / 2).succ)).filter |
| 269 | + (λ x : ℕ × ℕ, x.2 * p ≤ x.1 * q) ∪ |
| 270 | + ((Ico 1 (p / 2).succ).product (Ico 1 (q / 2).succ)).filter |
| 271 | + (λ x : ℕ × ℕ, x.1 * q ≤ x.2 * p) = |
| 272 | + ((Ico 1 (p / 2).succ).product (Ico 1 (q / 2).succ)), |
| 273 | + from finset.ext (λ x, by have := le_total (x.2 * p) (x.1 * q); |
| 274 | + simp only [mem_union, mem_filter, mem_Ico, mem_product]; tauto), |
| 275 | + rw [sum_Ico_eq_card_lt, sum_Ico_eq_card_lt, hswap, ← card_disjoint_union hdisj, hunion, |
| 276 | + card_product], |
| 277 | + simp only [card_Ico, tsub_zero, succ_sub_succ_eq_sub] |
| 278 | +end |
| 279 | + |
| 280 | +end legendre_symbol |
| 281 | + |
| 282 | +end gauss_eisenstein |
0 commit comments