Skip to content

Commit f0892df

Browse files
feat: port NumberTheory.Wilson (#4970)
1 parent 57f3c44 commit f0892df

File tree

2 files changed

+113
-0
lines changed

2 files changed

+113
-0
lines changed

Mathlib.lean

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2215,6 +2215,7 @@ import Mathlib.NumberTheory.PythagoreanTriples
22152215
import Mathlib.NumberTheory.RamificationInertia
22162216
import Mathlib.NumberTheory.SumFourSquares
22172217
import Mathlib.NumberTheory.VonMangoldt
2218+
import Mathlib.NumberTheory.Wilson
22182219
import Mathlib.NumberTheory.Zsqrtd.Basic
22192220
import Mathlib.NumberTheory.Zsqrtd.ToReal
22202221
import Mathlib.Order.Antichain

Mathlib/NumberTheory/Wilson.lean

Lines changed: 112 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,112 @@
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

Comments
 (0)