Skip to content

Commit 97ffe6c

Browse files
committed
feat(NumberTheory/SumTwoSquares): it is decidable whether a number is the sum of two squares (leanprover-community#30273)
Add a `Decidable` instance for the already proven theorem of being the sum of two squares. Try `#eval Finset.range 50 |>.filter (∃ x y, · = x ^ 2 + y ^ 2)`
1 parent cb5b0e5 commit 97ffe6c

File tree

1 file changed

+48
-39
lines changed

1 file changed

+48
-39
lines changed

Mathlib/NumberTheory/SumTwoSquares.lean

Lines changed: 48 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -87,19 +87,25 @@ theorem ZMod.isSquare_neg_one_mul {m n : ℕ} (hc : m.Coprime n) (hm : IsSquare
8787
exact ⟨(x, y), rfl⟩
8888
simpa only [RingEquiv.map_neg_one] using this.map (ZMod.chineseRemainder hc).symm
8989

90-
/-- If a prime `p` divides `n` such that `-1` is a square modulo `n`, then `p % 4 ≠ 3`. -/
91-
theorem Nat.Prime.mod_four_ne_three_of_dvd_isSquare_neg_one {p n : ℕ} (hpp : p.Prime) (hp : p ∣ n)
92-
(hs : IsSquare (-1 : ZMod n)) : p % 43 := by
93-
obtain ⟨y, h⟩ := ZMod.isSquare_neg_one_of_dvd hp hs
90+
/-- If `p` is a prime factor of `n` such that `-1` is a square modulo `n`, then `p % 4 ≠ 3`. -/
91+
theorem Nat.mod_four_ne_three_of_mem_primeFactors_of_isSquare_neg_one {p n : ℕ}
92+
(hp : p ∈ n.primeFactors) (hs : IsSquare (-1 : ZMod n)) : p % 43 := by
93+
obtain ⟨y, h⟩ := ZMod.isSquare_neg_one_of_dvd (Nat.dvd_of_mem_primeFactors hp) hs
9494
rw [← sq, eq_comm, show (-1 : ZMod p) = -1 ^ 2 by ring] at h
95-
haveI : Fact p.Prime := ⟨hpp
95+
haveI : Fact p.Prime := ⟨Nat.prime_of_mem_primeFactors hp
9696
exact ZMod.mod_four_ne_three_of_sq_eq_neg_sq' one_ne_zero h
9797

98+
@[deprecated "Note that the statement now uses `Nat.primeFactors`, \
99+
you can use `Nat.mem_primeFactors` to get the previous formulation" (since := "2025-10-15")]
100+
alias Nat.Prime.mod_four_ne_three_of_dvd_isSquare_neg_one :=
101+
Nat.mod_four_ne_three_of_mem_primeFactors_of_isSquare_neg_one
102+
98103
/-- If `n` is a squarefree natural number, then `-1` is a square modulo `n` if and only if
99-
`n` is not divisible by a prime `q` such that `q % 4 = 3`. -/
100-
theorem ZMod.isSquare_neg_one_iff {n : ℕ} (hn : Squarefree n) :
101-
IsSquare (-1 : ZMod n) ↔ ∀ {q : ℕ}, q.Prime → q ∣ n → q % 43 := by
102-
refine ⟨fun H q hqp hqd => hqp.mod_four_ne_three_of_dvd_isSquare_neg_one hqd H, fun H => ?_⟩
104+
`n` does not have a prime factor `q` such that `q % 4 = 3`. -/
105+
theorem ZMod.isSquare_neg_one_iff_forall_mem_primeFactors_mod_four_ne_three {n : ℕ}
106+
(hn : Squarefree n) : IsSquare (-1 : ZMod n) ↔ ∀ q ∈ n.primeFactors, q % 43 := by
107+
refine ⟨fun H q hq ↦ Nat.mod_four_ne_three_of_mem_primeFactors_of_isSquare_neg_one hq H,
108+
fun H ↦ ?_⟩
103109
induction n using induction_on_primes with
104110
| zero => exact False.elim (hn.ne_zero rfl)
105111
| one => exact ⟨0, by simp only [mul_zero, eq_iff_true_of_subsingleton]⟩
@@ -108,22 +114,31 @@ theorem ZMod.isSquare_neg_one_iff {n : ℕ} (hn : Squarefree n) :
108114
have hcp : p.Coprime n := by
109115
by_contra hc
110116
exact hpp.not_isUnit (hn p <| mul_dvd_mul_left p <| hpp.dvd_iff_not_coprime.mpr hc)
111-
have hp₁ := ZMod.exists_sq_eq_neg_one_iff.mpr (H hpp (dvd_mul_right p n))
112-
exact ZMod.isSquare_neg_one_mul hcp hp₁
113-
(ih hn.of_mul_right fun hqp hqd => H hqp <| dvd_mul_of_dvd_right hqd _)
117+
have hp₁ := ZMod.exists_sq_eq_neg_one_iff.mpr <| H _ <|
118+
Nat.mem_primeFactors.mpr ⟨hpp, Nat.dvd_mul_right .., Squarefree.ne_zero hn⟩
119+
exact ZMod.isSquare_neg_one_mul hcp hp₁ <| ih hn.of_mul_right fun q hqp => H q <|
120+
Nat.mem_primeFactors.mpr ⟨Nat.prime_of_mem_primeFactors hqp,
121+
dvd_mul_of_dvd_right (Nat.dvd_of_mem_primeFactors hqp) _, Squarefree.ne_zero hn⟩
122+
123+
@[deprecated "Note that the statement now uses `Nat.primeFactors`, \
124+
you can use `Nat.mem_primeFactors` and `Squarefree.ne_zero` to get the previous formulation"
125+
(since := "2025-10-15")]
126+
alias ZMod.isSquare_neg_one_iff :=
127+
ZMod.isSquare_neg_one_iff_forall_mem_primeFactors_mod_four_ne_three
114128

115129
/-- If `n` is a squarefree natural number, then `-1` is a square modulo `n` if and only if
116130
`n` has no divisor `q` that is `≡ 3 mod 4`. -/
117131
theorem ZMod.isSquare_neg_one_iff' {n : ℕ} (hn : Squarefree n) :
118132
IsSquare (-1 : ZMod n) ↔ ∀ {q : ℕ}, q ∣ n → q % 43 := by
119133
have help : ∀ a b : ZMod 4, a ≠ 3 → b ≠ 3 → a * b ≠ 3 := by decide
120-
rw [ZMod.isSquare_neg_one_iff hn]
121-
refine ⟨?_, fun H q _ => H⟩
134+
rw [ZMod.isSquare_neg_one_iff_forall_mem_primeFactors_mod_four_ne_three hn]
135+
refine ⟨?_, fun H q hq => H <| Nat.dvd_of_mem_primeFactors hq
122136
intro H
123137
refine @induction_on_primes _ ?_ ?_ (fun p q hp hq hpq => ?_)
124138
· exact fun _ => by simp
125139
· exact fun _ => by simp
126-
· replace hp := H hp (dvd_of_mul_right_dvd hpq)
140+
· replace hp := H _ <|
141+
Nat.mem_primeFactors.mpr ⟨hp, dvd_of_mul_right_dvd hpq, Squarefree.ne_zero hn⟩
127142
replace hq := hq (dvd_of_mul_left_dvd hpq)
128143
rw [show 3 = 3 % 4 by simp, Ne, ← ZMod.natCast_eq_natCast_iff'] at hp hq ⊢
129144
rw [Nat.cast_mul]
@@ -200,31 +215,25 @@ every prime `q` such that `q % 4 = 3` in the prime factorization of `n` is even.
200215
(The assumption `0 < n` is not present, since for `n = 0`, both sides are satisfied;
201216
the right-hand side holds, since `padicValNat q 0 = 0` by definition.) -/
202217
theorem Nat.eq_sq_add_sq_iff {n : ℕ} :
203-
(∃ x y : ℕ, n = x ^ 2 + y ^ 2) ↔ ∀ {q : ℕ}, q.Prime → q % 4 = 3 → Even (padicValNat q n) := by
218+
(∃ x y, n = x ^ 2 + y ^ 2) ↔ ∀ q ∈ n.primeFactors, q % 4 = 3 → Even (padicValNat q n) := by
204219
rcases n.eq_zero_or_pos with (rfl | hn₀)
205-
· exact ⟨fun _ q _ _ => (@padicValNat.zero q).symm ▸ Even.zero, fun _ =>0, 0, rfl⟩⟩
220+
· exact ⟨fun _ q _ _ padicValNat.zero.symm ▸ Even.zero, fun _ 0, 0, rfl⟩⟩
206221
-- now `0 < n`
207-
rw [Nat.eq_sq_add_sq_iff_eq_sq_mul]
208-
refine ⟨fun H q hq h => ?_, fun H => ?_⟩
209-
· obtain ⟨a, b, h₁, h₂⟩ := H
210-
have hqb := padicValNat.eq_zero_of_not_dvd fun hf =>
211-
(hq.mod_four_ne_three_of_dvd_isSquare_neg_one hf h₂) h
212-
have hab : a ^ 2 * b ≠ 0 := h₁ ▸ hn₀.ne'
213-
have ha₂ := left_ne_zero_of_mul hab
214-
have ha := mt sq_eq_zero_iff.mpr ha₂
215-
have hb := right_ne_zero_of_mul hab
216-
haveI hqi : Fact q.Prime := ⟨hq⟩
217-
simp_rw [h₁, padicValNat.mul ha₂ hb, padicValNat.pow 2 ha, hqb, add_zero]
218-
exact even_two_mul _
219-
· obtain ⟨b, a, hb₀, ha₀, hab, hb⟩ := Nat.sq_mul_squarefree_of_pos hn₀
220-
refine ⟨a, b, hab.symm, (ZMod.isSquare_neg_one_iff hb).mpr fun {q} hqp hqb hq4 => ?_⟩
221-
refine Nat.not_even_iff_odd.2 ?_ (H hqp hq4)
222-
have hqb' : padicValNat q b = 1 :=
223-
b.factorization_def hqp ▸ le_antisymm (hb.natFactorization_le_one _)
224-
((hqp.dvd_iff_one_le_factorization hb₀.ne').mp hqb)
225-
haveI hqi : Fact q.Prime := ⟨hqp⟩
226-
simp_rw [← hab, padicValNat.mul (pow_ne_zero 2 ha₀.ne') hb₀.ne', hqb',
227-
padicValNat.pow 2 ha₀.ne']
228-
exact odd_two_mul_add_one _
222+
refine eq_sq_add_sq_iff_eq_sq_mul.trans ⟨fun ⟨a, b, h₁, h₂⟩ q hq h ↦ ?_, fun H ↦ ?_⟩
223+
· haveI : Fact q.Prime := ⟨prime_of_mem_primeFactors hq⟩
224+
have : q ∣ b → q ∈ b.primeFactors := by grind [mem_primeFactors]
225+
grind [padicValNat.mul, padicValNat.pow,
226+
padicValNat.eq_zero_of_not_dvd, mod_four_ne_three_of_mem_primeFactors_of_isSquare_neg_one]
227+
· obtain ⟨b, a, hb₀, ha₀, hab, hb⟩ := sq_mul_squarefree_of_pos hn₀
228+
refine ⟨a, b, hab.symm, ZMod.isSquare_neg_one_iff_forall_mem_primeFactors_mod_four_ne_three hb
229+
|>.mpr fun q hq hq4 ↦ ?_⟩
230+
haveI : Fact q.Prime := ⟨prime_of_mem_primeFactors hq⟩
231+
have := Nat.primeFactors_mono <| Dvd.intro_left _ hab
232+
have : b.factorization q = 1 := by grind [Squarefree.natFactorization_le_one,
233+
Prime.dvd_iff_one_le_factorization, prime_of_mem_primeFactors, dvd_of_mem_primeFactors]
234+
grind [factorization_def, prime_of_mem_primeFactors, padicValNat.mul, padicValNat.pow]
229235

230236
end Main
237+
238+
instance {n : ℕ} : Decidable (∃ x y, n = x ^ 2 + y ^ 2) :=
239+
decidable_of_iff' _ Nat.eq_sq_add_sq_iff

0 commit comments

Comments
 (0)