|
| 1 | +/- |
| 2 | +Copyright (c) 2022 John Nicol. All rights reserved. |
| 3 | +Released under Apache 2.0 license as described in the file LICENSE. |
| 4 | +Authors: John Nicol |
| 5 | +
|
| 6 | +! This file was ported from Lean 3 source module number_theory.wilson |
| 7 | +! leanprover-community/mathlib commit c471da714c044131b90c133701e51b877c246677 |
| 8 | +! Please do not edit these lines, except to modify the commit id |
| 9 | +! if you have ported upstream changes. |
| 10 | +-/ |
| 11 | +import Mathlib.FieldTheory.Finite.Basic |
| 12 | + |
| 13 | +/-! |
| 14 | +# Wilson's theorem. |
| 15 | +
|
| 16 | +This file contains a proof of Wilson's theorem. |
| 17 | +
|
| 18 | +The heavy lifting is mostly done by the previous `wilsons_lemma`, |
| 19 | +but here we also prove the other logical direction. |
| 20 | +
|
| 21 | +This could be generalized to similar results about finite abelian groups. |
| 22 | +
|
| 23 | +## References |
| 24 | +
|
| 25 | +* [Wilson's Theorem](https://en.wikipedia.org/wiki/Wilson%27s_theorem) |
| 26 | +
|
| 27 | +## TODO |
| 28 | +
|
| 29 | +* Give `wilsons_lemma` a descriptive name. |
| 30 | +-/ |
| 31 | + |
| 32 | + |
| 33 | +open Finset Nat FiniteField ZMod |
| 34 | + |
| 35 | +open scoped BigOperators Nat |
| 36 | + |
| 37 | +namespace ZMod |
| 38 | + |
| 39 | +variable (p : ℕ) [Fact p.Prime] |
| 40 | + |
| 41 | +/-- **Wilson's Lemma**: the product of `1`, ..., `p-1` is `-1` modulo `p`. -/ |
| 42 | +@[simp] |
| 43 | +theorem wilsons_lemma : ((p - 1)! : ZMod p) = -1 := by |
| 44 | + refine' |
| 45 | + calc |
| 46 | + ((p - 1)! : ZMod p) = ∏ x in Ico 1 (succ (p - 1)), (x : ZMod p) := by |
| 47 | + rw [← Finset.prod_Ico_id_eq_factorial, prod_natCast] |
| 48 | + _ = ∏ x : (ZMod p)ˣ, (x : ZMod p) := _ |
| 49 | + _ = -1 := by |
| 50 | + -- Porting note: `simp` is less powerful. |
| 51 | + -- simp_rw [← Units.coeHom_apply, ← (Units.coeHom (ZMod p)).map_prod, |
| 52 | + -- prod_univ_units_id_eq_neg_one, Units.coeHom_apply, Units.val_neg, Units.val_one] |
| 53 | + simp_rw [← Units.coeHom_apply] |
| 54 | + rw [← (Units.coeHom (ZMod p)).map_prod] |
| 55 | + simp_rw [prod_univ_units_id_eq_neg_one, Units.coeHom_apply, Units.val_neg, Units.val_one] |
| 56 | + have hp : 0 < p := (Fact.out (p := p.Prime)).pos |
| 57 | + symm |
| 58 | + refine' prod_bij (fun a _ => (a : ZMod p).val) _ _ _ _ |
| 59 | + · intro a ha |
| 60 | + rw [mem_Ico, ← Nat.succ_sub hp, Nat.succ_sub_one] |
| 61 | + constructor |
| 62 | + · apply Nat.pos_of_ne_zero; rw [← @val_zero p] |
| 63 | + intro h; apply Units.ne_zero a (val_injective p h) |
| 64 | + · exact val_lt _ |
| 65 | + · rintro a -; simp only [cast_id, nat_cast_val] |
| 66 | + · intro _ _ _ _ h; rw [Units.ext_iff]; exact val_injective p h |
| 67 | + · intro b hb |
| 68 | + rw [mem_Ico, Nat.succ_le_iff, ← succ_sub hp, succ_sub_one, pos_iff_ne_zero] at hb |
| 69 | + refine' ⟨Units.mk0 b _, Finset.mem_univ _, _⟩ |
| 70 | + · intro h; apply hb.1; apply_fun val at h |
| 71 | + simpa only [val_cast_of_lt hb.right, val_zero] using h |
| 72 | + · simp only [val_cast_of_lt hb.right, Units.val_mk0] |
| 73 | +#align zmod.wilsons_lemma ZMod.wilsons_lemma |
| 74 | + |
| 75 | +@[simp] |
| 76 | +theorem prod_Ico_one_prime : ∏ x in Ico 1 p, (x : ZMod p) = -1 := by |
| 77 | + -- Porting note: was `conv in Ico 1 p =>` |
| 78 | + conv => |
| 79 | + congr |
| 80 | + congr |
| 81 | + rw [← succ_sub_one p, succ_sub (Fact.out (p := p.Prime)).pos] |
| 82 | + rw [← prod_natCast, Finset.prod_Ico_id_eq_factorial, wilsons_lemma] |
| 83 | +#align zmod.prod_Ico_one_prime ZMod.prod_Ico_one_prime |
| 84 | + |
| 85 | +end ZMod |
| 86 | + |
| 87 | +namespace Nat |
| 88 | + |
| 89 | +variable {n : ℕ} |
| 90 | + |
| 91 | +/-- For `n ≠ 1`, `(n-1)!` is congruent to `-1` modulo `n` only if n is prime. -/ |
| 92 | +theorem prime_of_fac_equiv_neg_one (h : ((n - 1)! : ZMod n) = -1) (h1 : n ≠ 1) : Prime n := by |
| 93 | + rcases eq_or_ne n 0 with (rfl | h0) |
| 94 | + · norm_num at h |
| 95 | + replace h1 : 1 < n := n.two_le_iff.mpr ⟨h0, h1⟩ |
| 96 | + by_contra h2 |
| 97 | + obtain ⟨m, hm1, hm2 : 1 < m, hm3⟩ := exists_dvd_of_not_prime2 h1 h2 |
| 98 | + have hm : m ∣ (n - 1)! := Nat.dvd_factorial (pos_of_gt hm2) (le_pred_of_lt hm3) |
| 99 | + refine' hm2.ne' (Nat.dvd_one.mp ((Nat.dvd_add_right hm).mp (hm1.trans _))) |
| 100 | + rw [← ZMod.nat_cast_zmod_eq_zero_iff_dvd, cast_add, cast_one, h, add_left_neg] |
| 101 | +#align nat.prime_of_fac_equiv_neg_one Nat.prime_of_fac_equiv_neg_one |
| 102 | + |
| 103 | +/-- **Wilson's Theorem**: For `n ≠ 1`, `(n-1)!` is congruent to `-1` modulo `n` iff n is prime. -/ |
| 104 | +theorem prime_iff_fac_equiv_neg_one (h : n ≠ 1) : Prime n ↔ ((n - 1)! : ZMod n) = -1 := by |
| 105 | + refine' ⟨fun h1 => _, fun h2 => prime_of_fac_equiv_neg_one h2 h⟩ |
| 106 | + haveI := Fact.mk h1 |
| 107 | + exact ZMod.wilsons_lemma n |
| 108 | +#align nat.prime_iff_fac_equiv_neg_one Nat.prime_iff_fac_equiv_neg_one |
| 109 | + |
| 110 | +end Nat |
| 111 | + |
| 112 | +assert_not_exists legendre_sym.quadratic_reciprocity |
0 commit comments