number_theory.pellMathlib.NumberTheory.Pell

This file has been ported!

Changes since the initial port

The following section lists changes to this file in mathlib3 and mathlib4 that occured after the initial port. Most recent changes are shown first. Hovering over a commit will show all commits associated with the same mathlib3 commit.

Changes in mathlib3

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(no changes)

(last sync)

Changes in mathlib3port

mathlib3
mathlib3port
Diff
@@ -478,14 +478,14 @@ theorem exists_of_not_isSquare (h₀ : 0 < d) (hd : ¬IsSquare d) :
     prod.ext_iff.mp hqf
   have hd₁ : m ∣ q₁.1 * q₂.1 - d * (q₁.2 * q₂.2) :=
     by
-    rw [← Int.natAbs_dvd, ← ZMod.int_cast_zmod_eq_zero_iff_dvd]
+    rw [← Int.natAbs_dvd, ← ZMod.intCast_zmod_eq_zero_iff_dvd]
     push_cast
     rw [hq1, hq2, ← sq, ← sq]
     norm_cast
-    rw [ZMod.int_cast_zmod_eq_zero_iff_dvd, Int.natAbs_dvd, Nat.cast_pow, ← h₂]
+    rw [ZMod.intCast_zmod_eq_zero_iff_dvd, Int.natAbs_dvd, Nat.cast_pow, ← h₂]
   have hd₂ : m ∣ q₁.1 * q₂.2 - q₂.1 * q₁.2 :=
     by
-    rw [← Int.natAbs_dvd, ← ZMod.int_cast_eq_int_cast_iff_dvd_sub]
+    rw [← Int.natAbs_dvd, ← ZMod.intCast_eq_intCast_iff_dvd_sub]
     push_cast
     rw [hq1, hq2]
   replace hm₀ : (m : ℚ) ≠ 0 := int.cast_ne_zero.mpr hm₀
Diff
@@ -4,7 +4,7 @@ Released under Apache 2.0 license as described in the file LICENSE.
 Authors: Michael Geißer, Michael Stoll
 -/
 import Tactic.Qify
-import Data.Zmod.Basic
+import Data.ZMod.Basic
 import NumberTheory.DiophantineApproximation
 import NumberTheory.Zsqrtd.Basic
 
@@ -344,7 +344,7 @@ theorem x_pow_pos {a : Solution₁ d} (hax : 0 < a.x) (n : ℕ) : 0 < (a ^ n).x
   by
   induction' n with n ih
   · simp only [pow_zero, x_one, zero_lt_one]
-  · rw [pow_succ]
+  · rw [pow_succ']
     exact x_mul_pos hax ih
 #align pell.solution₁.x_pow_pos Pell.Solution₁.x_pow_pos
 -/
@@ -356,7 +356,7 @@ theorem y_pow_succ_pos {a : Solution₁ d} (hax : 0 < a.x) (hay : 0 < a.y) (n :
     0 < (a ^ n.succ).y := by
   induction' n with n ih
   · simp only [hay, pow_one]
-  · rw [pow_succ]
+  · rw [pow_succ']
     exact y_mul_pos hax hay (x_pow_pos hax _) ih
 #align pell.solution₁.y_pow_succ_pos Pell.Solution₁.y_pow_succ_pos
 -/
@@ -378,7 +378,7 @@ theorem y_zpow_pos {a : Solution₁ d} (hax : 0 < a.x) (hay : 0 < a.y) {n : ℤ}
 theorem x_zpow_pos {a : Solution₁ d} (hax : 0 < a.x) (n : ℤ) : 0 < (a ^ n).x :=
   by
   cases n
-  · rw [zpow_coe_nat]
+  · rw [zpow_natCast]
     exact x_pow_pos hax n
   · rw [zpow_negSucc]
     exact x_pow_pos hax (n + 1)
@@ -393,7 +393,7 @@ theorem sign_y_zpow_eq_sign_of_x_pos_of_y_pos {a : Solution₁ d} (hax : 0 < a.x
   by
   rcases n with ((_ | _) | _)
   · rfl
-  · rw [zpow_coe_nat]
+  · rw [zpow_natCast]
     exact Int.sign_eq_one_of_pos (y_pow_succ_pos hax hay n)
   · rw [zpow_negSucc]
     exact Int.sign_eq_neg_one_of_neg (neg_neg_of_pos (y_pow_succ_pos hax hay n))
@@ -449,7 +449,7 @@ theorem exists_of_not_isSquare (h₀ : 0 < d) (hd : ¬IsSquare d) :
     have h1 : (q.num : ℝ) / (q.denom : ℝ) = q := by exact_mod_cast q.num_div_denom
     rw [mem_set_of, abs_sub_comm, ← @Int.cast_lt ℝ, ← div_lt_div_right (abs_pos_of_pos h0)]
     push_cast
-    rw [← abs_div, abs_sq, sub_div, mul_div_cancel _ h0.ne', ← div_pow, h1, ←
+    rw [← abs_div, abs_sq, sub_div, mul_div_cancel_right₀ _ h0.ne', ← div_pow, h1, ←
       sq_sqrt (int.cast_pos.mpr h₀).le, sq_sub_sq, abs_mul, ← mul_one_div]
     refine' mul_lt_mul'' (((abs_add ξ q).trans _).trans_lt hM₁) h (abs_nonneg _) (abs_nonneg _)
     rw [two_mul, add_assoc, add_le_add_iff_left, ← sub_le_iff_le_add']
@@ -808,7 +808,7 @@ theorem eq_pow_of_nonneg {a₁ : Solution₁ d} (h : IsFundamental a₁) {a : So
     have hyy := h.mul_inv_y_nonneg hx₁ hy
     lift (a * a₁⁻¹).x to ℕ using hxx₁.le with x' hx'
     obtain ⟨n, hn⟩ := ih x' (by exact_mod_cast hxx₂.trans_eq hax'.symm) hxx₁ hyy hx'
-    exact ⟨n + 1, by rw [pow_succ, ← hn, mul_comm a, ← mul_assoc, mul_inv_self, one_mul]⟩
+    exact ⟨n + 1, by rw [pow_succ', ← hn, mul_comm a, ← mul_assoc, mul_inv_self, one_mul]⟩
 #align pell.is_fundamental.eq_pow_of_nonneg Pell.IsFundamental.eq_pow_of_nonneg
 -/
 
Diff
@@ -253,7 +253,7 @@ theorem x_ne_zero (h₀ : 0 ≤ d) (a : Solution₁ d) : a.x ≠ 0 :=
   by
   intro hx
   have h : 0 ≤ d * a.y ^ 2 := mul_nonneg h₀ (sq_nonneg _)
-  rw [a.prop_y, hx, sq, MulZeroClass.zero_mul, zero_sub] at h 
+  rw [a.prop_y, hx, sq, MulZeroClass.zero_mul, zero_sub] at h
   exact not_le.mpr (neg_one_lt_zero : (-1 : ℤ) < 0) h
 #align pell.solution₁.x_ne_zero Pell.Solution₁.x_ne_zero
 -/
@@ -264,7 +264,7 @@ theorem y_ne_zero_of_one_lt_x {a : Solution₁ d} (ha : 1 < a.x) : a.y ≠ 0 :=
   by
   intro hy
   have prop := a.prop
-  rw [hy, sq (0 : ℤ), MulZeroClass.zero_mul, MulZeroClass.mul_zero, sub_zero] at prop 
+  rw [hy, sq (0 : ℤ), MulZeroClass.zero_mul, MulZeroClass.mul_zero, sub_zero] at prop
   exact lt_irrefl _ (((one_lt_sq_iff <| zero_le_one.trans ha.le).mpr ha).trans_eq prop)
 #align pell.solution₁.y_ne_zero_of_one_lt_x Pell.Solution₁.y_ne_zero_of_one_lt_x
 -/
@@ -285,7 +285,7 @@ theorem d_nonsquare_of_one_lt_x {a : Solution₁ d} (ha : 1 < a.x) : ¬IsSquare
   by
   have hp := a.prop
   rintro ⟨b, rfl⟩
-  simp_rw [← sq, ← mul_pow, sq_sub_sq, Int.mul_eq_one_iff_eq_one_or_neg_one] at hp 
+  simp_rw [← sq, ← mul_pow, sq_sub_sq, Int.mul_eq_one_iff_eq_one_or_neg_one] at hp
   rcases hp with (⟨hp₁, hp₂⟩ | ⟨hp₁, hp₂⟩) <;> linarith [ha, hp₁, hp₂]
 #align pell.solution₁.d_nonsquare_of_one_lt_x Pell.Solution₁.d_nonsquare_of_one_lt_x
 -/
@@ -295,7 +295,7 @@ theorem d_nonsquare_of_one_lt_x {a : Solution₁ d} (ha : 1 < a.x) : ¬IsSquare
 theorem eq_one_of_x_eq_one (h₀ : d ≠ 0) {a : Solution₁ d} (ha : a.x = 1) : a = 1 :=
   by
   have prop := a.prop_y
-  rw [ha, one_pow, sub_self, mul_eq_zero, or_iff_right h₀, sq_eq_zero_iff] at prop 
+  rw [ha, one_pow, sub_self, mul_eq_zero, or_iff_right h₀, sq_eq_zero_iff] at prop
   exact ext ha prop
 #align pell.solution₁.eq_one_of_x_eq_one Pell.Solution₁.eq_one_of_x_eq_one
 -/
@@ -306,7 +306,7 @@ theorem eq_one_or_neg_one_iff_y_eq_zero {a : Solution₁ d} : a = 1 ∨ a = -1 
   by
   refine' ⟨fun H => H.elim (fun h => by simp [h]) fun h => by simp [h], fun H => _⟩
   have prop := a.prop
-  rw [H, sq (0 : ℤ), MulZeroClass.mul_zero, MulZeroClass.mul_zero, sub_zero, sq_eq_one_iff] at prop 
+  rw [H, sq (0 : ℤ), MulZeroClass.mul_zero, MulZeroClass.mul_zero, sub_zero, sq_eq_one_iff] at prop
   exact prop.imp (fun h => ext h H) fun h => ext h H
 #align pell.solution₁.eq_one_or_neg_one_iff_y_eq_zero Pell.Solution₁.eq_one_or_neg_one_iff_y_eq_zero
 -/
@@ -453,7 +453,7 @@ theorem exists_of_not_isSquare (h₀ : 0 < d) (hd : ¬IsSquare d) :
       sq_sqrt (int.cast_pos.mpr h₀).le, sq_sub_sq, abs_mul, ← mul_one_div]
     refine' mul_lt_mul'' (((abs_add ξ q).trans _).trans_lt hM₁) h (abs_nonneg _) (abs_nonneg _)
     rw [two_mul, add_assoc, add_le_add_iff_left, ← sub_le_iff_le_add']
-    rw [mem_set_of, abs_sub_comm] at h 
+    rw [mem_set_of, abs_sub_comm] at h
     refine' (abs_sub_abs_le_abs_sub (q : ℝ) ξ).trans (h.le.trans _)
     rw [div_le_one h0, one_le_sq_iff_one_le_abs, Nat.abs_cast, Nat.one_le_cast]
     exact q.pos
@@ -466,9 +466,9 @@ theorem exists_of_not_isSquare (h₀ : 0 < d) (hd : ¬IsSquare d) :
   have hm₀ : m ≠ 0 := by
     rintro rfl
     obtain ⟨q, hq⟩ := hm.nonempty
-    rw [mem_set_of, sub_eq_zero, mul_comm] at hq 
+    rw [mem_set_of, sub_eq_zero, mul_comm] at hq
     obtain ⟨a, ha⟩ := (Int.pow_dvd_pow_iff two_pos).mp ⟨d, hq⟩
-    rw [ha, mul_pow, mul_right_inj' (pow_pos (int.coe_nat_pos.mpr q.pos) 2).ne'] at hq 
+    rw [ha, mul_pow, mul_right_inj' (pow_pos (int.coe_nat_pos.mpr q.pos) 2).ne'] at hq
     exact hd ⟨a, sq a ▸ hq.symm⟩
   haveI := ne_zero_iff.mpr (int.nat_abs_ne_zero.mpr hm₀)
   let f : ℚ → ZMod m.nat_abs × ZMod m.nat_abs := fun q => (q.1, q.2)
@@ -516,7 +516,7 @@ theorem exists_iff_not_isSquare (h₀ : 0 < d) :
   by
   refine' ⟨_, exists_of_not_is_square h₀⟩
   rintro ⟨x, y, hxy, hy⟩ ⟨a, rfl⟩
-  rw [← sq, ← mul_pow, sq_sub_sq] at hxy 
+  rw [← sq, ← mul_pow, sq_sub_sq] at hxy
   simpa [mul_self_pos.mp h₀, sub_eq_add_neg, eq_neg_self_iff] using Int.eq_of_mul_eq_one hxy
 #align pell.exists_iff_not_is_square Pell.exists_iff_not_isSquare
 -/
@@ -530,7 +530,7 @@ theorem exists_nontrivial_of_not_isSquare (h₀ : 0 < d) (hd : ¬IsSquare d) :
     ∃ a : Solution₁ d, a ≠ 1 ∧ a ≠ -1 :=
   by
   obtain ⟨x, y, prop, hy⟩ := exists_of_not_is_square h₀ hd
-  refine' ⟨mk x y prop, fun H => _, fun H => _⟩ <;> apply_fun solution₁.y at H  <;>
+  refine' ⟨mk x y prop, fun H => _, fun H => _⟩ <;> apply_fun solution₁.y at H <;>
     simpa only [hy] using H
 #align pell.solution₁.exists_nontrivial_of_not_is_square Pell.Solution₁.exists_nontrivial_of_not_isSquare
 -/
@@ -617,7 +617,7 @@ theorem exists_of_not_isSquare (h₀ : 0 < d) (hd : ¬IsSquare d) :
     by
     have hax := a.prop
     lift a.x to ℕ using by positivity with ax
-    norm_cast at ha₁ 
+    norm_cast at ha₁
     exact ⟨ax, ha₁, a.y, ha₂, hax⟩
   classical
   -- to avoid having to show that the predicate is decidable
@@ -687,9 +687,9 @@ fundamental solution. -/
 theorem zpow_ne_neg_zpow {a : Solution₁ d} (h : IsFundamental a) {n n' : ℤ} : a ^ n ≠ -a ^ n' :=
   by
   intro hf
-  apply_fun solution₁.x at hf 
+  apply_fun solution₁.x at hf
   have H := x_zpow_pos h.x_pos n
-  rw [hf, x_neg, lt_neg, neg_zero] at H 
+  rw [hf, x_neg, lt_neg, neg_zero] at H
   exact lt_irrefl _ ((x_zpow_pos h.x_pos n').trans H)
 #align pell.is_fundamental.zpow_ne_neg_zpow Pell.IsFundamental.zpow_ne_neg_zpow
 -/
@@ -796,10 +796,10 @@ theorem eq_pow_of_nonneg {a₁ : Solution₁ d} (h : IsFundamental a₁) {a : So
     ext <;> simp only [x_one, y_one]
     · have prop := a.prop
       rw [← hy, sq (0 : ℤ), MulZeroClass.zero_mul, MulZeroClass.mul_zero, sub_zero,
-        sq_eq_one_iff] at prop 
+        sq_eq_one_iff] at prop
       refine' prop.resolve_right fun hf => _
       have := (hax.trans_eq hax').le.trans_eq hf
-      norm_num at this 
+      norm_num at this
     · exact hy.symm
   · -- case 2: `a ≥ a₁`
     have hx₁ : 1 < a.x := by nlinarith [a.prop, h.d_pos]
@@ -823,7 +823,7 @@ theorem eq_zpow_or_neg_zpow {a₁ : Solution₁ d} (h : IsFundamental a₁) (a :
   · exact ⟨n, Or.inl (by exact_mod_cast hn)⟩
   · exact ⟨-n, Or.inl (by simp [hn])⟩
   · exact ⟨n, Or.inr (by simp [hn])⟩
-  · rw [Set.mem_singleton_iff] at hb 
+  · rw [Set.mem_singleton_iff] at hb
     rw [hb]
     exact ⟨-n, Or.inr (by simp [hn])⟩
 #align pell.is_fundamental.eq_zpow_or_neg_zpow Pell.IsFundamental.eq_zpow_or_neg_zpow
@@ -847,20 +847,20 @@ theorem existsUnique_pos_generator (h₀ : 0 < d) (hd : ¬IsSquare d) :
   obtain ⟨n₂, hn₂⟩ := ha₁.eq_zpow_or_neg_zpow a
   rcases hn₂ with (rfl | rfl)
   · rw [← zpow_mul, eq_comm, @eq_comm _ a₁, ← mul_inv_eq_one, ← @mul_inv_eq_one _ _ _ a₁, ←
-      zpow_neg_one, neg_mul, ← zpow_add, ← sub_eq_add_neg] at hn₁ 
+      zpow_neg_one, neg_mul, ← zpow_add, ← sub_eq_add_neg] at hn₁
     cases hn₁
     · rcases int.is_unit_iff.mp
           (isUnit_of_mul_eq_one _ _ <|
             sub_eq_zero.mp <| (ha₁.zpow_eq_one_iff (n₂ * n₁ - 1)).mp hn₁) with
         (rfl | rfl)
       · rw [zpow_one]
-      · rw [zpow_neg_one, y_inv, lt_neg, neg_zero] at Hy 
+      · rw [zpow_neg_one, y_inv, lt_neg, neg_zero] at Hy
         exact False.elim (lt_irrefl _ <| ha₁.2.1.trans Hy)
-    · rw [← zpow_zero a₁, eq_comm] at hn₁ 
+    · rw [← zpow_zero a₁, eq_comm] at hn₁
       exact False.elim (ha₁.zpow_ne_neg_zpow hn₁)
-  · rw [x_neg, lt_neg] at Hx 
+  · rw [x_neg, lt_neg] at Hx
     have := (x_zpow_pos (zero_lt_one.trans ha₁.1) n₂).trans Hx
-    norm_num at this 
+    norm_num at this
 #align pell.exists_unique_pos_generator Pell.existsUnique_pos_generator
 -/
 
Diff
@@ -378,7 +378,7 @@ theorem y_zpow_pos {a : Solution₁ d} (hax : 0 < a.x) (hay : 0 < a.y) {n : ℤ}
 theorem x_zpow_pos {a : Solution₁ d} (hax : 0 < a.x) (n : ℤ) : 0 < (a ^ n).x :=
   by
   cases n
-  · rw [zpow_ofNat]
+  · rw [zpow_coe_nat]
     exact x_pow_pos hax n
   · rw [zpow_negSucc]
     exact x_pow_pos hax (n + 1)
@@ -393,7 +393,7 @@ theorem sign_y_zpow_eq_sign_of_x_pos_of_y_pos {a : Solution₁ d} (hax : 0 < a.x
   by
   rcases n with ((_ | _) | _)
   · rfl
-  · rw [zpow_ofNat]
+  · rw [zpow_coe_nat]
     exact Int.sign_eq_one_of_pos (y_pow_succ_pos hax hay n)
   · rw [zpow_negSucc]
     exact Int.sign_eq_neg_one_of_neg (neg_neg_of_pos (y_pow_succ_pos hax hay n))
Diff
@@ -620,11 +620,22 @@ theorem exists_of_not_isSquare (h₀ : 0 < d) (hd : ¬IsSquare d) :
     norm_cast at ha₁ 
     exact ⟨ax, ha₁, a.y, ha₂, hax⟩
   classical
+  -- to avoid having to show that the predicate is decidable
+  let x₁ := Nat.find P
+  obtain ⟨hx, y₁, hy₀, hy₁⟩ := Nat.find_spec P
+  refine' ⟨mk x₁ y₁ hy₁, by rw [x_mk]; exact_mod_cast hx, hy₀, fun b hb => _⟩
+  rw [x_mk]
+  have hb' := (Int.toNat_of_nonneg <| zero_le_one.trans hb.le).symm
+  have hb'' := hb
+  rw [hb'] at hb ⊢
+  norm_cast at hb ⊢
+  refine' Nat.find_min' P ⟨hb, |b.y|, abs_pos.mpr <| y_ne_zero_of_one_lt_x hb'', _⟩
+  rw [← hb', sq_abs]
+  exact b.prop
 #align pell.is_fundamental.exists_of_not_is_square Pell.IsFundamental.exists_of_not_isSquare
 -/
 
 #print Pell.IsFundamental.y_strictMono /-
--- to avoid having to show that the predicate is decidable
 /-- The map sending an integer `n` to the `y`-coordinate of `a^n` for a fundamental
 solution `a` is stritcly increasing. -/
 theorem y_strictMono {a : Solution₁ d} (h : IsFundamental a) : StrictMono fun n : ℤ => (a ^ n).y :=
Diff
@@ -620,22 +620,11 @@ theorem exists_of_not_isSquare (h₀ : 0 < d) (hd : ¬IsSquare d) :
     norm_cast at ha₁ 
     exact ⟨ax, ha₁, a.y, ha₂, hax⟩
   classical
-  -- to avoid having to show that the predicate is decidable
-  let x₁ := Nat.find P
-  obtain ⟨hx, y₁, hy₀, hy₁⟩ := Nat.find_spec P
-  refine' ⟨mk x₁ y₁ hy₁, by rw [x_mk]; exact_mod_cast hx, hy₀, fun b hb => _⟩
-  rw [x_mk]
-  have hb' := (Int.toNat_of_nonneg <| zero_le_one.trans hb.le).symm
-  have hb'' := hb
-  rw [hb'] at hb ⊢
-  norm_cast at hb ⊢
-  refine' Nat.find_min' P ⟨hb, |b.y|, abs_pos.mpr <| y_ne_zero_of_one_lt_x hb'', _⟩
-  rw [← hb', sq_abs]
-  exact b.prop
 #align pell.is_fundamental.exists_of_not_is_square Pell.IsFundamental.exists_of_not_isSquare
 -/
 
 #print Pell.IsFundamental.y_strictMono /-
+-- to avoid having to show that the predicate is decidable
 /-- The map sending an integer `n` to the `y`-coordinate of `a^n` for a fundamental
 solution `a` is stritcly increasing. -/
 theorem y_strictMono {a : Solution₁ d} (h : IsFundamental a) : StrictMono fun n : ℤ => (a ^ n).y :=
Diff
@@ -145,7 +145,7 @@ theorem prop_y (a : Solution₁ d) : d * a.y ^ 2 = a.x ^ 2 - 1 := by rw [← a.p
 /-- Two solutions are equal if their `x` and `y` components are equal. -/
 @[ext]
 theorem ext {a b : Solution₁ d} (hx : a.x = b.x) (hy : a.y = b.y) : a = b :=
-  Subtype.ext <| ext.mpr ⟨hx, hy⟩
+  Subtype.ext <| ext_iff.mpr ⟨hx, hy⟩
 #align pell.solution₁.ext Pell.Solution₁.ext
 -/
 
@@ -175,7 +175,7 @@ theorem y_mk (x y : ℤ) (prop : x ^ 2 - d * y ^ 2 = 1) : (mk x y prop).y = y :=
 #print Pell.Solution₁.coe_mk /-
 @[simp]
 theorem coe_mk (x y : ℤ) (prop : x ^ 2 - d * y ^ 2 = 1) : (↑(mk x y prop) : ℤ√d) = ⟨x, y⟩ :=
-  Zsqrtd.ext.mpr ⟨x_mk x y prop, y_mk x y prop⟩
+  Zsqrtd.ext_iff.mpr ⟨x_mk x y prop, y_mk x y prop⟩
 #align pell.solution₁.coe_mk Pell.Solution₁.coe_mk
 -/
 
Diff
@@ -3,10 +3,10 @@ Copyright (c) 2023 Michael Stoll. All rights reserved.
 Released under Apache 2.0 license as described in the file LICENSE.
 Authors: Michael Geißer, Michael Stoll
 -/
-import Mathbin.Tactic.Qify
-import Mathbin.Data.Zmod.Basic
-import Mathbin.NumberTheory.DiophantineApproximation
-import Mathbin.NumberTheory.Zsqrtd.Basic
+import Tactic.Qify
+import Data.Zmod.Basic
+import NumberTheory.DiophantineApproximation
+import NumberTheory.Zsqrtd.Basic
 
 #align_import number_theory.pell from "leanprover-community/mathlib"@"2a0ce625dbb0ffbc7d1316597de0b25c1ec75303"
 
Diff
@@ -602,7 +602,7 @@ theorem subsingleton {a b : Solution₁ d} (ha : IsFundamental a) (hb : IsFundam
   have hx := le_antisymm (ha.2.2 hb.1) (hb.2.2 ha.1)
   refine' solution₁.ext hx _
   have : d * a.y ^ 2 = d * b.y ^ 2 := by rw [a.prop_y, b.prop_y, hx]
-  exact (sq_eq_sq ha.2.1.le hb.2.1.le).mp (Int.eq_of_mul_eq_mul_left ha.d_pos.ne' this)
+  exact (sq_eq_sq ha.2.1.le hb.2.1.le).mp (Int.eq_of_hMul_eq_hMul_left ha.d_pos.ne' this)
 #align pell.is_fundamental.subsingleton Pell.IsFundamental.subsingleton
 -/
 
Diff
@@ -2,17 +2,14 @@
 Copyright (c) 2023 Michael Stoll. All rights reserved.
 Released under Apache 2.0 license as described in the file LICENSE.
 Authors: Michael Geißer, Michael Stoll
-
-! This file was ported from Lean 3 source module number_theory.pell
-! leanprover-community/mathlib commit 2a0ce625dbb0ffbc7d1316597de0b25c1ec75303
-! Please do not edit these lines, except to modify the commit id
-! if you have ported upstream changes.
 -/
 import Mathbin.Tactic.Qify
 import Mathbin.Data.Zmod.Basic
 import Mathbin.NumberTheory.DiophantineApproximation
 import Mathbin.NumberTheory.Zsqrtd.Basic
 
+#align_import number_theory.pell from "leanprover-community/mathlib"@"2a0ce625dbb0ffbc7d1316597de0b25c1ec75303"
+
 /-!
 # Pell's Equation
 
Diff
@@ -545,7 +545,7 @@ theorem exists_pos_of_not_isSquare (h₀ : 0 < d) (hd : ¬IsSquare d) :
     ∃ a : Solution₁ d, 1 < a.x ∧ 0 < a.y :=
   by
   obtain ⟨x, y, h, hy⟩ := exists_of_not_is_square h₀ hd
-  refine' ⟨mk (|x|) (|y|) (by rwa [sq_abs, sq_abs]), _, abs_pos.mpr hy⟩
+  refine' ⟨mk |x| |y| (by rwa [sq_abs, sq_abs]), _, abs_pos.mpr hy⟩
   rw [x_mk, ← one_lt_sq_iff_one_lt_abs, eq_add_of_sub_eq h, lt_add_iff_pos_right]
   exact mul_pos h₀ (sq_pos_of_ne_zero y hy)
 #align pell.solution₁.exists_pos_of_not_is_square Pell.Solution₁.exists_pos_of_not_isSquare
Diff
@@ -82,6 +82,7 @@ We then set up an API for `pell.solution₁ d`.
 
 open Zsqrtd
 
+#print Pell.is_pell_solution_iff_mem_unitary /-
 /-- An element of `ℤ√d` has norm one (i.e., `a.re^2 - d*a.im^2 = 1`) if and only if
 it is contained in the submonoid of unitary elements.
 
@@ -90,7 +91,9 @@ theorem is_pell_solution_iff_mem_unitary {d : ℤ} {a : ℤ√d} :
     a.re ^ 2 - d * a.im ^ 2 = 1 ↔ a ∈ unitary (ℤ√d) := by
   rw [← norm_eq_one_iff_mem_unitary, norm_def, sq, sq, ← mul_assoc]
 #align pell.is_pell_solution_iff_mem_unitary Pell.is_pell_solution_iff_mem_unitary
+-/
 
+#print Pell.Solution₁ /-
 -- We use `solution₁ d` to allow for a more general structure `solution d m` that
 -- encodes solutions to `x^2 - d*y^2 = m` to be added later.
 /-- `pell.solution₁ d` is the type of solutions to the Pell equation `x^2 - d*y^2 = 1`.
@@ -100,6 +103,7 @@ def Solution₁ (d : ℤ) : Type :=
   ↥(unitary (ℤ√d))
 deriving CommGroup, HasDistribNeg, Inhabited
 #align pell.solution₁ Pell.Solution₁
+-/
 
 namespace Solution₁
 
@@ -107,97 +111,134 @@ variable {d : ℤ}
 
 instance : Coe (Solution₁ d) (ℤ√d) where coe := Subtype.val
 
+#print Pell.Solution₁.x /-
 /-- The `x` component of a solution to the Pell equation `x^2 - d*y^2 = 1` -/
 protected def x (a : Solution₁ d) : ℤ :=
   (a : ℤ√d).re
 #align pell.solution₁.x Pell.Solution₁.x
+-/
 
+#print Pell.Solution₁.y /-
 /-- The `y` component of a solution to the Pell equation `x^2 - d*y^2 = 1` -/
 protected def y (a : Solution₁ d) : ℤ :=
   (a : ℤ√d).im
 #align pell.solution₁.y Pell.Solution₁.y
+-/
 
+#print Pell.Solution₁.prop /-
 /-- The proof that `a` is a solution to the Pell equation `x^2 - d*y^2 = 1` -/
 theorem prop (a : Solution₁ d) : a.x ^ 2 - d * a.y ^ 2 = 1 :=
   is_pell_solution_iff_mem_unitary.mpr a.property
 #align pell.solution₁.prop Pell.Solution₁.prop
+-/
 
+#print Pell.Solution₁.prop_x /-
 /-- An alternative form of the equation, suitable for rewriting `x^2`. -/
 theorem prop_x (a : Solution₁ d) : a.x ^ 2 = 1 + d * a.y ^ 2 := by rw [← a.prop]; ring
 #align pell.solution₁.prop_x Pell.Solution₁.prop_x
+-/
 
+#print Pell.Solution₁.prop_y /-
 /-- An alternative form of the equation, suitable for rewriting `d * y^2`. -/
 theorem prop_y (a : Solution₁ d) : d * a.y ^ 2 = a.x ^ 2 - 1 := by rw [← a.prop]; ring
 #align pell.solution₁.prop_y Pell.Solution₁.prop_y
+-/
 
+#print Pell.Solution₁.ext /-
 /-- Two solutions are equal if their `x` and `y` components are equal. -/
 @[ext]
 theorem ext {a b : Solution₁ d} (hx : a.x = b.x) (hy : a.y = b.y) : a = b :=
   Subtype.ext <| ext.mpr ⟨hx, hy⟩
 #align pell.solution₁.ext Pell.Solution₁.ext
+-/
 
+#print Pell.Solution₁.mk /-
 /-- Construct a solution from `x`, `y` and a proof that the equation is satisfied. -/
 def mk (x y : ℤ) (prop : x ^ 2 - d * y ^ 2 = 1) : Solution₁ d
     where
   val := ⟨x, y⟩
   property := is_pell_solution_iff_mem_unitary.mp prop
 #align pell.solution₁.mk Pell.Solution₁.mk
+-/
 
+#print Pell.Solution₁.x_mk /-
 @[simp]
 theorem x_mk (x y : ℤ) (prop : x ^ 2 - d * y ^ 2 = 1) : (mk x y prop).x = x :=
   rfl
 #align pell.solution₁.x_mk Pell.Solution₁.x_mk
+-/
 
+#print Pell.Solution₁.y_mk /-
 @[simp]
 theorem y_mk (x y : ℤ) (prop : x ^ 2 - d * y ^ 2 = 1) : (mk x y prop).y = y :=
   rfl
 #align pell.solution₁.y_mk Pell.Solution₁.y_mk
+-/
 
+#print Pell.Solution₁.coe_mk /-
 @[simp]
 theorem coe_mk (x y : ℤ) (prop : x ^ 2 - d * y ^ 2 = 1) : (↑(mk x y prop) : ℤ√d) = ⟨x, y⟩ :=
   Zsqrtd.ext.mpr ⟨x_mk x y prop, y_mk x y prop⟩
 #align pell.solution₁.coe_mk Pell.Solution₁.coe_mk
+-/
 
+#print Pell.Solution₁.x_one /-
 @[simp]
 theorem x_one : (1 : Solution₁ d).x = 1 :=
   rfl
 #align pell.solution₁.x_one Pell.Solution₁.x_one
+-/
 
+#print Pell.Solution₁.y_one /-
 @[simp]
 theorem y_one : (1 : Solution₁ d).y = 0 :=
   rfl
 #align pell.solution₁.y_one Pell.Solution₁.y_one
+-/
 
+#print Pell.Solution₁.x_mul /-
 @[simp]
 theorem x_mul (a b : Solution₁ d) : (a * b).x = a.x * b.x + d * (a.y * b.y) := by rw [← mul_assoc];
   rfl
 #align pell.solution₁.x_mul Pell.Solution₁.x_mul
+-/
 
+#print Pell.Solution₁.y_mul /-
 @[simp]
 theorem y_mul (a b : Solution₁ d) : (a * b).y = a.x * b.y + a.y * b.x :=
   rfl
 #align pell.solution₁.y_mul Pell.Solution₁.y_mul
+-/
 
+#print Pell.Solution₁.x_inv /-
 @[simp]
 theorem x_inv (a : Solution₁ d) : a⁻¹.x = a.x :=
   rfl
 #align pell.solution₁.x_inv Pell.Solution₁.x_inv
+-/
 
+#print Pell.Solution₁.y_inv /-
 @[simp]
 theorem y_inv (a : Solution₁ d) : a⁻¹.y = -a.y :=
   rfl
 #align pell.solution₁.y_inv Pell.Solution₁.y_inv
+-/
 
+#print Pell.Solution₁.x_neg /-
 @[simp]
 theorem x_neg (a : Solution₁ d) : (-a).x = -a.x :=
   rfl
 #align pell.solution₁.x_neg Pell.Solution₁.x_neg
+-/
 
+#print Pell.Solution₁.y_neg /-
 @[simp]
 theorem y_neg (a : Solution₁ d) : (-a).y = -a.y :=
   rfl
 #align pell.solution₁.y_neg Pell.Solution₁.y_neg
+-/
 
+#print Pell.Solution₁.eq_zero_of_d_neg /-
 /-- When `d` is negative, then `x` or `y` must be zero in a solution. -/
 theorem eq_zero_of_d_neg (h₀ : d < 0) (a : Solution₁ d) : a.x = 0 ∨ a.y = 0 :=
   by
@@ -207,7 +248,9 @@ theorem eq_zero_of_d_neg (h₀ : d < 0) (a : Solution₁ d) : a.x = 0 ∨ a.y =
   have h2 := sq_pos_of_ne_zero a.y h.2
   nlinarith
 #align pell.solution₁.eq_zero_of_d_neg Pell.Solution₁.eq_zero_of_d_neg
+-/
 
+#print Pell.Solution₁.x_ne_zero /-
 /-- A solution has `x ≠ 0`. -/
 theorem x_ne_zero (h₀ : 0 ≤ d) (a : Solution₁ d) : a.x ≠ 0 :=
   by
@@ -216,7 +259,9 @@ theorem x_ne_zero (h₀ : 0 ≤ d) (a : Solution₁ d) : a.x ≠ 0 :=
   rw [a.prop_y, hx, sq, MulZeroClass.zero_mul, zero_sub] at h 
   exact not_le.mpr (neg_one_lt_zero : (-1 : ℤ) < 0) h
 #align pell.solution₁.x_ne_zero Pell.Solution₁.x_ne_zero
+-/
 
+#print Pell.Solution₁.y_ne_zero_of_one_lt_x /-
 /-- A solution with `x > 1` must have `y ≠ 0`. -/
 theorem y_ne_zero_of_one_lt_x {a : Solution₁ d} (ha : 1 < a.x) : a.y ≠ 0 :=
   by
@@ -225,7 +270,9 @@ theorem y_ne_zero_of_one_lt_x {a : Solution₁ d} (ha : 1 < a.x) : a.y ≠ 0 :=
   rw [hy, sq (0 : ℤ), MulZeroClass.zero_mul, MulZeroClass.mul_zero, sub_zero] at prop 
   exact lt_irrefl _ (((one_lt_sq_iff <| zero_le_one.trans ha.le).mpr ha).trans_eq prop)
 #align pell.solution₁.y_ne_zero_of_one_lt_x Pell.Solution₁.y_ne_zero_of_one_lt_x
+-/
 
+#print Pell.Solution₁.d_pos_of_one_lt_x /-
 /-- If a solution has `x > 1`, then `d` is positive. -/
 theorem d_pos_of_one_lt_x {a : Solution₁ d} (ha : 1 < a.x) : 0 < d :=
   by
@@ -233,7 +280,9 @@ theorem d_pos_of_one_lt_x {a : Solution₁ d} (ha : 1 < a.x) : 0 < d :=
   rw [a.prop_y, sub_pos]
   exact one_lt_pow ha two_ne_zero
 #align pell.solution₁.d_pos_of_one_lt_x Pell.Solution₁.d_pos_of_one_lt_x
+-/
 
+#print Pell.Solution₁.d_nonsquare_of_one_lt_x /-
 /-- If a solution has `x > 1`, then `d` is not a square. -/
 theorem d_nonsquare_of_one_lt_x {a : Solution₁ d} (ha : 1 < a.x) : ¬IsSquare d :=
   by
@@ -242,7 +291,9 @@ theorem d_nonsquare_of_one_lt_x {a : Solution₁ d} (ha : 1 < a.x) : ¬IsSquare
   simp_rw [← sq, ← mul_pow, sq_sub_sq, Int.mul_eq_one_iff_eq_one_or_neg_one] at hp 
   rcases hp with (⟨hp₁, hp₂⟩ | ⟨hp₁, hp₂⟩) <;> linarith [ha, hp₁, hp₂]
 #align pell.solution₁.d_nonsquare_of_one_lt_x Pell.Solution₁.d_nonsquare_of_one_lt_x
+-/
 
+#print Pell.Solution₁.eq_one_of_x_eq_one /-
 /-- A solution with `x = 1` is trivial. -/
 theorem eq_one_of_x_eq_one (h₀ : d ≠ 0) {a : Solution₁ d} (ha : a.x = 1) : a = 1 :=
   by
@@ -250,7 +301,9 @@ theorem eq_one_of_x_eq_one (h₀ : d ≠ 0) {a : Solution₁ d} (ha : a.x = 1) :
   rw [ha, one_pow, sub_self, mul_eq_zero, or_iff_right h₀, sq_eq_zero_iff] at prop 
   exact ext ha prop
 #align pell.solution₁.eq_one_of_x_eq_one Pell.Solution₁.eq_one_of_x_eq_one
+-/
 
+#print Pell.Solution₁.eq_one_or_neg_one_iff_y_eq_zero /-
 /-- A solution is `1` or `-1` if and only if `y = 0`. -/
 theorem eq_one_or_neg_one_iff_y_eq_zero {a : Solution₁ d} : a = 1 ∨ a = -1 ↔ a.y = 0 :=
   by
@@ -259,7 +312,9 @@ theorem eq_one_or_neg_one_iff_y_eq_zero {a : Solution₁ d} : a = 1 ∨ a = -1 
   rw [H, sq (0 : ℤ), MulZeroClass.mul_zero, MulZeroClass.mul_zero, sub_zero, sq_eq_one_iff] at prop 
   exact prop.imp (fun h => ext h H) fun h => ext h H
 #align pell.solution₁.eq_one_or_neg_one_iff_y_eq_zero Pell.Solution₁.eq_one_or_neg_one_iff_y_eq_zero
+-/
 
+#print Pell.Solution₁.x_mul_pos /-
 /-- The set of solutions with `x > 0` is closed under multiplication. -/
 theorem x_mul_pos {a b : Solution₁ d} (ha : 0 < a.x) (hb : 0 < b.x) : 0 < (a * b).x :=
   by
@@ -274,14 +329,18 @@ theorem x_mul_pos {a b : Solution₁ d} (ha : 0 < a.x) (hb : 0 < b.x) : 0 < (a *
       zero_pow two_pos, zero_add, MulZeroClass.zero_mul, zero_add]
     exact one_pos
 #align pell.solution₁.x_mul_pos Pell.Solution₁.x_mul_pos
+-/
 
+#print Pell.Solution₁.y_mul_pos /-
 /-- The set of solutions with `x` and `y` positive is closed under multiplication. -/
 theorem y_mul_pos {a b : Solution₁ d} (hax : 0 < a.x) (hay : 0 < a.y) (hbx : 0 < b.x)
     (hby : 0 < b.y) : 0 < (a * b).y := by
   simp only [y_mul]
   positivity
 #align pell.solution₁.y_mul_pos Pell.Solution₁.y_mul_pos
+-/
 
+#print Pell.Solution₁.x_pow_pos /-
 /-- If `(x, y)` is a solution with `x` positive, then all its powers with natural exponents
 have positive `x`. -/
 theorem x_pow_pos {a : Solution₁ d} (hax : 0 < a.x) (n : ℕ) : 0 < (a ^ n).x :=
@@ -291,7 +350,9 @@ theorem x_pow_pos {a : Solution₁ d} (hax : 0 < a.x) (n : ℕ) : 0 < (a ^ n).x
   · rw [pow_succ]
     exact x_mul_pos hax ih
 #align pell.solution₁.x_pow_pos Pell.Solution₁.x_pow_pos
+-/
 
+#print Pell.Solution₁.y_pow_succ_pos /-
 /-- If `(x, y)` is a solution with `x` and `y` positive, then all its powers with positive
 natural exponents have positive `y`. -/
 theorem y_pow_succ_pos {a : Solution₁ d} (hax : 0 < a.x) (hay : 0 < a.y) (n : ℕ) :
@@ -301,7 +362,9 @@ theorem y_pow_succ_pos {a : Solution₁ d} (hax : 0 < a.x) (hay : 0 < a.y) (n :
   · rw [pow_succ]
     exact y_mul_pos hax hay (x_pow_pos hax _) ih
 #align pell.solution₁.y_pow_succ_pos Pell.Solution₁.y_pow_succ_pos
+-/
 
+#print Pell.Solution₁.y_zpow_pos /-
 /-- If `(x, y)` is a solution with `x` and `y` positive, then all its powers with positive
 exponents have positive `y`. -/
 theorem y_zpow_pos {a : Solution₁ d} (hax : 0 < a.x) (hay : 0 < a.y) {n : ℤ} (hn : 0 < n) :
@@ -311,7 +374,9 @@ theorem y_zpow_pos {a : Solution₁ d} (hax : 0 < a.x) (hay : 0 < a.y) {n : ℤ}
   rw [← Nat.succ_pred_eq_of_pos hn]
   exact y_pow_succ_pos hax hay _
 #align pell.solution₁.y_zpow_pos Pell.Solution₁.y_zpow_pos
+-/
 
+#print Pell.Solution₁.x_zpow_pos /-
 /-- If `(x, y)` is a solution with `x` positive, then all its powers have positive `x`. -/
 theorem x_zpow_pos {a : Solution₁ d} (hax : 0 < a.x) (n : ℤ) : 0 < (a ^ n).x :=
   by
@@ -321,7 +386,9 @@ theorem x_zpow_pos {a : Solution₁ d} (hax : 0 < a.x) (n : ℤ) : 0 < (a ^ n).x
   · rw [zpow_negSucc]
     exact x_pow_pos hax (n + 1)
 #align pell.solution₁.x_zpow_pos Pell.Solution₁.x_zpow_pos
+-/
 
+#print Pell.Solution₁.sign_y_zpow_eq_sign_of_x_pos_of_y_pos /-
 /-- If `(x, y)` is a solution with `x` and `y` positive, then the `y` component of any power
 has the same sign as the exponent. -/
 theorem sign_y_zpow_eq_sign_of_x_pos_of_y_pos {a : Solution₁ d} (hax : 0 < a.x) (hay : 0 < a.y)
@@ -334,7 +401,9 @@ theorem sign_y_zpow_eq_sign_of_x_pos_of_y_pos {a : Solution₁ d} (hax : 0 < a.x
   · rw [zpow_negSucc]
     exact Int.sign_eq_neg_one_of_neg (neg_neg_of_pos (y_pow_succ_pos hax hay n))
 #align pell.solution₁.sign_y_zpow_eq_sign_of_x_pos_of_y_pos Pell.Solution₁.sign_y_zpow_eq_sign_of_x_pos_of_y_pos
+-/
 
+#print Pell.Solution₁.exists_pos_variant /-
 /-- If `a` is any solution, then one of `a`, `a⁻¹`, `-a`, `-a⁻¹` has
 positive `x` and nonnegative `y`. -/
 theorem exists_pos_variant (h₀ : 0 < d) (a : Solution₁ d) :
@@ -347,6 +416,7 @@ theorem exists_pos_variant (h₀ : 0 < d) (a : Solution₁ d) :
         eq_self_iff_true, x_neg, x_inv, y_neg, y_inv, neg_pos, neg_nonneg, or_true_iff] <;>
     assumption
 #align pell.solution₁.exists_pos_variant Pell.Solution₁.exists_pos_variant
+-/
 
 end Solution₁
 
@@ -361,6 +431,7 @@ variable {d : ℤ}
 
 open Set Real
 
+#print Pell.exists_of_not_isSquare /-
 /-- If `d` is a positive integer that is not a square, then there is a nontrivial solution
 to the Pell equation `x^2 - d*y^2 = 1`. -/
 theorem exists_of_not_isSquare (h₀ : 0 < d) (hd : ¬IsSquare d) :
@@ -438,7 +509,9 @@ theorem exists_of_not_isSquare (h₀ : 0 < d) (hd : ¬IsSquare d) :
     refine' div_ne_zero_iff.mpr ⟨_, hm₀⟩
     exact_mod_cast mt sub_eq_zero.mp (mt rat.eq_iff_mul_eq_mul.mpr hne)
 #align pell.exists_of_not_is_square Pell.exists_of_not_isSquare
+-/
 
+#print Pell.exists_iff_not_isSquare /-
 /-- If `d` is a positive integer, then there is a nontrivial solution
 to the Pell equation `x^2 - d*y^2 = 1` if and only if `d` is not a square. -/
 theorem exists_iff_not_isSquare (h₀ : 0 < d) :
@@ -449,9 +522,11 @@ theorem exists_iff_not_isSquare (h₀ : 0 < d) :
   rw [← sq, ← mul_pow, sq_sub_sq] at hxy 
   simpa [mul_self_pos.mp h₀, sub_eq_add_neg, eq_neg_self_iff] using Int.eq_of_mul_eq_one hxy
 #align pell.exists_iff_not_is_square Pell.exists_iff_not_isSquare
+-/
 
 namespace Solution₁
 
+#print Pell.Solution₁.exists_nontrivial_of_not_isSquare /-
 /-- If `d` is a positive integer that is not a square, then there exists a nontrivial solution
 to the Pell equation `x^2 - d*y^2 = 1`. -/
 theorem exists_nontrivial_of_not_isSquare (h₀ : 0 < d) (hd : ¬IsSquare d) :
@@ -461,7 +536,9 @@ theorem exists_nontrivial_of_not_isSquare (h₀ : 0 < d) (hd : ¬IsSquare d) :
   refine' ⟨mk x y prop, fun H => _, fun H => _⟩ <;> apply_fun solution₁.y at H  <;>
     simpa only [hy] using H
 #align pell.solution₁.exists_nontrivial_of_not_is_square Pell.Solution₁.exists_nontrivial_of_not_isSquare
+-/
 
+#print Pell.Solution₁.exists_pos_of_not_isSquare /-
 /-- If `d` is a positive integer that is not a square, then there exists a solution
 to the Pell equation `x^2 - d*y^2 = 1` with `x > 1` and `y > 0`. -/
 theorem exists_pos_of_not_isSquare (h₀ : 0 < d) (hd : ¬IsSquare d) :
@@ -472,6 +549,7 @@ theorem exists_pos_of_not_isSquare (h₀ : 0 < d) (hd : ¬IsSquare d) :
   rw [x_mk, ← one_lt_sq_iff_one_lt_abs, eq_add_of_sub_eq h, lt_add_iff_pos_right]
   exact mul_pos h₀ (sq_pos_of_ne_zero y hy)
 #align pell.solution₁.exists_pos_of_not_is_square Pell.Solution₁.exists_pos_of_not_isSquare
+-/
 
 end Solution₁
 
@@ -487,31 +565,40 @@ and generates the group of solutions up to sign.
 
 variable {d : ℤ}
 
+#print Pell.IsFundamental /-
 /-- We define a solution to be *fundamental* if it has `x > 1` and `y > 0`
 and its `x` is the smallest possible among solutions with `x > 1`. -/
 def IsFundamental (a : Solution₁ d) : Prop :=
   1 < a.x ∧ 0 < a.y ∧ ∀ {b : Solution₁ d}, 1 < b.x → a.x ≤ b.x
 #align pell.is_fundamental Pell.IsFundamental
+-/
 
 namespace IsFundamental
 
 open Solution₁
 
+#print Pell.IsFundamental.x_pos /-
 /-- A fundamental solution has positive `x`. -/
 theorem x_pos {a : Solution₁ d} (h : IsFundamental a) : 0 < a.x :=
   zero_lt_one.trans h.1
 #align pell.is_fundamental.x_pos Pell.IsFundamental.x_pos
+-/
 
+#print Pell.IsFundamental.d_pos /-
 /-- If a fundamental solution exists, then `d` must be positive. -/
 theorem d_pos {a : Solution₁ d} (h : IsFundamental a) : 0 < d :=
   d_pos_of_one_lt_x h.1
 #align pell.is_fundamental.d_pos Pell.IsFundamental.d_pos
+-/
 
+#print Pell.IsFundamental.d_nonsquare /-
 /-- If a fundamental solution exists, then `d` must be a non-square. -/
 theorem d_nonsquare {a : Solution₁ d} (h : IsFundamental a) : ¬IsSquare d :=
   d_nonsquare_of_one_lt_x h.1
 #align pell.is_fundamental.d_nonsquare Pell.IsFundamental.d_nonsquare
+-/
 
+#print Pell.IsFundamental.subsingleton /-
 /-- If there is a fundamental solution, it is unique. -/
 theorem subsingleton {a b : Solution₁ d} (ha : IsFundamental a) (hb : IsFundamental b) : a = b :=
   by
@@ -520,7 +607,9 @@ theorem subsingleton {a b : Solution₁ d} (ha : IsFundamental a) (hb : IsFundam
   have : d * a.y ^ 2 = d * b.y ^ 2 := by rw [a.prop_y, b.prop_y, hx]
   exact (sq_eq_sq ha.2.1.le hb.2.1.le).mp (Int.eq_of_mul_eq_mul_left ha.d_pos.ne' this)
 #align pell.is_fundamental.subsingleton Pell.IsFundamental.subsingleton
+-/
 
+#print Pell.IsFundamental.exists_of_not_isSquare /-
 /-- If `d` is positive and not a square, then a fundamental solution exists. -/
 theorem exists_of_not_isSquare (h₀ : 0 < d) (hd : ¬IsSquare d) :
     ∃ a : Solution₁ d, IsFundamental a :=
@@ -547,7 +636,9 @@ theorem exists_of_not_isSquare (h₀ : 0 < d) (hd : ¬IsSquare d) :
   rw [← hb', sq_abs]
   exact b.prop
 #align pell.is_fundamental.exists_of_not_is_square Pell.IsFundamental.exists_of_not_isSquare
+-/
 
+#print Pell.IsFundamental.y_strictMono /-
 /-- The map sending an integer `n` to the `y`-coordinate of `a^n` for a fundamental
 solution `a` is stritcly increasing. -/
 theorem y_strictMono {a : Solution₁ d} (h : IsFundamental a) : StrictMono fun n : ℤ => (a ^ n).y :=
@@ -571,7 +662,9 @@ theorem y_strictMono {a : Solution₁ d} (h : IsFundamental a) : StrictMono fun
     rw [hm, sub_add_cancel, ← neg_add', zpow_neg, zpow_neg, y_inv, y_inv, neg_lt_neg_iff]
     exact H _ (by linarith [hn])
 #align pell.is_fundamental.y_strict_mono Pell.IsFundamental.y_strictMono
+-/
 
+#print Pell.IsFundamental.zpow_y_lt_iff_lt /-
 /-- If `a` is a fundamental solution, then `(a^m).y < (a^n).y` if and only if `m < n`. -/
 theorem zpow_y_lt_iff_lt {a : Solution₁ d} (h : IsFundamental a) (m n : ℤ) :
     (a ^ m).y < (a ^ n).y ↔ m < n :=
@@ -580,14 +673,18 @@ theorem zpow_y_lt_iff_lt {a : Solution₁ d} (h : IsFundamental a) (m n : ℤ) :
   contrapose! H
   exact h.y_strict_mono.monotone H
 #align pell.is_fundamental.zpow_y_lt_iff_lt Pell.IsFundamental.zpow_y_lt_iff_lt
+-/
 
+#print Pell.IsFundamental.zpow_eq_one_iff /-
 /-- The `n`th power of a fundamental solution is trivial if and only if `n = 0`. -/
 theorem zpow_eq_one_iff {a : Solution₁ d} (h : IsFundamental a) (n : ℤ) : a ^ n = 1 ↔ n = 0 :=
   by
   rw [← zpow_zero a]
   exact ⟨fun H => h.y_strict_mono.injective (congr_arg solution₁.y H), fun H => H ▸ rfl⟩
 #align pell.is_fundamental.zpow_eq_one_iff Pell.IsFundamental.zpow_eq_one_iff
+-/
 
+#print Pell.IsFundamental.zpow_ne_neg_zpow /-
 /-- A power of a fundamental solution is never equal to the negative of a power of this
 fundamental solution. -/
 theorem zpow_ne_neg_zpow {a : Solution₁ d} (h : IsFundamental a) {n n' : ℤ} : a ^ n ≠ -a ^ n' :=
@@ -598,14 +695,18 @@ theorem zpow_ne_neg_zpow {a : Solution₁ d} (h : IsFundamental a) {n n' : ℤ}
   rw [hf, x_neg, lt_neg, neg_zero] at H 
   exact lt_irrefl _ ((x_zpow_pos h.x_pos n').trans H)
 #align pell.is_fundamental.zpow_ne_neg_zpow Pell.IsFundamental.zpow_ne_neg_zpow
+-/
 
+#print Pell.IsFundamental.x_le_x /-
 /-- The `x`-coordinate of a fundamental solution is a lower bound for the `x`-coordinate
 of any positive solution. -/
 theorem x_le_x {a₁ : Solution₁ d} (h : IsFundamental a₁) {a : Solution₁ d} (hax : 1 < a.x) :
     a₁.x ≤ a.x :=
   h.2.2 hax
 #align pell.is_fundamental.x_le_x Pell.IsFundamental.x_le_x
+-/
 
+#print Pell.IsFundamental.y_le_y /-
 /-- The `y`-coordinate of a fundamental solution is a lower bound for the `y`-coordinate
 of any positive solution. -/
 theorem y_le_y {a₁ : Solution₁ d} (h : IsFundamental a₁) {a : Solution₁ d} (hax : 1 < a.x)
@@ -617,7 +718,9 @@ theorem y_le_y {a₁ : Solution₁ d} (h : IsFundamental a₁) {a : Solution₁
     abs_of_pos (zero_lt_one.trans hax)]
   exact h.x_le_x hax
 #align pell.is_fundamental.y_le_y Pell.IsFundamental.y_le_y
+-/
 
+#print Pell.IsFundamental.x_mul_y_le_y_mul_x /-
 -- helper lemma for the next three results
 theorem x_mul_y_le_y_mul_x {a₁ : Solution₁ d} (h : IsFundamental a₁) {a : Solution₁ d}
     (hax : 1 < a.x) (hay : 0 < a.y) : a.x * a₁.y ≤ a.y * a₁.x :=
@@ -629,7 +732,9 @@ theorem x_mul_y_le_y_mul_x {a₁ : Solution₁ d} (h : IsFundamental a₁) {a :
   rw [sub_nonneg, sq_le_sq, abs_of_pos hay, abs_of_pos h.2.1]
   exact h.y_le_y hax hay
 #align pell.is_fundamental.x_mul_y_le_y_mul_x Pell.IsFundamental.x_mul_y_le_y_mul_x
+-/
 
+#print Pell.IsFundamental.mul_inv_y_nonneg /-
 /-- If we multiply a positive solution with the inverse of a fundamental solution,
 the `y`-coordinate remains nonnegative. -/
 theorem mul_inv_y_nonneg {a₁ : Solution₁ d} (h : IsFundamental a₁) {a : Solution₁ d} (hax : 1 < a.x)
@@ -637,7 +742,9 @@ theorem mul_inv_y_nonneg {a₁ : Solution₁ d} (h : IsFundamental a₁) {a : So
   simpa only [y_inv, mul_neg, y_mul, le_neg_add_iff_add_le, add_zero] using
     h.x_mul_y_le_y_mul_x hax hay
 #align pell.is_fundamental.mul_inv_y_nonneg Pell.IsFundamental.mul_inv_y_nonneg
+-/
 
+#print Pell.IsFundamental.mul_inv_x_pos /-
 /-- If we multiply a positive solution with the inverse of a fundamental solution,
 the `x`-coordinate stays positive. -/
 theorem mul_inv_x_pos {a₁ : Solution₁ d} (h : IsFundamental a₁) {a : Solution₁ d} (hax : 1 < a.x)
@@ -651,7 +758,9 @@ theorem mul_inv_x_pos {a₁ : Solution₁ d} (h : IsFundamental a₁) {a : Solut
   ring_nf
   exact zero_lt_one.trans h.1
 #align pell.is_fundamental.mul_inv_x_pos Pell.IsFundamental.mul_inv_x_pos
+-/
 
+#print Pell.IsFundamental.mul_inv_x_lt_x /-
 /-- If we multiply a positive solution with the inverse of a fundamental solution,
 the `x`-coordinate decreases. -/
 theorem mul_inv_x_lt_x {a₁ : Solution₁ d} (h : IsFundamental a₁) {a : Solution₁ d} (hax : 1 < a.x)
@@ -674,7 +783,9 @@ theorem mul_inv_x_lt_x {a₁ : Solution₁ d} (h : IsFundamental a₁) {a : Solu
     _ ≤ (1 + d * a.y ^ 2) * a₁.y ^ 2 :=
       (mul_le_mul_left (by have := h.d_pos; positivity)).mpr (sq_pos_of_pos h.2.1)
 #align pell.is_fundamental.mul_inv_x_lt_x Pell.IsFundamental.mul_inv_x_lt_x
+-/
 
+#print Pell.IsFundamental.eq_pow_of_nonneg /-
 /-- Any nonnegative solution is a power with nonnegative exponent of a fundamental solution. -/
 theorem eq_pow_of_nonneg {a₁ : Solution₁ d} (h : IsFundamental a₁) {a : Solution₁ d} (hax : 0 < a.x)
     (hay : 0 ≤ a.y) : ∃ n : ℕ, a = a₁ ^ n :=
@@ -702,7 +813,9 @@ theorem eq_pow_of_nonneg {a₁ : Solution₁ d} (h : IsFundamental a₁) {a : So
     obtain ⟨n, hn⟩ := ih x' (by exact_mod_cast hxx₂.trans_eq hax'.symm) hxx₁ hyy hx'
     exact ⟨n + 1, by rw [pow_succ, ← hn, mul_comm a, ← mul_assoc, mul_inv_self, one_mul]⟩
 #align pell.is_fundamental.eq_pow_of_nonneg Pell.IsFundamental.eq_pow_of_nonneg
+-/
 
+#print Pell.IsFundamental.eq_zpow_or_neg_zpow /-
 /-- Every solution is, up to a sign, a power of a given fundamental solution. -/
 theorem eq_zpow_or_neg_zpow {a₁ : Solution₁ d} (h : IsFundamental a₁) (a : Solution₁ d) :
     ∃ n : ℤ, a = a₁ ^ n ∨ a = -a₁ ^ n :=
@@ -717,11 +830,13 @@ theorem eq_zpow_or_neg_zpow {a₁ : Solution₁ d} (h : IsFundamental a₁) (a :
     rw [hb]
     exact ⟨-n, Or.inr (by simp [hn])⟩
 #align pell.is_fundamental.eq_zpow_or_neg_zpow Pell.IsFundamental.eq_zpow_or_neg_zpow
+-/
 
 end IsFundamental
 
 open Solution₁ IsFundamental
 
+#print Pell.existsUnique_pos_generator /-
 /-- When `d` is positive and not a square, then the group of solutions to the Pell equation
 `x^2 - d*y^2 = 1` has a unique positive generator (up to sign). -/
 theorem existsUnique_pos_generator (h₀ : 0 < d) (hd : ¬IsSquare d) :
@@ -750,7 +865,9 @@ theorem existsUnique_pos_generator (h₀ : 0 < d) (hd : ¬IsSquare d) :
     have := (x_zpow_pos (zero_lt_one.trans ha₁.1) n₂).trans Hx
     norm_num at this 
 #align pell.exists_unique_pos_generator Pell.existsUnique_pos_generator
+-/
 
+#print Pell.pos_generator_iff_fundamental /-
 /-- A positive solution is a generator (up to sign) of the group of all solutions to the
 Pell equation `x^2 - d*y^2 = 1` if and only if it is a fundamental solution. -/
 theorem pos_generator_iff_fundamental (a : Solution₁ d) :
@@ -763,6 +880,7 @@ theorem pos_generator_iff_fundamental (a : Solution₁ d) :
   obtain ⟨b, hb₁, hb₂⟩ := exists_unique_pos_generator h₀ hd
   rwa [hb₂ a h, ← hb₂ a₁ ⟨ha₁.1, ha₁.2.1, ha₁.eq_zpow_or_neg_zpow⟩]
 #align pell.pos_generator_iff_fundamental Pell.pos_generator_iff_fundamental
+-/
 
 end Pell
 
Diff
@@ -4,7 +4,7 @@ Released under Apache 2.0 license as described in the file LICENSE.
 Authors: Michael Geißer, Michael Stoll
 
 ! This file was ported from Lean 3 source module number_theory.pell
-! leanprover-community/mathlib commit 7ad820c4997738e2f542f8a20f32911f52020e26
+! leanprover-community/mathlib commit 2a0ce625dbb0ffbc7d1316597de0b25c1ec75303
 ! Please do not edit these lines, except to modify the commit id
 ! if you have ported upstream changes.
 -/
@@ -16,6 +16,9 @@ import Mathbin.NumberTheory.Zsqrtd.Basic
 /-!
 # Pell's Equation
 
+> THIS FILE IS SYNCHRONIZED WITH MATHLIB4.
+> Any changes to this file require a corresponding PR to mathlib4.
+
 *Pell's Equation* is the equation $x^2 - d y^2 = 1$, where $d$ is a positive integer
 that is not a square, and one is interested in solutions in integers $x$ and $y$.
 
Diff
@@ -670,7 +670,6 @@ theorem mul_inv_x_lt_x {a₁ : Solution₁ d} (h : IsFundamental a₁) {a : Solu
     _ = (1 + d * a.y ^ 2) * 1 := by rw [add_comm, mul_one]
     _ ≤ (1 + d * a.y ^ 2) * a₁.y ^ 2 :=
       (mul_le_mul_left (by have := h.d_pos; positivity)).mpr (sq_pos_of_pos h.2.1)
-    
 #align pell.is_fundamental.mul_inv_x_lt_x Pell.IsFundamental.mul_inv_x_lt_x
 
 /-- Any nonnegative solution is a power with nonnegative exponent of a fundamental solution. -/
Diff
@@ -304,7 +304,7 @@ exponents have positive `y`. -/
 theorem y_zpow_pos {a : Solution₁ d} (hax : 0 < a.x) (hay : 0 < a.y) {n : ℤ} (hn : 0 < n) :
     0 < (a ^ n).y := by
   lift n to ℕ using hn.le
-  norm_cast  at hn ⊢
+  norm_cast at hn ⊢
   rw [← Nat.succ_pred_eq_of_pos hn]
   exact y_pow_succ_pos hax hay _
 #align pell.solution₁.y_zpow_pos Pell.Solution₁.y_zpow_pos
@@ -371,7 +371,7 @@ theorem exists_of_not_isSquare (h₀ : 0 < d) (hd : ¬IsSquare d) :
     refine' hd ⟨x, @Int.cast_injective ℝ _ _ d (x * x) _⟩
     rw [← sq_sqrt <| int.cast_nonneg.mpr h₀.le, Int.cast_mul, ← hx, sq]
   obtain ⟨M, hM₁⟩ := exists_int_gt (2 * |ξ| + 1)
-  have hM : { q : ℚ | |q.1 ^ 2 - d * q.2 ^ 2| < M }.Infinite :=
+  have hM : {q : ℚ | |q.1 ^ 2 - d * q.2 ^ 2| < M}.Infinite :=
     by
     refine' infinite.mono (fun q h => _) (infinite_rat_abs_sub_lt_one_div_denom_sq_of_irrational hξ)
     have h0 : 0 < (q.2 : ℝ) ^ 2 := pow_pos (nat.cast_pos.mpr q.pos) 2
@@ -386,7 +386,7 @@ theorem exists_of_not_isSquare (h₀ : 0 < d) (hd : ¬IsSquare d) :
     refine' (abs_sub_abs_le_abs_sub (q : ℝ) ξ).trans (h.le.trans _)
     rw [div_le_one h0, one_le_sq_iff_one_le_abs, Nat.abs_cast, Nat.one_le_cast]
     exact q.pos
-  obtain ⟨m, hm⟩ : ∃ m : ℤ, { q : ℚ | q.1 ^ 2 - d * q.2 ^ 2 = m }.Infinite :=
+  obtain ⟨m, hm⟩ : ∃ m : ℤ, {q : ℚ | q.1 ^ 2 - d * q.2 ^ 2 = m}.Infinite :=
     by
     contrapose! hM
     simp only [not_infinite] at hM ⊢
@@ -455,7 +455,7 @@ theorem exists_nontrivial_of_not_isSquare (h₀ : 0 < d) (hd : ¬IsSquare d) :
     ∃ a : Solution₁ d, a ≠ 1 ∧ a ≠ -1 :=
   by
   obtain ⟨x, y, prop, hy⟩ := exists_of_not_is_square h₀ hd
-  refine' ⟨mk x y prop, fun H => _, fun H => _⟩ <;> apply_fun solution₁.y  at H  <;>
+  refine' ⟨mk x y prop, fun H => _, fun H => _⟩ <;> apply_fun solution₁.y at H  <;>
     simpa only [hy] using H
 #align pell.solution₁.exists_nontrivial_of_not_is_square Pell.Solution₁.exists_nontrivial_of_not_isSquare
 
@@ -528,21 +528,21 @@ theorem exists_of_not_isSquare (h₀ : 0 < d) (hd : ¬IsSquare d) :
     by
     have hax := a.prop
     lift a.x to ℕ using by positivity with ax
-    norm_cast  at ha₁ 
+    norm_cast at ha₁ 
     exact ⟨ax, ha₁, a.y, ha₂, hax⟩
   classical
-    -- to avoid having to show that the predicate is decidable
-    let x₁ := Nat.find P
-    obtain ⟨hx, y₁, hy₀, hy₁⟩ := Nat.find_spec P
-    refine' ⟨mk x₁ y₁ hy₁, by rw [x_mk]; exact_mod_cast hx, hy₀, fun b hb => _⟩
-    rw [x_mk]
-    have hb' := (Int.toNat_of_nonneg <| zero_le_one.trans hb.le).symm
-    have hb'' := hb
-    rw [hb'] at hb ⊢
-    norm_cast  at hb ⊢
-    refine' Nat.find_min' P ⟨hb, |b.y|, abs_pos.mpr <| y_ne_zero_of_one_lt_x hb'', _⟩
-    rw [← hb', sq_abs]
-    exact b.prop
+  -- to avoid having to show that the predicate is decidable
+  let x₁ := Nat.find P
+  obtain ⟨hx, y₁, hy₀, hy₁⟩ := Nat.find_spec P
+  refine' ⟨mk x₁ y₁ hy₁, by rw [x_mk]; exact_mod_cast hx, hy₀, fun b hb => _⟩
+  rw [x_mk]
+  have hb' := (Int.toNat_of_nonneg <| zero_le_one.trans hb.le).symm
+  have hb'' := hb
+  rw [hb'] at hb ⊢
+  norm_cast at hb ⊢
+  refine' Nat.find_min' P ⟨hb, |b.y|, abs_pos.mpr <| y_ne_zero_of_one_lt_x hb'', _⟩
+  rw [← hb', sq_abs]
+  exact b.prop
 #align pell.is_fundamental.exists_of_not_is_square Pell.IsFundamental.exists_of_not_isSquare
 
 /-- The map sending an integer `n` to the `y`-coordinate of `a^n` for a fundamental
@@ -590,7 +590,7 @@ fundamental solution. -/
 theorem zpow_ne_neg_zpow {a : Solution₁ d} (h : IsFundamental a) {n n' : ℤ} : a ^ n ≠ -a ^ n' :=
   by
   intro hf
-  apply_fun solution₁.x  at hf 
+  apply_fun solution₁.x at hf 
   have H := x_zpow_pos h.x_pos n
   rw [hf, x_neg, lt_neg, neg_zero] at H 
   exact lt_irrefl _ ((x_zpow_pos h.x_pos n').trans H)
Diff
@@ -94,7 +94,8 @@ theorem is_pell_solution_iff_mem_unitary {d : ℤ} {a : ℤ√d} :
 We define this in terms of elements of `ℤ√d` of norm one.
 -/
 def Solution₁ (d : ℤ) : Type :=
-  ↥(unitary (ℤ√d))deriving CommGroup, HasDistribNeg, Inhabited
+  ↥(unitary (ℤ√d))
+deriving CommGroup, HasDistribNeg, Inhabited
 #align pell.solution₁ Pell.Solution₁
 
 namespace Solution₁
@@ -209,7 +210,7 @@ theorem x_ne_zero (h₀ : 0 ≤ d) (a : Solution₁ d) : a.x ≠ 0 :=
   by
   intro hx
   have h : 0 ≤ d * a.y ^ 2 := mul_nonneg h₀ (sq_nonneg _)
-  rw [a.prop_y, hx, sq, MulZeroClass.zero_mul, zero_sub] at h
+  rw [a.prop_y, hx, sq, MulZeroClass.zero_mul, zero_sub] at h 
   exact not_le.mpr (neg_one_lt_zero : (-1 : ℤ) < 0) h
 #align pell.solution₁.x_ne_zero Pell.Solution₁.x_ne_zero
 
@@ -218,7 +219,7 @@ theorem y_ne_zero_of_one_lt_x {a : Solution₁ d} (ha : 1 < a.x) : a.y ≠ 0 :=
   by
   intro hy
   have prop := a.prop
-  rw [hy, sq (0 : ℤ), MulZeroClass.zero_mul, MulZeroClass.mul_zero, sub_zero] at prop
+  rw [hy, sq (0 : ℤ), MulZeroClass.zero_mul, MulZeroClass.mul_zero, sub_zero] at prop 
   exact lt_irrefl _ (((one_lt_sq_iff <| zero_le_one.trans ha.le).mpr ha).trans_eq prop)
 #align pell.solution₁.y_ne_zero_of_one_lt_x Pell.Solution₁.y_ne_zero_of_one_lt_x
 
@@ -235,7 +236,7 @@ theorem d_nonsquare_of_one_lt_x {a : Solution₁ d} (ha : 1 < a.x) : ¬IsSquare
   by
   have hp := a.prop
   rintro ⟨b, rfl⟩
-  simp_rw [← sq, ← mul_pow, sq_sub_sq, Int.mul_eq_one_iff_eq_one_or_neg_one] at hp
+  simp_rw [← sq, ← mul_pow, sq_sub_sq, Int.mul_eq_one_iff_eq_one_or_neg_one] at hp 
   rcases hp with (⟨hp₁, hp₂⟩ | ⟨hp₁, hp₂⟩) <;> linarith [ha, hp₁, hp₂]
 #align pell.solution₁.d_nonsquare_of_one_lt_x Pell.Solution₁.d_nonsquare_of_one_lt_x
 
@@ -243,7 +244,7 @@ theorem d_nonsquare_of_one_lt_x {a : Solution₁ d} (ha : 1 < a.x) : ¬IsSquare
 theorem eq_one_of_x_eq_one (h₀ : d ≠ 0) {a : Solution₁ d} (ha : a.x = 1) : a = 1 :=
   by
   have prop := a.prop_y
-  rw [ha, one_pow, sub_self, mul_eq_zero, or_iff_right h₀, sq_eq_zero_iff] at prop
+  rw [ha, one_pow, sub_self, mul_eq_zero, or_iff_right h₀, sq_eq_zero_iff] at prop 
   exact ext ha prop
 #align pell.solution₁.eq_one_of_x_eq_one Pell.Solution₁.eq_one_of_x_eq_one
 
@@ -252,7 +253,7 @@ theorem eq_one_or_neg_one_iff_y_eq_zero {a : Solution₁ d} : a = 1 ∨ a = -1 
   by
   refine' ⟨fun H => H.elim (fun h => by simp [h]) fun h => by simp [h], fun H => _⟩
   have prop := a.prop
-  rw [H, sq (0 : ℤ), MulZeroClass.mul_zero, MulZeroClass.mul_zero, sub_zero, sq_eq_one_iff] at prop
+  rw [H, sq (0 : ℤ), MulZeroClass.mul_zero, MulZeroClass.mul_zero, sub_zero, sq_eq_one_iff] at prop 
   exact prop.imp (fun h => ext h H) fun h => ext h H
 #align pell.solution₁.eq_one_or_neg_one_iff_y_eq_zero Pell.Solution₁.eq_one_or_neg_one_iff_y_eq_zero
 
@@ -303,7 +304,7 @@ exponents have positive `y`. -/
 theorem y_zpow_pos {a : Solution₁ d} (hax : 0 < a.x) (hay : 0 < a.y) {n : ℤ} (hn : 0 < n) :
     0 < (a ^ n).y := by
   lift n to ℕ using hn.le
-  norm_cast  at hn⊢
+  norm_cast  at hn ⊢
   rw [← Nat.succ_pred_eq_of_pos hn]
   exact y_pow_succ_pos hax hay _
 #align pell.solution₁.y_zpow_pos Pell.Solution₁.y_zpow_pos
@@ -381,22 +382,22 @@ theorem exists_of_not_isSquare (h₀ : 0 < d) (hd : ¬IsSquare d) :
       sq_sqrt (int.cast_pos.mpr h₀).le, sq_sub_sq, abs_mul, ← mul_one_div]
     refine' mul_lt_mul'' (((abs_add ξ q).trans _).trans_lt hM₁) h (abs_nonneg _) (abs_nonneg _)
     rw [two_mul, add_assoc, add_le_add_iff_left, ← sub_le_iff_le_add']
-    rw [mem_set_of, abs_sub_comm] at h
+    rw [mem_set_of, abs_sub_comm] at h 
     refine' (abs_sub_abs_le_abs_sub (q : ℝ) ξ).trans (h.le.trans _)
     rw [div_le_one h0, one_le_sq_iff_one_le_abs, Nat.abs_cast, Nat.one_le_cast]
     exact q.pos
   obtain ⟨m, hm⟩ : ∃ m : ℤ, { q : ℚ | q.1 ^ 2 - d * q.2 ^ 2 = m }.Infinite :=
     by
     contrapose! hM
-    simp only [not_infinite] at hM⊢
+    simp only [not_infinite] at hM ⊢
     refine' (congr_arg _ (ext fun x => _)).mp (finite.bUnion (finite_Ioo (-M) M) fun m _ => hM m)
     simp only [abs_lt, mem_set_of_eq, mem_Ioo, mem_Union, exists_prop, exists_eq_right']
   have hm₀ : m ≠ 0 := by
     rintro rfl
     obtain ⟨q, hq⟩ := hm.nonempty
-    rw [mem_set_of, sub_eq_zero, mul_comm] at hq
+    rw [mem_set_of, sub_eq_zero, mul_comm] at hq 
     obtain ⟨a, ha⟩ := (Int.pow_dvd_pow_iff two_pos).mp ⟨d, hq⟩
-    rw [ha, mul_pow, mul_right_inj' (pow_pos (int.coe_nat_pos.mpr q.pos) 2).ne'] at hq
+    rw [ha, mul_pow, mul_right_inj' (pow_pos (int.coe_nat_pos.mpr q.pos) 2).ne'] at hq 
     exact hd ⟨a, sq a ▸ hq.symm⟩
   haveI := ne_zero_iff.mpr (int.nat_abs_ne_zero.mpr hm₀)
   let f : ℚ → ZMod m.nat_abs × ZMod m.nat_abs := fun q => (q.1, q.2)
@@ -442,7 +443,7 @@ theorem exists_iff_not_isSquare (h₀ : 0 < d) :
   by
   refine' ⟨_, exists_of_not_is_square h₀⟩
   rintro ⟨x, y, hxy, hy⟩ ⟨a, rfl⟩
-  rw [← sq, ← mul_pow, sq_sub_sq] at hxy
+  rw [← sq, ← mul_pow, sq_sub_sq] at hxy 
   simpa [mul_self_pos.mp h₀, sub_eq_add_neg, eq_neg_self_iff] using Int.eq_of_mul_eq_one hxy
 #align pell.exists_iff_not_is_square Pell.exists_iff_not_isSquare
 
@@ -454,7 +455,7 @@ theorem exists_nontrivial_of_not_isSquare (h₀ : 0 < d) (hd : ¬IsSquare d) :
     ∃ a : Solution₁ d, a ≠ 1 ∧ a ≠ -1 :=
   by
   obtain ⟨x, y, prop, hy⟩ := exists_of_not_is_square h₀ hd
-  refine' ⟨mk x y prop, fun H => _, fun H => _⟩ <;> apply_fun solution₁.y  at H <;>
+  refine' ⟨mk x y prop, fun H => _, fun H => _⟩ <;> apply_fun solution₁.y  at H  <;>
     simpa only [hy] using H
 #align pell.solution₁.exists_nontrivial_of_not_is_square Pell.Solution₁.exists_nontrivial_of_not_isSquare
 
@@ -527,7 +528,7 @@ theorem exists_of_not_isSquare (h₀ : 0 < d) (hd : ¬IsSquare d) :
     by
     have hax := a.prop
     lift a.x to ℕ using by positivity with ax
-    norm_cast  at ha₁
+    norm_cast  at ha₁ 
     exact ⟨ax, ha₁, a.y, ha₂, hax⟩
   classical
     -- to avoid having to show that the predicate is decidable
@@ -537,8 +538,8 @@ theorem exists_of_not_isSquare (h₀ : 0 < d) (hd : ¬IsSquare d) :
     rw [x_mk]
     have hb' := (Int.toNat_of_nonneg <| zero_le_one.trans hb.le).symm
     have hb'' := hb
-    rw [hb'] at hb⊢
-    norm_cast  at hb⊢
+    rw [hb'] at hb ⊢
+    norm_cast  at hb ⊢
     refine' Nat.find_min' P ⟨hb, |b.y|, abs_pos.mpr <| y_ne_zero_of_one_lt_x hb'', _⟩
     rw [← hb', sq_abs]
     exact b.prop
@@ -589,9 +590,9 @@ fundamental solution. -/
 theorem zpow_ne_neg_zpow {a : Solution₁ d} (h : IsFundamental a) {n n' : ℤ} : a ^ n ≠ -a ^ n' :=
   by
   intro hf
-  apply_fun solution₁.x  at hf
+  apply_fun solution₁.x  at hf 
   have H := x_zpow_pos h.x_pos n
-  rw [hf, x_neg, lt_neg, neg_zero] at H
+  rw [hf, x_neg, lt_neg, neg_zero] at H 
   exact lt_irrefl _ ((x_zpow_pos h.x_pos n').trans H)
 #align pell.is_fundamental.zpow_ne_neg_zpow Pell.IsFundamental.zpow_ne_neg_zpow
 
@@ -685,10 +686,10 @@ theorem eq_pow_of_nonneg {a₁ : Solution₁ d} (h : IsFundamental a₁) {a : So
     ext <;> simp only [x_one, y_one]
     · have prop := a.prop
       rw [← hy, sq (0 : ℤ), MulZeroClass.zero_mul, MulZeroClass.mul_zero, sub_zero,
-        sq_eq_one_iff] at prop
+        sq_eq_one_iff] at prop 
       refine' prop.resolve_right fun hf => _
       have := (hax.trans_eq hax').le.trans_eq hf
-      norm_num at this
+      norm_num at this 
     · exact hy.symm
   · -- case 2: `a ≥ a₁`
     have hx₁ : 1 < a.x := by nlinarith [a.prop, h.d_pos]
@@ -710,7 +711,7 @@ theorem eq_zpow_or_neg_zpow {a₁ : Solution₁ d} (h : IsFundamental a₁) (a :
   · exact ⟨n, Or.inl (by exact_mod_cast hn)⟩
   · exact ⟨-n, Or.inl (by simp [hn])⟩
   · exact ⟨n, Or.inr (by simp [hn])⟩
-  · rw [Set.mem_singleton_iff] at hb
+  · rw [Set.mem_singleton_iff] at hb 
     rw [hb]
     exact ⟨-n, Or.inr (by simp [hn])⟩
 #align pell.is_fundamental.eq_zpow_or_neg_zpow Pell.IsFundamental.eq_zpow_or_neg_zpow
@@ -732,20 +733,20 @@ theorem existsUnique_pos_generator (h₀ : 0 < d) (hd : ¬IsSquare d) :
   obtain ⟨n₂, hn₂⟩ := ha₁.eq_zpow_or_neg_zpow a
   rcases hn₂ with (rfl | rfl)
   · rw [← zpow_mul, eq_comm, @eq_comm _ a₁, ← mul_inv_eq_one, ← @mul_inv_eq_one _ _ _ a₁, ←
-      zpow_neg_one, neg_mul, ← zpow_add, ← sub_eq_add_neg] at hn₁
+      zpow_neg_one, neg_mul, ← zpow_add, ← sub_eq_add_neg] at hn₁ 
     cases hn₁
     · rcases int.is_unit_iff.mp
           (isUnit_of_mul_eq_one _ _ <|
             sub_eq_zero.mp <| (ha₁.zpow_eq_one_iff (n₂ * n₁ - 1)).mp hn₁) with
         (rfl | rfl)
       · rw [zpow_one]
-      · rw [zpow_neg_one, y_inv, lt_neg, neg_zero] at Hy
+      · rw [zpow_neg_one, y_inv, lt_neg, neg_zero] at Hy 
         exact False.elim (lt_irrefl _ <| ha₁.2.1.trans Hy)
-    · rw [← zpow_zero a₁, eq_comm] at hn₁
+    · rw [← zpow_zero a₁, eq_comm] at hn₁ 
       exact False.elim (ha₁.zpow_ne_neg_zpow hn₁)
-  · rw [x_neg, lt_neg] at Hx
+  · rw [x_neg, lt_neg] at Hx 
     have := (x_zpow_pos (zero_lt_one.trans ha₁.1) n₂).trans Hx
-    norm_num at this
+    norm_num at this 
 #align pell.exists_unique_pos_generator Pell.existsUnique_pos_generator
 
 /-- A positive solution is a generator (up to sign) of the group of all solutions to the
Diff
@@ -119,17 +119,11 @@ theorem prop (a : Solution₁ d) : a.x ^ 2 - d * a.y ^ 2 = 1 :=
 #align pell.solution₁.prop Pell.Solution₁.prop
 
 /-- An alternative form of the equation, suitable for rewriting `x^2`. -/
-theorem prop_x (a : Solution₁ d) : a.x ^ 2 = 1 + d * a.y ^ 2 :=
-  by
-  rw [← a.prop]
-  ring
+theorem prop_x (a : Solution₁ d) : a.x ^ 2 = 1 + d * a.y ^ 2 := by rw [← a.prop]; ring
 #align pell.solution₁.prop_x Pell.Solution₁.prop_x
 
 /-- An alternative form of the equation, suitable for rewriting `d * y^2`. -/
-theorem prop_y (a : Solution₁ d) : d * a.y ^ 2 = a.x ^ 2 - 1 :=
-  by
-  rw [← a.prop]
-  ring
+theorem prop_y (a : Solution₁ d) : d * a.y ^ 2 = a.x ^ 2 - 1 := by rw [← a.prop]; ring
 #align pell.solution₁.prop_y Pell.Solution₁.prop_y
 
 /-- Two solutions are equal if their `x` and `y` components are equal. -/
@@ -171,9 +165,7 @@ theorem y_one : (1 : Solution₁ d).y = 0 :=
 #align pell.solution₁.y_one Pell.Solution₁.y_one
 
 @[simp]
-theorem x_mul (a b : Solution₁ d) : (a * b).x = a.x * b.x + d * (a.y * b.y) :=
-  by
-  rw [← mul_assoc]
+theorem x_mul (a b : Solution₁ d) : (a * b).x = a.x * b.x + d * (a.y * b.y) := by rw [← mul_assoc];
   rfl
 #align pell.solution₁.x_mul Pell.Solution₁.x_mul
 
@@ -541,10 +533,7 @@ theorem exists_of_not_isSquare (h₀ : 0 < d) (hd : ¬IsSquare d) :
     -- to avoid having to show that the predicate is decidable
     let x₁ := Nat.find P
     obtain ⟨hx, y₁, hy₀, hy₁⟩ := Nat.find_spec P
-    refine'
-      ⟨mk x₁ y₁ hy₁, by
-        rw [x_mk]
-        exact_mod_cast hx, hy₀, fun b hb => _⟩
+    refine' ⟨mk x₁ y₁ hy₁, by rw [x_mk]; exact_mod_cast hx, hy₀, fun b hb => _⟩
     rw [x_mk]
     have hb' := (Int.toNat_of_nonneg <| zero_le_one.trans hb.le).symm
     have hb'' := hb
@@ -566,10 +555,7 @@ theorem y_strictMono {a : Solution₁ d} (h : IsFundamental a) : StrictMono fun
     rw [show (a ^ n).y * a.x - (a ^ n).y = (a ^ n).y * (a.x - 1) by ring]
     refine'
       add_pos_of_pos_of_nonneg (mul_pos (x_zpow_pos h.x_pos _) h.2.1)
-        (mul_nonneg _
-          (by
-            rw [sub_nonneg]
-            exact h.1.le))
+        (mul_nonneg _ (by rw [sub_nonneg]; exact h.1.le))
     rcases hn.eq_or_lt with (rfl | hn)
     · simp only [zpow_zero, y_one]
     · exact (y_zpow_pos h.x_pos h.2.1 hn).le
@@ -621,10 +607,7 @@ of any positive solution. -/
 theorem y_le_y {a₁ : Solution₁ d} (h : IsFundamental a₁) {a : Solution₁ d} (hax : 1 < a.x)
     (hay : 0 < a.y) : a₁.y ≤ a.y :=
   by
-  have H : d * (a₁.y ^ 2 - a.y ^ 2) = a₁.x ^ 2 - a.x ^ 2 :=
-    by
-    rw [a.prop_x, a₁.prop_x]
-    ring
+  have H : d * (a₁.y ^ 2 - a.y ^ 2) = a₁.x ^ 2 - a.x ^ 2 := by rw [a.prop_x, a₁.prop_x]; ring
   rw [← abs_of_pos hay, ← abs_of_pos h.2.1, ← sq_le_sq, ← mul_le_mul_left h.d_pos, ← sub_nonpos, ←
     mul_sub, H, sub_nonpos, sq_le_sq, abs_of_pos (zero_lt_one.trans h.1),
     abs_of_pos (zero_lt_one.trans hax)]
@@ -685,11 +668,7 @@ theorem mul_inv_x_lt_x {a₁ : Solution₁ d} (h : IsFundamental a₁) {a : Solu
     _ < d * a.y ^ 2 + 1 := (lt_add_one _)
     _ = (1 + d * a.y ^ 2) * 1 := by rw [add_comm, mul_one]
     _ ≤ (1 + d * a.y ^ 2) * a₁.y ^ 2 :=
-      (mul_le_mul_left
-            (by
-              have := h.d_pos
-              positivity)).mpr
-        (sq_pos_of_pos h.2.1)
+      (mul_le_mul_left (by have := h.d_pos; positivity)).mpr (sq_pos_of_pos h.2.1)
     
 #align pell.is_fundamental.mul_inv_x_lt_x Pell.IsFundamental.mul_inv_x_lt_x
 
Diff
@@ -534,7 +534,7 @@ theorem exists_of_not_isSquare (h₀ : 0 < d) (hd : ¬IsSquare d) :
   have P : ∃ x' : ℕ, 1 < x' ∧ ∃ y' : ℤ, 0 < y' ∧ (x' : ℤ) ^ 2 - d * y' ^ 2 = 1 :=
     by
     have hax := a.prop
-    lift a.x to ℕ using by positivity
+    lift a.x to ℕ using by positivity with ax
     norm_cast  at ha₁
     exact ⟨ax, ha₁, a.y, ha₂, hax⟩
   classical
@@ -697,7 +697,7 @@ theorem mul_inv_x_lt_x {a₁ : Solution₁ d} (h : IsFundamental a₁) {a : Solu
 theorem eq_pow_of_nonneg {a₁ : Solution₁ d} (h : IsFundamental a₁) {a : Solution₁ d} (hax : 0 < a.x)
     (hay : 0 ≤ a.y) : ∃ n : ℕ, a = a₁ ^ n :=
   by
-  lift a.x to ℕ using hax.le
+  lift a.x to ℕ using hax.le with ax hax'
   induction' ax using Nat.strong_induction_on with x ih generalizing a
   cases' hay.eq_or_lt with hy hy
   · -- case 1: `a = 1`
@@ -716,7 +716,7 @@ theorem eq_pow_of_nonneg {a₁ : Solution₁ d} (h : IsFundamental a₁) {a : So
     have hxx₁ := h.mul_inv_x_pos hx₁ hy
     have hxx₂ := h.mul_inv_x_lt_x hx₁ hy
     have hyy := h.mul_inv_y_nonneg hx₁ hy
-    lift (a * a₁⁻¹).x to ℕ using hxx₁.le
+    lift (a * a₁⁻¹).x to ℕ using hxx₁.le with x' hx'
     obtain ⟨n, hn⟩ := ih x' (by exact_mod_cast hxx₂.trans_eq hax'.symm) hxx₁ hyy hx'
     exact ⟨n + 1, by rw [pow_succ, ← hn, mul_comm a, ← mul_assoc, mul_inv_self, one_mul]⟩
 #align pell.is_fundamental.eq_pow_of_nonneg Pell.IsFundamental.eq_pow_of_nonneg
Diff
@@ -534,7 +534,7 @@ theorem exists_of_not_isSquare (h₀ : 0 < d) (hd : ¬IsSquare d) :
   have P : ∃ x' : ℕ, 1 < x' ∧ ∃ y' : ℤ, 0 < y' ∧ (x' : ℤ) ^ 2 - d * y' ^ 2 = 1 :=
     by
     have hax := a.prop
-    lift a.x to ℕ using by positivity with ax
+    lift a.x to ℕ using by positivity
     norm_cast  at ha₁
     exact ⟨ax, ha₁, a.y, ha₂, hax⟩
   classical
@@ -697,7 +697,7 @@ theorem mul_inv_x_lt_x {a₁ : Solution₁ d} (h : IsFundamental a₁) {a : Solu
 theorem eq_pow_of_nonneg {a₁ : Solution₁ d} (h : IsFundamental a₁) {a : Solution₁ d} (hax : 0 < a.x)
     (hay : 0 ≤ a.y) : ∃ n : ℕ, a = a₁ ^ n :=
   by
-  lift a.x to ℕ using hax.le with ax hax'
+  lift a.x to ℕ using hax.le
   induction' ax using Nat.strong_induction_on with x ih generalizing a
   cases' hay.eq_or_lt with hy hy
   · -- case 1: `a = 1`
@@ -716,7 +716,7 @@ theorem eq_pow_of_nonneg {a₁ : Solution₁ d} (h : IsFundamental a₁) {a : So
     have hxx₁ := h.mul_inv_x_pos hx₁ hy
     have hxx₂ := h.mul_inv_x_lt_x hx₁ hy
     have hyy := h.mul_inv_y_nonneg hx₁ hy
-    lift (a * a₁⁻¹).x to ℕ using hxx₁.le with x' hx'
+    lift (a * a₁⁻¹).x to ℕ using hxx₁.le
     obtain ⟨n, hn⟩ := ih x' (by exact_mod_cast hxx₂.trans_eq hax'.symm) hxx₁ hyy hx'
     exact ⟨n + 1, by rw [pow_succ, ← hn, mul_comm a, ← mul_assoc, mul_inv_self, one_mul]⟩
 #align pell.is_fundamental.eq_pow_of_nonneg Pell.IsFundamental.eq_pow_of_nonneg
Diff
@@ -4,7 +4,7 @@ Released under Apache 2.0 license as described in the file LICENSE.
 Authors: Michael Geißer, Michael Stoll
 
 ! This file was ported from Lean 3 source module number_theory.pell
-! leanprover-community/mathlib commit 0b20dffb0d2141f40a76ad71330dfadb0af75746
+! leanprover-community/mathlib commit 7ad820c4997738e2f542f8a20f32911f52020e26
 ! Please do not edit these lines, except to modify the commit id
 ! if you have ported upstream changes.
 -/
@@ -32,13 +32,13 @@ We then prove the following
 **Theorem.** Let $d$ be a positive integer that is not a square. Then the equation
 $x^2 - d y^2 = 1$ has a nontrivial (i.e., with $y \ne 0$) solution in integers.
 
-See `pell.exists_of_not_is_square` and `pell.exists_nontrivial_of_not_is_square`.
+See `pell.exists_of_not_is_square` and `pell.solution₁.exists_nontrivial_of_not_is_square`.
 
 We then define the *fundamental solution* to be the solution
 with smallest $x$ among all solutions satisfying $x > 1$ and $y > 0$.
 We show that every solution is a power (in the sense of the group structure mentioned above)
 of the fundamental solution up to a (common) sign,
-see `pell.fundamental.eq_zpow_or_neg_zpow`, and that a (positive) solution has this property
+see `pell.is_fundamental.eq_zpow_or_neg_zpow`, and that a (positive) solution has this property
 if and only if it is fundamental, see `pell.pos_generator_iff_fundamental`.
 
 ## References
Diff
@@ -4,7 +4,7 @@ Released under Apache 2.0 license as described in the file LICENSE.
 Authors: Michael Geißer, Michael Stoll
 
 ! This file was ported from Lean 3 source module number_theory.pell
-! leanprover-community/mathlib commit dc65937e7a0fff4677f0f5a7086f42da70a69575
+! leanprover-community/mathlib commit 0b20dffb0d2141f40a76ad71330dfadb0af75746
 ! Please do not edit these lines, except to modify the commit id
 ! if you have ported upstream changes.
 -/
@@ -34,9 +34,12 @@ $x^2 - d y^2 = 1$ has a nontrivial (i.e., with $y \ne 0$) solution in integers.
 
 See `pell.exists_of_not_is_square` and `pell.exists_nontrivial_of_not_is_square`.
 
-The next step (TODO) will be to define the *fundamental solution* as the solution
-with smallest $x$ among all solutions satisfying $x > 1$ and $y > 0$ and to show
-that every solution is a power of the fundamental solution up to a (common) sign.
+We then define the *fundamental solution* to be the solution
+with smallest $x$ among all solutions satisfying $x > 1$ and $y > 0$.
+We show that every solution is a power (in the sense of the group structure mentioned above)
+of the fundamental solution up to a (common) sign,
+see `pell.fundamental.eq_zpow_or_neg_zpow`, and that a (positive) solution has this property
+if and only if it is fundamental, see `pell.pos_generator_iff_fundamental`.
 
 ## References
 
@@ -49,8 +52,7 @@ Pell's equation
 
 ## TODO
 
-* Provide the structure theory of the solution set to Pell's equation
-  and furthermore also for `x ^ 2 - d * y ^ 2 = -1` and further generalizations.
+* Extend to `x ^ 2 - d * y ^ 2 = -1` and further generalizations.
 * Connect solutions to the continued fraction expansion of `√d`.
 -/
 
@@ -228,6 +230,23 @@ theorem y_ne_zero_of_one_lt_x {a : Solution₁ d} (ha : 1 < a.x) : a.y ≠ 0 :=
   exact lt_irrefl _ (((one_lt_sq_iff <| zero_le_one.trans ha.le).mpr ha).trans_eq prop)
 #align pell.solution₁.y_ne_zero_of_one_lt_x Pell.Solution₁.y_ne_zero_of_one_lt_x
 
+/-- If a solution has `x > 1`, then `d` is positive. -/
+theorem d_pos_of_one_lt_x {a : Solution₁ d} (ha : 1 < a.x) : 0 < d :=
+  by
+  refine' pos_of_mul_pos_left _ (sq_nonneg a.y)
+  rw [a.prop_y, sub_pos]
+  exact one_lt_pow ha two_ne_zero
+#align pell.solution₁.d_pos_of_one_lt_x Pell.Solution₁.d_pos_of_one_lt_x
+
+/-- If a solution has `x > 1`, then `d` is not a square. -/
+theorem d_nonsquare_of_one_lt_x {a : Solution₁ d} (ha : 1 < a.x) : ¬IsSquare d :=
+  by
+  have hp := a.prop
+  rintro ⟨b, rfl⟩
+  simp_rw [← sq, ← mul_pow, sq_sub_sq, Int.mul_eq_one_iff_eq_one_or_neg_one] at hp
+  rcases hp with (⟨hp₁, hp₂⟩ | ⟨hp₁, hp₂⟩) <;> linarith [ha, hp₁, hp₂]
+#align pell.solution₁.d_nonsquare_of_one_lt_x Pell.Solution₁.d_nonsquare_of_one_lt_x
+
 /-- A solution with `x = 1` is trivial. -/
 theorem eq_one_of_x_eq_one (h₀ : d ≠ 0) {a : Solution₁ d} (ha : a.x = 1) : a = 1 :=
   by
@@ -287,6 +306,16 @@ theorem y_pow_succ_pos {a : Solution₁ d} (hax : 0 < a.x) (hay : 0 < a.y) (n :
     exact y_mul_pos hax hay (x_pow_pos hax _) ih
 #align pell.solution₁.y_pow_succ_pos Pell.Solution₁.y_pow_succ_pos
 
+/-- If `(x, y)` is a solution with `x` and `y` positive, then all its powers with positive
+exponents have positive `y`. -/
+theorem y_zpow_pos {a : Solution₁ d} (hax : 0 < a.x) (hay : 0 < a.y) {n : ℤ} (hn : 0 < n) :
+    0 < (a ^ n).y := by
+  lift n to ℕ using hn.le
+  norm_cast  at hn⊢
+  rw [← Nat.succ_pred_eq_of_pos hn]
+  exact y_pow_succ_pos hax hay _
+#align pell.solution₁.y_zpow_pos Pell.Solution₁.y_zpow_pos
+
 /-- If `(x, y)` is a solution with `x` positive, then all its powers have positive `x`. -/
 theorem x_zpow_pos {a : Solution₁ d} (hax : 0 < a.x) (n : ℤ) : 0 < (a ^ n).x :=
   by
@@ -452,5 +481,306 @@ end Solution₁
 
 end Existence
 
+/-! ### Fundamental solutions
+
+We define the notion of a *fundamental solution* of Pell's equation and
+show that it exists and is unique (when `d` is positive and non-square)
+and generates the group of solutions up to sign.
+-/
+
+
+variable {d : ℤ}
+
+/-- We define a solution to be *fundamental* if it has `x > 1` and `y > 0`
+and its `x` is the smallest possible among solutions with `x > 1`. -/
+def IsFundamental (a : Solution₁ d) : Prop :=
+  1 < a.x ∧ 0 < a.y ∧ ∀ {b : Solution₁ d}, 1 < b.x → a.x ≤ b.x
+#align pell.is_fundamental Pell.IsFundamental
+
+namespace IsFundamental
+
+open Solution₁
+
+/-- A fundamental solution has positive `x`. -/
+theorem x_pos {a : Solution₁ d} (h : IsFundamental a) : 0 < a.x :=
+  zero_lt_one.trans h.1
+#align pell.is_fundamental.x_pos Pell.IsFundamental.x_pos
+
+/-- If a fundamental solution exists, then `d` must be positive. -/
+theorem d_pos {a : Solution₁ d} (h : IsFundamental a) : 0 < d :=
+  d_pos_of_one_lt_x h.1
+#align pell.is_fundamental.d_pos Pell.IsFundamental.d_pos
+
+/-- If a fundamental solution exists, then `d` must be a non-square. -/
+theorem d_nonsquare {a : Solution₁ d} (h : IsFundamental a) : ¬IsSquare d :=
+  d_nonsquare_of_one_lt_x h.1
+#align pell.is_fundamental.d_nonsquare Pell.IsFundamental.d_nonsquare
+
+/-- If there is a fundamental solution, it is unique. -/
+theorem subsingleton {a b : Solution₁ d} (ha : IsFundamental a) (hb : IsFundamental b) : a = b :=
+  by
+  have hx := le_antisymm (ha.2.2 hb.1) (hb.2.2 ha.1)
+  refine' solution₁.ext hx _
+  have : d * a.y ^ 2 = d * b.y ^ 2 := by rw [a.prop_y, b.prop_y, hx]
+  exact (sq_eq_sq ha.2.1.le hb.2.1.le).mp (Int.eq_of_mul_eq_mul_left ha.d_pos.ne' this)
+#align pell.is_fundamental.subsingleton Pell.IsFundamental.subsingleton
+
+/-- If `d` is positive and not a square, then a fundamental solution exists. -/
+theorem exists_of_not_isSquare (h₀ : 0 < d) (hd : ¬IsSquare d) :
+    ∃ a : Solution₁ d, IsFundamental a :=
+  by
+  obtain ⟨a, ha₁, ha₂⟩ := exists_pos_of_not_is_square h₀ hd
+  -- convert to `x : ℕ` to be able to use `nat.find`
+  have P : ∃ x' : ℕ, 1 < x' ∧ ∃ y' : ℤ, 0 < y' ∧ (x' : ℤ) ^ 2 - d * y' ^ 2 = 1 :=
+    by
+    have hax := a.prop
+    lift a.x to ℕ using by positivity with ax
+    norm_cast  at ha₁
+    exact ⟨ax, ha₁, a.y, ha₂, hax⟩
+  classical
+    -- to avoid having to show that the predicate is decidable
+    let x₁ := Nat.find P
+    obtain ⟨hx, y₁, hy₀, hy₁⟩ := Nat.find_spec P
+    refine'
+      ⟨mk x₁ y₁ hy₁, by
+        rw [x_mk]
+        exact_mod_cast hx, hy₀, fun b hb => _⟩
+    rw [x_mk]
+    have hb' := (Int.toNat_of_nonneg <| zero_le_one.trans hb.le).symm
+    have hb'' := hb
+    rw [hb'] at hb⊢
+    norm_cast  at hb⊢
+    refine' Nat.find_min' P ⟨hb, |b.y|, abs_pos.mpr <| y_ne_zero_of_one_lt_x hb'', _⟩
+    rw [← hb', sq_abs]
+    exact b.prop
+#align pell.is_fundamental.exists_of_not_is_square Pell.IsFundamental.exists_of_not_isSquare
+
+/-- The map sending an integer `n` to the `y`-coordinate of `a^n` for a fundamental
+solution `a` is stritcly increasing. -/
+theorem y_strictMono {a : Solution₁ d} (h : IsFundamental a) : StrictMono fun n : ℤ => (a ^ n).y :=
+  by
+  have H : ∀ n : ℤ, 0 ≤ n → (a ^ n).y < (a ^ (n + 1)).y :=
+    by
+    intro n hn
+    rw [← sub_pos, zpow_add, zpow_one, y_mul, add_sub_assoc]
+    rw [show (a ^ n).y * a.x - (a ^ n).y = (a ^ n).y * (a.x - 1) by ring]
+    refine'
+      add_pos_of_pos_of_nonneg (mul_pos (x_zpow_pos h.x_pos _) h.2.1)
+        (mul_nonneg _
+          (by
+            rw [sub_nonneg]
+            exact h.1.le))
+    rcases hn.eq_or_lt with (rfl | hn)
+    · simp only [zpow_zero, y_one]
+    · exact (y_zpow_pos h.x_pos h.2.1 hn).le
+  refine' strictMono_int_of_lt_succ fun n => _
+  cases' le_or_lt 0 n with hn hn
+  · exact H n hn
+  · let m : ℤ := -n - 1
+    have hm : n = -m - 1 := by simp only [neg_sub, sub_neg_eq_add, add_tsub_cancel_left]
+    rw [hm, sub_add_cancel, ← neg_add', zpow_neg, zpow_neg, y_inv, y_inv, neg_lt_neg_iff]
+    exact H _ (by linarith [hn])
+#align pell.is_fundamental.y_strict_mono Pell.IsFundamental.y_strictMono
+
+/-- If `a` is a fundamental solution, then `(a^m).y < (a^n).y` if and only if `m < n`. -/
+theorem zpow_y_lt_iff_lt {a : Solution₁ d} (h : IsFundamental a) (m n : ℤ) :
+    (a ^ m).y < (a ^ n).y ↔ m < n :=
+  by
+  refine' ⟨fun H => _, fun H => h.y_strict_mono H⟩
+  contrapose! H
+  exact h.y_strict_mono.monotone H
+#align pell.is_fundamental.zpow_y_lt_iff_lt Pell.IsFundamental.zpow_y_lt_iff_lt
+
+/-- The `n`th power of a fundamental solution is trivial if and only if `n = 0`. -/
+theorem zpow_eq_one_iff {a : Solution₁ d} (h : IsFundamental a) (n : ℤ) : a ^ n = 1 ↔ n = 0 :=
+  by
+  rw [← zpow_zero a]
+  exact ⟨fun H => h.y_strict_mono.injective (congr_arg solution₁.y H), fun H => H ▸ rfl⟩
+#align pell.is_fundamental.zpow_eq_one_iff Pell.IsFundamental.zpow_eq_one_iff
+
+/-- A power of a fundamental solution is never equal to the negative of a power of this
+fundamental solution. -/
+theorem zpow_ne_neg_zpow {a : Solution₁ d} (h : IsFundamental a) {n n' : ℤ} : a ^ n ≠ -a ^ n' :=
+  by
+  intro hf
+  apply_fun solution₁.x  at hf
+  have H := x_zpow_pos h.x_pos n
+  rw [hf, x_neg, lt_neg, neg_zero] at H
+  exact lt_irrefl _ ((x_zpow_pos h.x_pos n').trans H)
+#align pell.is_fundamental.zpow_ne_neg_zpow Pell.IsFundamental.zpow_ne_neg_zpow
+
+/-- The `x`-coordinate of a fundamental solution is a lower bound for the `x`-coordinate
+of any positive solution. -/
+theorem x_le_x {a₁ : Solution₁ d} (h : IsFundamental a₁) {a : Solution₁ d} (hax : 1 < a.x) :
+    a₁.x ≤ a.x :=
+  h.2.2 hax
+#align pell.is_fundamental.x_le_x Pell.IsFundamental.x_le_x
+
+/-- The `y`-coordinate of a fundamental solution is a lower bound for the `y`-coordinate
+of any positive solution. -/
+theorem y_le_y {a₁ : Solution₁ d} (h : IsFundamental a₁) {a : Solution₁ d} (hax : 1 < a.x)
+    (hay : 0 < a.y) : a₁.y ≤ a.y :=
+  by
+  have H : d * (a₁.y ^ 2 - a.y ^ 2) = a₁.x ^ 2 - a.x ^ 2 :=
+    by
+    rw [a.prop_x, a₁.prop_x]
+    ring
+  rw [← abs_of_pos hay, ← abs_of_pos h.2.1, ← sq_le_sq, ← mul_le_mul_left h.d_pos, ← sub_nonpos, ←
+    mul_sub, H, sub_nonpos, sq_le_sq, abs_of_pos (zero_lt_one.trans h.1),
+    abs_of_pos (zero_lt_one.trans hax)]
+  exact h.x_le_x hax
+#align pell.is_fundamental.y_le_y Pell.IsFundamental.y_le_y
+
+-- helper lemma for the next three results
+theorem x_mul_y_le_y_mul_x {a₁ : Solution₁ d} (h : IsFundamental a₁) {a : Solution₁ d}
+    (hax : 1 < a.x) (hay : 0 < a.y) : a.x * a₁.y ≤ a.y * a₁.x :=
+  by
+  rw [← abs_of_pos <| zero_lt_one.trans hax, ← abs_of_pos hay, ← abs_of_pos h.x_pos, ←
+    abs_of_pos h.2.1, ← abs_mul, ← abs_mul, ← sq_le_sq, mul_pow, mul_pow, a.prop_x, a₁.prop_x, ←
+    sub_nonneg]
+  ring_nf
+  rw [sub_nonneg, sq_le_sq, abs_of_pos hay, abs_of_pos h.2.1]
+  exact h.y_le_y hax hay
+#align pell.is_fundamental.x_mul_y_le_y_mul_x Pell.IsFundamental.x_mul_y_le_y_mul_x
+
+/-- If we multiply a positive solution with the inverse of a fundamental solution,
+the `y`-coordinate remains nonnegative. -/
+theorem mul_inv_y_nonneg {a₁ : Solution₁ d} (h : IsFundamental a₁) {a : Solution₁ d} (hax : 1 < a.x)
+    (hay : 0 < a.y) : 0 ≤ (a * a₁⁻¹).y := by
+  simpa only [y_inv, mul_neg, y_mul, le_neg_add_iff_add_le, add_zero] using
+    h.x_mul_y_le_y_mul_x hax hay
+#align pell.is_fundamental.mul_inv_y_nonneg Pell.IsFundamental.mul_inv_y_nonneg
+
+/-- If we multiply a positive solution with the inverse of a fundamental solution,
+the `x`-coordinate stays positive. -/
+theorem mul_inv_x_pos {a₁ : Solution₁ d} (h : IsFundamental a₁) {a : Solution₁ d} (hax : 1 < a.x)
+    (hay : 0 < a.y) : 0 < (a * a₁⁻¹).x :=
+  by
+  simp only [x_mul, x_inv, y_inv, mul_neg, lt_add_neg_iff_add_lt, zero_add]
+  refine' (mul_lt_mul_left <| zero_lt_one.trans hax).mp _
+  rw [(by ring : a.x * (d * (a.y * a₁.y)) = d * a.y * (a.x * a₁.y))]
+  refine' ((mul_le_mul_left <| mul_pos h.d_pos hay).mpr <| x_mul_y_le_y_mul_x h hax hay).trans_lt _
+  rw [← mul_assoc, mul_assoc d, ← sq, a.prop_y, ← sub_pos]
+  ring_nf
+  exact zero_lt_one.trans h.1
+#align pell.is_fundamental.mul_inv_x_pos Pell.IsFundamental.mul_inv_x_pos
+
+/-- If we multiply a positive solution with the inverse of a fundamental solution,
+the `x`-coordinate decreases. -/
+theorem mul_inv_x_lt_x {a₁ : Solution₁ d} (h : IsFundamental a₁) {a : Solution₁ d} (hax : 1 < a.x)
+    (hay : 0 < a.y) : (a * a₁⁻¹).x < a.x :=
+  by
+  simp only [x_mul, x_inv, y_inv, mul_neg, add_neg_lt_iff_le_add']
+  refine' (mul_lt_mul_left h.2.1).mp _
+  rw [(by ring : a₁.y * (a.x * a₁.x) = a.x * a₁.y * a₁.x)]
+  refine'
+    ((mul_le_mul_right <| zero_lt_one.trans h.1).mpr <| x_mul_y_le_y_mul_x h hax hay).trans_lt _
+  rw [mul_assoc, ← sq, a₁.prop_x, ← sub_neg]
+  ring_nf
+  rw [sub_neg, ← abs_of_pos hay, ← abs_of_pos h.2.1, ← abs_of_pos <| zero_lt_one.trans hax, ←
+    abs_mul, ← sq_lt_sq, mul_pow, a.prop_x]
+  calc
+    a.y ^ 2 = 1 * a.y ^ 2 := (one_mul _).symm
+    _ ≤ d * a.y ^ 2 := ((mul_le_mul_right <| sq_pos_of_pos hay).mpr h.d_pos)
+    _ < d * a.y ^ 2 + 1 := (lt_add_one _)
+    _ = (1 + d * a.y ^ 2) * 1 := by rw [add_comm, mul_one]
+    _ ≤ (1 + d * a.y ^ 2) * a₁.y ^ 2 :=
+      (mul_le_mul_left
+            (by
+              have := h.d_pos
+              positivity)).mpr
+        (sq_pos_of_pos h.2.1)
+    
+#align pell.is_fundamental.mul_inv_x_lt_x Pell.IsFundamental.mul_inv_x_lt_x
+
+/-- Any nonnegative solution is a power with nonnegative exponent of a fundamental solution. -/
+theorem eq_pow_of_nonneg {a₁ : Solution₁ d} (h : IsFundamental a₁) {a : Solution₁ d} (hax : 0 < a.x)
+    (hay : 0 ≤ a.y) : ∃ n : ℕ, a = a₁ ^ n :=
+  by
+  lift a.x to ℕ using hax.le with ax hax'
+  induction' ax using Nat.strong_induction_on with x ih generalizing a
+  cases' hay.eq_or_lt with hy hy
+  · -- case 1: `a = 1`
+    refine' ⟨0, _⟩
+    simp only [pow_zero]
+    ext <;> simp only [x_one, y_one]
+    · have prop := a.prop
+      rw [← hy, sq (0 : ℤ), MulZeroClass.zero_mul, MulZeroClass.mul_zero, sub_zero,
+        sq_eq_one_iff] at prop
+      refine' prop.resolve_right fun hf => _
+      have := (hax.trans_eq hax').le.trans_eq hf
+      norm_num at this
+    · exact hy.symm
+  · -- case 2: `a ≥ a₁`
+    have hx₁ : 1 < a.x := by nlinarith [a.prop, h.d_pos]
+    have hxx₁ := h.mul_inv_x_pos hx₁ hy
+    have hxx₂ := h.mul_inv_x_lt_x hx₁ hy
+    have hyy := h.mul_inv_y_nonneg hx₁ hy
+    lift (a * a₁⁻¹).x to ℕ using hxx₁.le with x' hx'
+    obtain ⟨n, hn⟩ := ih x' (by exact_mod_cast hxx₂.trans_eq hax'.symm) hxx₁ hyy hx'
+    exact ⟨n + 1, by rw [pow_succ, ← hn, mul_comm a, ← mul_assoc, mul_inv_self, one_mul]⟩
+#align pell.is_fundamental.eq_pow_of_nonneg Pell.IsFundamental.eq_pow_of_nonneg
+
+/-- Every solution is, up to a sign, a power of a given fundamental solution. -/
+theorem eq_zpow_or_neg_zpow {a₁ : Solution₁ d} (h : IsFundamental a₁) (a : Solution₁ d) :
+    ∃ n : ℤ, a = a₁ ^ n ∨ a = -a₁ ^ n :=
+  by
+  obtain ⟨b, hbx, hby, hb⟩ := exists_pos_variant h.d_pos a
+  obtain ⟨n, hn⟩ := h.eq_pow_of_nonneg hbx hby
+  rcases hb with (rfl | rfl | rfl | hb)
+  · exact ⟨n, Or.inl (by exact_mod_cast hn)⟩
+  · exact ⟨-n, Or.inl (by simp [hn])⟩
+  · exact ⟨n, Or.inr (by simp [hn])⟩
+  · rw [Set.mem_singleton_iff] at hb
+    rw [hb]
+    exact ⟨-n, Or.inr (by simp [hn])⟩
+#align pell.is_fundamental.eq_zpow_or_neg_zpow Pell.IsFundamental.eq_zpow_or_neg_zpow
+
+end IsFundamental
+
+open Solution₁ IsFundamental
+
+/-- When `d` is positive and not a square, then the group of solutions to the Pell equation
+`x^2 - d*y^2 = 1` has a unique positive generator (up to sign). -/
+theorem existsUnique_pos_generator (h₀ : 0 < d) (hd : ¬IsSquare d) :
+    ∃! a₁ : Solution₁ d,
+      1 < a₁.x ∧ 0 < a₁.y ∧ ∀ a : Solution₁ d, ∃ n : ℤ, a = a₁ ^ n ∨ a = -a₁ ^ n :=
+  by
+  obtain ⟨a₁, ha₁⟩ := is_fundamental.exists_of_not_is_square h₀ hd
+  refine' ⟨a₁, ⟨ha₁.1, ha₁.2.1, ha₁.eq_zpow_or_neg_zpow⟩, fun a (H : 1 < _ ∧ _) => _⟩
+  obtain ⟨Hx, Hy, H⟩ := H
+  obtain ⟨n₁, hn₁⟩ := H a₁
+  obtain ⟨n₂, hn₂⟩ := ha₁.eq_zpow_or_neg_zpow a
+  rcases hn₂ with (rfl | rfl)
+  · rw [← zpow_mul, eq_comm, @eq_comm _ a₁, ← mul_inv_eq_one, ← @mul_inv_eq_one _ _ _ a₁, ←
+      zpow_neg_one, neg_mul, ← zpow_add, ← sub_eq_add_neg] at hn₁
+    cases hn₁
+    · rcases int.is_unit_iff.mp
+          (isUnit_of_mul_eq_one _ _ <|
+            sub_eq_zero.mp <| (ha₁.zpow_eq_one_iff (n₂ * n₁ - 1)).mp hn₁) with
+        (rfl | rfl)
+      · rw [zpow_one]
+      · rw [zpow_neg_one, y_inv, lt_neg, neg_zero] at Hy
+        exact False.elim (lt_irrefl _ <| ha₁.2.1.trans Hy)
+    · rw [← zpow_zero a₁, eq_comm] at hn₁
+      exact False.elim (ha₁.zpow_ne_neg_zpow hn₁)
+  · rw [x_neg, lt_neg] at Hx
+    have := (x_zpow_pos (zero_lt_one.trans ha₁.1) n₂).trans Hx
+    norm_num at this
+#align pell.exists_unique_pos_generator Pell.existsUnique_pos_generator
+
+/-- A positive solution is a generator (up to sign) of the group of all solutions to the
+Pell equation `x^2 - d*y^2 = 1` if and only if it is a fundamental solution. -/
+theorem pos_generator_iff_fundamental (a : Solution₁ d) :
+    (1 < a.x ∧ 0 < a.y ∧ ∀ b : Solution₁ d, ∃ n : ℤ, b = a ^ n ∨ b = -a ^ n) ↔ IsFundamental a :=
+  by
+  refine' ⟨fun h => _, fun H => ⟨H.1, H.2.1, H.eq_zpow_or_neg_zpow⟩⟩
+  have h₀ := d_pos_of_one_lt_x h.1
+  have hd := d_nonsquare_of_one_lt_x h.1
+  obtain ⟨a₁, ha₁⟩ := is_fundamental.exists_of_not_is_square h₀ hd
+  obtain ⟨b, hb₁, hb₂⟩ := exists_unique_pos_generator h₀ hd
+  rwa [hb₂ a h, ← hb₂ a₁ ⟨ha₁.1, ha₁.2.1, ha₁.eq_zpow_or_neg_zpow⟩]
+#align pell.pos_generator_iff_fundamental Pell.pos_generator_iff_fundamental
+
 end Pell
 
Diff
@@ -4,7 +4,7 @@ Released under Apache 2.0 license as described in the file LICENSE.
 Authors: Michael Geißer, Michael Stoll
 
 ! This file was ported from Lean 3 source module number_theory.pell
-! leanprover-community/mathlib commit 842557b6253ace82c125d567a80b5f74f6ce9f99
+! leanprover-community/mathlib commit dc65937e7a0fff4677f0f5a7086f42da70a69575
 ! Please do not edit these lines, except to modify the commit id
 ! if you have ported upstream changes.
 -/
@@ -16,16 +16,27 @@ import Mathbin.NumberTheory.Zsqrtd.Basic
 /-!
 # Pell's Equation
 
-We prove the following
+*Pell's Equation* is the equation $x^2 - d y^2 = 1$, where $d$ is a positive integer
+that is not a square, and one is interested in solutions in integers $x$ and $y$.
+
+In this file, we aim at providing all of the essential theory of Pell's Equation for general $d$
+(as opposed to the contents of `number_theory.pell_matiyasevic`, which is specific to the case
+$d = a^2 - 1$ for some $a > 1$).
+
+We begin by defining a type `pell.solution₁ d` for solutions of the equation,
+show that it has a natural structure as an abelian group, and prove some basic
+properties.
+
+We then prove the following
 
 **Theorem.** Let $d$ be a positive integer that is not a square. Then the equation
 $x^2 - d y^2 = 1$ has a nontrivial (i.e., with $y \ne 0$) solution in integers.
 
-See `pell.exists_of_not_is_square`.
+See `pell.exists_of_not_is_square` and `pell.exists_nontrivial_of_not_is_square`.
 
-This is the beginning of a development that aims at providing all of the essential theory
-of Pell's Equation for general $d$ (as opposed to the contents of `number_theory.pell_matiyasevic`,
-which is specific to the case $d = a^2 - 1$ for some $a > 1$).
+The next step (TODO) will be to define the *fundamental solution* as the solution
+with smallest $x$ among all solutions satisfying $x > 1$ and $y > 0$ and to show
+that every solution is a power of the fundamental solution up to a (common) sign.
 
 ## References
 
@@ -189,6 +200,129 @@ theorem y_neg (a : Solution₁ d) : (-a).y = -a.y :=
   rfl
 #align pell.solution₁.y_neg Pell.Solution₁.y_neg
 
+/-- When `d` is negative, then `x` or `y` must be zero in a solution. -/
+theorem eq_zero_of_d_neg (h₀ : d < 0) (a : Solution₁ d) : a.x = 0 ∨ a.y = 0 :=
+  by
+  have h := a.prop
+  contrapose! h
+  have h1 := sq_pos_of_ne_zero a.x h.1
+  have h2 := sq_pos_of_ne_zero a.y h.2
+  nlinarith
+#align pell.solution₁.eq_zero_of_d_neg Pell.Solution₁.eq_zero_of_d_neg
+
+/-- A solution has `x ≠ 0`. -/
+theorem x_ne_zero (h₀ : 0 ≤ d) (a : Solution₁ d) : a.x ≠ 0 :=
+  by
+  intro hx
+  have h : 0 ≤ d * a.y ^ 2 := mul_nonneg h₀ (sq_nonneg _)
+  rw [a.prop_y, hx, sq, MulZeroClass.zero_mul, zero_sub] at h
+  exact not_le.mpr (neg_one_lt_zero : (-1 : ℤ) < 0) h
+#align pell.solution₁.x_ne_zero Pell.Solution₁.x_ne_zero
+
+/-- A solution with `x > 1` must have `y ≠ 0`. -/
+theorem y_ne_zero_of_one_lt_x {a : Solution₁ d} (ha : 1 < a.x) : a.y ≠ 0 :=
+  by
+  intro hy
+  have prop := a.prop
+  rw [hy, sq (0 : ℤ), MulZeroClass.zero_mul, MulZeroClass.mul_zero, sub_zero] at prop
+  exact lt_irrefl _ (((one_lt_sq_iff <| zero_le_one.trans ha.le).mpr ha).trans_eq prop)
+#align pell.solution₁.y_ne_zero_of_one_lt_x Pell.Solution₁.y_ne_zero_of_one_lt_x
+
+/-- A solution with `x = 1` is trivial. -/
+theorem eq_one_of_x_eq_one (h₀ : d ≠ 0) {a : Solution₁ d} (ha : a.x = 1) : a = 1 :=
+  by
+  have prop := a.prop_y
+  rw [ha, one_pow, sub_self, mul_eq_zero, or_iff_right h₀, sq_eq_zero_iff] at prop
+  exact ext ha prop
+#align pell.solution₁.eq_one_of_x_eq_one Pell.Solution₁.eq_one_of_x_eq_one
+
+/-- A solution is `1` or `-1` if and only if `y = 0`. -/
+theorem eq_one_or_neg_one_iff_y_eq_zero {a : Solution₁ d} : a = 1 ∨ a = -1 ↔ a.y = 0 :=
+  by
+  refine' ⟨fun H => H.elim (fun h => by simp [h]) fun h => by simp [h], fun H => _⟩
+  have prop := a.prop
+  rw [H, sq (0 : ℤ), MulZeroClass.mul_zero, MulZeroClass.mul_zero, sub_zero, sq_eq_one_iff] at prop
+  exact prop.imp (fun h => ext h H) fun h => ext h H
+#align pell.solution₁.eq_one_or_neg_one_iff_y_eq_zero Pell.Solution₁.eq_one_or_neg_one_iff_y_eq_zero
+
+/-- The set of solutions with `x > 0` is closed under multiplication. -/
+theorem x_mul_pos {a b : Solution₁ d} (ha : 0 < a.x) (hb : 0 < b.x) : 0 < (a * b).x :=
+  by
+  simp only [x_mul]
+  refine' neg_lt_iff_pos_add'.mp (abs_lt.mp _).1
+  rw [← abs_of_pos ha, ← abs_of_pos hb, ← abs_mul, ← sq_lt_sq, mul_pow a.x, a.prop_x, b.prop_x, ←
+    sub_pos]
+  ring_nf
+  cases' le_or_lt 0 d with h h
+  · positivity
+  · rw [(eq_zero_of_d_neg h a).resolve_left ha.ne', (eq_zero_of_d_neg h b).resolve_left hb.ne',
+      zero_pow two_pos, zero_add, MulZeroClass.zero_mul, zero_add]
+    exact one_pos
+#align pell.solution₁.x_mul_pos Pell.Solution₁.x_mul_pos
+
+/-- The set of solutions with `x` and `y` positive is closed under multiplication. -/
+theorem y_mul_pos {a b : Solution₁ d} (hax : 0 < a.x) (hay : 0 < a.y) (hbx : 0 < b.x)
+    (hby : 0 < b.y) : 0 < (a * b).y := by
+  simp only [y_mul]
+  positivity
+#align pell.solution₁.y_mul_pos Pell.Solution₁.y_mul_pos
+
+/-- If `(x, y)` is a solution with `x` positive, then all its powers with natural exponents
+have positive `x`. -/
+theorem x_pow_pos {a : Solution₁ d} (hax : 0 < a.x) (n : ℕ) : 0 < (a ^ n).x :=
+  by
+  induction' n with n ih
+  · simp only [pow_zero, x_one, zero_lt_one]
+  · rw [pow_succ]
+    exact x_mul_pos hax ih
+#align pell.solution₁.x_pow_pos Pell.Solution₁.x_pow_pos
+
+/-- If `(x, y)` is a solution with `x` and `y` positive, then all its powers with positive
+natural exponents have positive `y`. -/
+theorem y_pow_succ_pos {a : Solution₁ d} (hax : 0 < a.x) (hay : 0 < a.y) (n : ℕ) :
+    0 < (a ^ n.succ).y := by
+  induction' n with n ih
+  · simp only [hay, pow_one]
+  · rw [pow_succ]
+    exact y_mul_pos hax hay (x_pow_pos hax _) ih
+#align pell.solution₁.y_pow_succ_pos Pell.Solution₁.y_pow_succ_pos
+
+/-- If `(x, y)` is a solution with `x` positive, then all its powers have positive `x`. -/
+theorem x_zpow_pos {a : Solution₁ d} (hax : 0 < a.x) (n : ℤ) : 0 < (a ^ n).x :=
+  by
+  cases n
+  · rw [zpow_ofNat]
+    exact x_pow_pos hax n
+  · rw [zpow_negSucc]
+    exact x_pow_pos hax (n + 1)
+#align pell.solution₁.x_zpow_pos Pell.Solution₁.x_zpow_pos
+
+/-- If `(x, y)` is a solution with `x` and `y` positive, then the `y` component of any power
+has the same sign as the exponent. -/
+theorem sign_y_zpow_eq_sign_of_x_pos_of_y_pos {a : Solution₁ d} (hax : 0 < a.x) (hay : 0 < a.y)
+    (n : ℤ) : (a ^ n).y.sign = n.sign :=
+  by
+  rcases n with ((_ | _) | _)
+  · rfl
+  · rw [zpow_ofNat]
+    exact Int.sign_eq_one_of_pos (y_pow_succ_pos hax hay n)
+  · rw [zpow_negSucc]
+    exact Int.sign_eq_neg_one_of_neg (neg_neg_of_pos (y_pow_succ_pos hax hay n))
+#align pell.solution₁.sign_y_zpow_eq_sign_of_x_pos_of_y_pos Pell.Solution₁.sign_y_zpow_eq_sign_of_x_pos_of_y_pos
+
+/-- If `a` is any solution, then one of `a`, `a⁻¹`, `-a`, `-a⁻¹` has
+positive `x` and nonnegative `y`. -/
+theorem exists_pos_variant (h₀ : 0 < d) (a : Solution₁ d) :
+    ∃ b : Solution₁ d, 0 < b.x ∧ 0 ≤ b.y ∧ a ∈ ({b, b⁻¹, -b, -b⁻¹} : Set (Solution₁ d)) := by
+  refine'
+        (lt_or_gt_of_ne (a.x_ne_zero h₀.le)).elim
+          ((le_total 0 a.y).elim (fun hy hx => ⟨-a⁻¹, _, _, _⟩) fun hy hx => ⟨-a, _, _, _⟩)
+          ((le_total 0 a.y).elim (fun hy hx => ⟨a, hx, hy, _⟩) fun hy hx => ⟨a⁻¹, hx, _, _⟩) <;>
+      simp only [neg_neg, inv_inv, neg_inv, Set.mem_insert_iff, Set.mem_singleton_iff, true_or_iff,
+        eq_self_iff_true, x_neg, x_inv, y_neg, y_inv, neg_pos, neg_nonneg, or_true_iff] <;>
+    assumption
+#align pell.solution₁.exists_pos_variant Pell.Solution₁.exists_pos_variant
+
 end Solution₁
 
 section Existence
@@ -291,16 +425,30 @@ theorem exists_iff_not_isSquare (h₀ : 0 < d) :
   simpa [mul_self_pos.mp h₀, sub_eq_add_neg, eq_neg_self_iff] using Int.eq_of_mul_eq_one hxy
 #align pell.exists_iff_not_is_square Pell.exists_iff_not_isSquare
 
+namespace Solution₁
+
+/-- If `d` is a positive integer that is not a square, then there exists a nontrivial solution
+to the Pell equation `x^2 - d*y^2 = 1`. -/
+theorem exists_nontrivial_of_not_isSquare (h₀ : 0 < d) (hd : ¬IsSquare d) :
+    ∃ a : Solution₁ d, a ≠ 1 ∧ a ≠ -1 :=
+  by
+  obtain ⟨x, y, prop, hy⟩ := exists_of_not_is_square h₀ hd
+  refine' ⟨mk x y prop, fun H => _, fun H => _⟩ <;> apply_fun solution₁.y  at H <;>
+    simpa only [hy] using H
+#align pell.solution₁.exists_nontrivial_of_not_is_square Pell.Solution₁.exists_nontrivial_of_not_isSquare
+
 /-- If `d` is a positive integer that is not a square, then there exists a solution
 to the Pell equation `x^2 - d*y^2 = 1` with `x > 1` and `y > 0`. -/
 theorem exists_pos_of_not_isSquare (h₀ : 0 < d) (hd : ¬IsSquare d) :
-    ∃ x y : ℤ, x ^ 2 - d * y ^ 2 = 1 ∧ 1 < x ∧ 0 < y :=
+    ∃ a : Solution₁ d, 1 < a.x ∧ 0 < a.y :=
   by
   obtain ⟨x, y, h, hy⟩ := exists_of_not_is_square h₀ hd
-  refine' ⟨|x|, |y|, by rwa [sq_abs, sq_abs], _, abs_pos.mpr hy⟩
-  rw [← one_lt_sq_iff_one_lt_abs, eq_add_of_sub_eq h, lt_add_iff_pos_right]
+  refine' ⟨mk (|x|) (|y|) (by rwa [sq_abs, sq_abs]), _, abs_pos.mpr hy⟩
+  rw [x_mk, ← one_lt_sq_iff_one_lt_abs, eq_add_of_sub_eq h, lt_add_iff_pos_right]
   exact mul_pos h₀ (sq_pos_of_ne_zero y hy)
-#align pell.exists_pos_of_not_is_square Pell.exists_pos_of_not_isSquare
+#align pell.solution₁.exists_pos_of_not_is_square Pell.Solution₁.exists_pos_of_not_isSquare
+
+end Solution₁
 
 end Existence
 
Diff
@@ -4,7 +4,7 @@ Released under Apache 2.0 license as described in the file LICENSE.
 Authors: Michael Geißer, Michael Stoll
 
 ! This file was ported from Lean 3 source module number_theory.pell
-! leanprover-community/mathlib commit 7ec294687917cbc5c73620b4414ae9b5dd9ae1b4
+! leanprover-community/mathlib commit 842557b6253ace82c125d567a80b5f74f6ce9f99
 ! Please do not edit these lines, except to modify the commit id
 ! if you have ported upstream changes.
 -/
@@ -46,114 +46,6 @@ Pell's equation
 
 namespace Pell
 
-section Existence
-
-variable {d : ℤ}
-
-open Set Real
-
-/-- If `d` is a positive integer that is not a square, then there is a nontrivial solution
-to the Pell equation `x^2 - d*y^2 = 1`. -/
-theorem exists_of_not_isSquare (h₀ : 0 < d) (hd : ¬IsSquare d) :
-    ∃ x y : ℤ, x ^ 2 - d * y ^ 2 = 1 ∧ y ≠ 0 :=
-  by
-  let ξ : ℝ := sqrt d
-  have hξ : Irrational ξ :=
-    by
-    refine' irrational_nrt_of_notint_nrt 2 d (sq_sqrt <| int.cast_nonneg.mpr h₀.le) _ two_pos
-    rintro ⟨x, hx⟩
-    refine' hd ⟨x, @Int.cast_injective ℝ _ _ d (x * x) _⟩
-    rw [← sq_sqrt <| int.cast_nonneg.mpr h₀.le, Int.cast_mul, ← hx, sq]
-  obtain ⟨M, hM₁⟩ := exists_int_gt (2 * |ξ| + 1)
-  have hM : { q : ℚ | |q.1 ^ 2 - d * q.2 ^ 2| < M }.Infinite :=
-    by
-    refine' infinite.mono (fun q h => _) (infinite_rat_abs_sub_lt_one_div_denom_sq_of_irrational hξ)
-    have h0 : 0 < (q.2 : ℝ) ^ 2 := pow_pos (nat.cast_pos.mpr q.pos) 2
-    have h1 : (q.num : ℝ) / (q.denom : ℝ) = q := by exact_mod_cast q.num_div_denom
-    rw [mem_set_of, abs_sub_comm, ← @Int.cast_lt ℝ, ← div_lt_div_right (abs_pos_of_pos h0)]
-    push_cast
-    rw [← abs_div, abs_sq, sub_div, mul_div_cancel _ h0.ne', ← div_pow, h1, ←
-      sq_sqrt (int.cast_pos.mpr h₀).le, sq_sub_sq, abs_mul, ← mul_one_div]
-    refine' mul_lt_mul'' (((abs_add ξ q).trans _).trans_lt hM₁) h (abs_nonneg _) (abs_nonneg _)
-    rw [two_mul, add_assoc, add_le_add_iff_left, ← sub_le_iff_le_add']
-    rw [mem_set_of, abs_sub_comm] at h
-    refine' (abs_sub_abs_le_abs_sub (q : ℝ) ξ).trans (h.le.trans _)
-    rw [div_le_one h0, one_le_sq_iff_one_le_abs, Nat.abs_cast, Nat.one_le_cast]
-    exact q.pos
-  obtain ⟨m, hm⟩ : ∃ m : ℤ, { q : ℚ | q.1 ^ 2 - d * q.2 ^ 2 = m }.Infinite :=
-    by
-    contrapose! hM
-    simp only [not_infinite] at hM⊢
-    refine' (congr_arg _ (ext fun x => _)).mp (finite.bUnion (finite_Ioo (-M) M) fun m _ => hM m)
-    simp only [abs_lt, mem_set_of_eq, mem_Ioo, mem_Union, exists_prop, exists_eq_right']
-  have hm₀ : m ≠ 0 := by
-    rintro rfl
-    obtain ⟨q, hq⟩ := hm.nonempty
-    rw [mem_set_of, sub_eq_zero, mul_comm] at hq
-    obtain ⟨a, ha⟩ := (Int.pow_dvd_pow_iff two_pos).mp ⟨d, hq⟩
-    rw [ha, mul_pow, mul_right_inj' (pow_pos (int.coe_nat_pos.mpr q.pos) 2).ne'] at hq
-    exact hd ⟨a, sq a ▸ hq.symm⟩
-  haveI := ne_zero_iff.mpr (int.nat_abs_ne_zero.mpr hm₀)
-  let f : ℚ → ZMod m.nat_abs × ZMod m.nat_abs := fun q => (q.1, q.2)
-  obtain ⟨q₁, h₁ : q₁.1 ^ 2 - d * q₁.2 ^ 2 = m, q₂, h₂ : q₂.1 ^ 2 - d * q₂.2 ^ 2 = m, hne, hqf⟩ :=
-    hm.exists_ne_map_eq_of_maps_to (maps_to_univ f _) finite_univ
-  obtain ⟨hq1 : (q₁.1 : ZMod m.nat_abs) = q₂.1, hq2 : (q₁.2 : ZMod m.nat_abs) = q₂.2⟩ :=
-    prod.ext_iff.mp hqf
-  have hd₁ : m ∣ q₁.1 * q₂.1 - d * (q₁.2 * q₂.2) :=
-    by
-    rw [← Int.natAbs_dvd, ← ZMod.int_cast_zmod_eq_zero_iff_dvd]
-    push_cast
-    rw [hq1, hq2, ← sq, ← sq]
-    norm_cast
-    rw [ZMod.int_cast_zmod_eq_zero_iff_dvd, Int.natAbs_dvd, Nat.cast_pow, ← h₂]
-  have hd₂ : m ∣ q₁.1 * q₂.2 - q₂.1 * q₁.2 :=
-    by
-    rw [← Int.natAbs_dvd, ← ZMod.int_cast_eq_int_cast_iff_dvd_sub]
-    push_cast
-    rw [hq1, hq2]
-  replace hm₀ : (m : ℚ) ≠ 0 := int.cast_ne_zero.mpr hm₀
-  refine' ⟨(q₁.1 * q₂.1 - d * (q₁.2 * q₂.2)) / m, (q₁.1 * q₂.2 - q₂.1 * q₁.2) / m, _, _⟩
-  · qify [hd₁, hd₂]
-    field_simp [hm₀]
-    norm_cast
-    conv_rhs =>
-      congr
-      rw [sq]
-      congr
-      rw [← h₁]
-      skip
-      rw [← h₂]
-    push_cast
-    ring
-  · qify [hd₂]
-    refine' div_ne_zero_iff.mpr ⟨_, hm₀⟩
-    exact_mod_cast mt sub_eq_zero.mp (mt rat.eq_iff_mul_eq_mul.mpr hne)
-#align pell.exists_of_not_is_square Pell.exists_of_not_isSquare
-
-/-- If `d` is a positive integer, then there is a nontrivial solution
-to the Pell equation `x^2 - d*y^2 = 1` if and only if `d` is not a square. -/
-theorem exists_iff_not_isSquare (h₀ : 0 < d) :
-    (∃ x y : ℤ, x ^ 2 - d * y ^ 2 = 1 ∧ y ≠ 0) ↔ ¬IsSquare d :=
-  by
-  refine' ⟨_, exists_of_not_is_square h₀⟩
-  rintro ⟨x, y, hxy, hy⟩ ⟨a, rfl⟩
-  rw [← sq, ← mul_pow, sq_sub_sq] at hxy
-  simpa [mul_self_pos.mp h₀, sub_eq_add_neg, eq_neg_self_iff] using Int.eq_of_mul_eq_one hxy
-#align pell.exists_iff_not_is_square Pell.exists_iff_not_isSquare
-
-/-- If `d` is a positive integer that is not a square, then there exists a solution
-to the Pell equation `x^2 - d*y^2 = 1` with `x > 1` and `y > 0`. -/
-theorem exists_pos_of_not_isSquare (h₀ : 0 < d) (hd : ¬IsSquare d) :
-    ∃ x y : ℤ, x ^ 2 - d * y ^ 2 = 1 ∧ 1 < x ∧ 0 < y :=
-  by
-  obtain ⟨x, y, h, hy⟩ := exists_of_not_is_square h₀ hd
-  refine' ⟨|x|, |y|, by rwa [sq_abs, sq_abs], _, abs_pos.mpr hy⟩
-  rw [← one_lt_sq_iff_one_lt_abs, eq_add_of_sub_eq h, lt_add_iff_pos_right]
-  exact mul_pos h₀ (sq_pos_of_ne_zero y hy)
-#align pell.exists_pos_of_not_is_square Pell.exists_pos_of_not_isSquare
-
-end Existence
-
 /-!
 ### Group structure of the solution set
 
@@ -299,5 +191,118 @@ theorem y_neg (a : Solution₁ d) : (-a).y = -a.y :=
 
 end Solution₁
 
+section Existence
+
+/-!
+### Existence of nontrivial solutions
+-/
+
+
+variable {d : ℤ}
+
+open Set Real
+
+/-- If `d` is a positive integer that is not a square, then there is a nontrivial solution
+to the Pell equation `x^2 - d*y^2 = 1`. -/
+theorem exists_of_not_isSquare (h₀ : 0 < d) (hd : ¬IsSquare d) :
+    ∃ x y : ℤ, x ^ 2 - d * y ^ 2 = 1 ∧ y ≠ 0 :=
+  by
+  let ξ : ℝ := sqrt d
+  have hξ : Irrational ξ :=
+    by
+    refine' irrational_nrt_of_notint_nrt 2 d (sq_sqrt <| int.cast_nonneg.mpr h₀.le) _ two_pos
+    rintro ⟨x, hx⟩
+    refine' hd ⟨x, @Int.cast_injective ℝ _ _ d (x * x) _⟩
+    rw [← sq_sqrt <| int.cast_nonneg.mpr h₀.le, Int.cast_mul, ← hx, sq]
+  obtain ⟨M, hM₁⟩ := exists_int_gt (2 * |ξ| + 1)
+  have hM : { q : ℚ | |q.1 ^ 2 - d * q.2 ^ 2| < M }.Infinite :=
+    by
+    refine' infinite.mono (fun q h => _) (infinite_rat_abs_sub_lt_one_div_denom_sq_of_irrational hξ)
+    have h0 : 0 < (q.2 : ℝ) ^ 2 := pow_pos (nat.cast_pos.mpr q.pos) 2
+    have h1 : (q.num : ℝ) / (q.denom : ℝ) = q := by exact_mod_cast q.num_div_denom
+    rw [mem_set_of, abs_sub_comm, ← @Int.cast_lt ℝ, ← div_lt_div_right (abs_pos_of_pos h0)]
+    push_cast
+    rw [← abs_div, abs_sq, sub_div, mul_div_cancel _ h0.ne', ← div_pow, h1, ←
+      sq_sqrt (int.cast_pos.mpr h₀).le, sq_sub_sq, abs_mul, ← mul_one_div]
+    refine' mul_lt_mul'' (((abs_add ξ q).trans _).trans_lt hM₁) h (abs_nonneg _) (abs_nonneg _)
+    rw [two_mul, add_assoc, add_le_add_iff_left, ← sub_le_iff_le_add']
+    rw [mem_set_of, abs_sub_comm] at h
+    refine' (abs_sub_abs_le_abs_sub (q : ℝ) ξ).trans (h.le.trans _)
+    rw [div_le_one h0, one_le_sq_iff_one_le_abs, Nat.abs_cast, Nat.one_le_cast]
+    exact q.pos
+  obtain ⟨m, hm⟩ : ∃ m : ℤ, { q : ℚ | q.1 ^ 2 - d * q.2 ^ 2 = m }.Infinite :=
+    by
+    contrapose! hM
+    simp only [not_infinite] at hM⊢
+    refine' (congr_arg _ (ext fun x => _)).mp (finite.bUnion (finite_Ioo (-M) M) fun m _ => hM m)
+    simp only [abs_lt, mem_set_of_eq, mem_Ioo, mem_Union, exists_prop, exists_eq_right']
+  have hm₀ : m ≠ 0 := by
+    rintro rfl
+    obtain ⟨q, hq⟩ := hm.nonempty
+    rw [mem_set_of, sub_eq_zero, mul_comm] at hq
+    obtain ⟨a, ha⟩ := (Int.pow_dvd_pow_iff two_pos).mp ⟨d, hq⟩
+    rw [ha, mul_pow, mul_right_inj' (pow_pos (int.coe_nat_pos.mpr q.pos) 2).ne'] at hq
+    exact hd ⟨a, sq a ▸ hq.symm⟩
+  haveI := ne_zero_iff.mpr (int.nat_abs_ne_zero.mpr hm₀)
+  let f : ℚ → ZMod m.nat_abs × ZMod m.nat_abs := fun q => (q.1, q.2)
+  obtain ⟨q₁, h₁ : q₁.1 ^ 2 - d * q₁.2 ^ 2 = m, q₂, h₂ : q₂.1 ^ 2 - d * q₂.2 ^ 2 = m, hne, hqf⟩ :=
+    hm.exists_ne_map_eq_of_maps_to (maps_to_univ f _) finite_univ
+  obtain ⟨hq1 : (q₁.1 : ZMod m.nat_abs) = q₂.1, hq2 : (q₁.2 : ZMod m.nat_abs) = q₂.2⟩ :=
+    prod.ext_iff.mp hqf
+  have hd₁ : m ∣ q₁.1 * q₂.1 - d * (q₁.2 * q₂.2) :=
+    by
+    rw [← Int.natAbs_dvd, ← ZMod.int_cast_zmod_eq_zero_iff_dvd]
+    push_cast
+    rw [hq1, hq2, ← sq, ← sq]
+    norm_cast
+    rw [ZMod.int_cast_zmod_eq_zero_iff_dvd, Int.natAbs_dvd, Nat.cast_pow, ← h₂]
+  have hd₂ : m ∣ q₁.1 * q₂.2 - q₂.1 * q₁.2 :=
+    by
+    rw [← Int.natAbs_dvd, ← ZMod.int_cast_eq_int_cast_iff_dvd_sub]
+    push_cast
+    rw [hq1, hq2]
+  replace hm₀ : (m : ℚ) ≠ 0 := int.cast_ne_zero.mpr hm₀
+  refine' ⟨(q₁.1 * q₂.1 - d * (q₁.2 * q₂.2)) / m, (q₁.1 * q₂.2 - q₂.1 * q₁.2) / m, _, _⟩
+  · qify [hd₁, hd₂]
+    field_simp [hm₀]
+    norm_cast
+    conv_rhs =>
+      congr
+      rw [sq]
+      congr
+      rw [← h₁]
+      skip
+      rw [← h₂]
+    push_cast
+    ring
+  · qify [hd₂]
+    refine' div_ne_zero_iff.mpr ⟨_, hm₀⟩
+    exact_mod_cast mt sub_eq_zero.mp (mt rat.eq_iff_mul_eq_mul.mpr hne)
+#align pell.exists_of_not_is_square Pell.exists_of_not_isSquare
+
+/-- If `d` is a positive integer, then there is a nontrivial solution
+to the Pell equation `x^2 - d*y^2 = 1` if and only if `d` is not a square. -/
+theorem exists_iff_not_isSquare (h₀ : 0 < d) :
+    (∃ x y : ℤ, x ^ 2 - d * y ^ 2 = 1 ∧ y ≠ 0) ↔ ¬IsSquare d :=
+  by
+  refine' ⟨_, exists_of_not_is_square h₀⟩
+  rintro ⟨x, y, hxy, hy⟩ ⟨a, rfl⟩
+  rw [← sq, ← mul_pow, sq_sub_sq] at hxy
+  simpa [mul_self_pos.mp h₀, sub_eq_add_neg, eq_neg_self_iff] using Int.eq_of_mul_eq_one hxy
+#align pell.exists_iff_not_is_square Pell.exists_iff_not_isSquare
+
+/-- If `d` is a positive integer that is not a square, then there exists a solution
+to the Pell equation `x^2 - d*y^2 = 1` with `x > 1` and `y > 0`. -/
+theorem exists_pos_of_not_isSquare (h₀ : 0 < d) (hd : ¬IsSquare d) :
+    ∃ x y : ℤ, x ^ 2 - d * y ^ 2 = 1 ∧ 1 < x ∧ 0 < y :=
+  by
+  obtain ⟨x, y, h, hy⟩ := exists_of_not_is_square h₀ hd
+  refine' ⟨|x|, |y|, by rwa [sq_abs, sq_abs], _, abs_pos.mpr hy⟩
+  rw [← one_lt_sq_iff_one_lt_abs, eq_add_of_sub_eq h, lt_add_iff_pos_right]
+  exact mul_pos h₀ (sq_pos_of_ne_zero y hy)
+#align pell.exists_pos_of_not_is_square Pell.exists_pos_of_not_isSquare
+
+end Existence
+
 end Pell
 
Diff
@@ -4,13 +4,14 @@ Released under Apache 2.0 license as described in the file LICENSE.
 Authors: Michael Geißer, Michael Stoll
 
 ! This file was ported from Lean 3 source module number_theory.pell
-! leanprover-community/mathlib commit 5b05c634aa9ed56cce0f5dedd4ccf4ca0c1dcd95
+! leanprover-community/mathlib commit 7ec294687917cbc5c73620b4414ae9b5dd9ae1b4
 ! Please do not edit these lines, except to modify the commit id
 ! if you have ported upstream changes.
 -/
 import Mathbin.Tactic.Qify
 import Mathbin.Data.Zmod.Basic
 import Mathbin.NumberTheory.DiophantineApproximation
+import Mathbin.NumberTheory.Zsqrtd.Basic
 
 /-!
 # Pell's Equation
@@ -153,5 +154,150 @@ theorem exists_pos_of_not_isSquare (h₀ : 0 < d) (hd : ¬IsSquare d) :
 
 end Existence
 
+/-!
+### Group structure of the solution set
+
+We define a structure of a commutative multiplicative group with distributive negation
+on the set of all solutions to the Pell equation `x^2 - d*y^2 = 1`.
+
+The type of such solutions is `pell.solution₁ d`. It corresponds to a pair of integers `x` and `y`
+and a proof that `(x, y)` is indeed a solution.
+
+The multiplication is given by `(x, y) * (x', y') = (x*y' + d*y*y', x*y' + y*x')`.
+This is obtained by mapping `(x, y)` to `x + y*√d` and multiplying the results.
+In fact, we define `pell.solution₁ d` to be `↥(unitary (ℤ√d))` and transport
+the "commutative group with distributive negation" structure from `↥(unitary (ℤ√d))`.
+
+We then set up an API for `pell.solution₁ d`.
+-/
+
+
+open Zsqrtd
+
+/-- An element of `ℤ√d` has norm one (i.e., `a.re^2 - d*a.im^2 = 1`) if and only if
+it is contained in the submonoid of unitary elements.
+
+TODO: merge this result with `pell.is_pell_iff_mem_unitary`. -/
+theorem is_pell_solution_iff_mem_unitary {d : ℤ} {a : ℤ√d} :
+    a.re ^ 2 - d * a.im ^ 2 = 1 ↔ a ∈ unitary (ℤ√d) := by
+  rw [← norm_eq_one_iff_mem_unitary, norm_def, sq, sq, ← mul_assoc]
+#align pell.is_pell_solution_iff_mem_unitary Pell.is_pell_solution_iff_mem_unitary
+
+-- We use `solution₁ d` to allow for a more general structure `solution d m` that
+-- encodes solutions to `x^2 - d*y^2 = m` to be added later.
+/-- `pell.solution₁ d` is the type of solutions to the Pell equation `x^2 - d*y^2 = 1`.
+We define this in terms of elements of `ℤ√d` of norm one.
+-/
+def Solution₁ (d : ℤ) : Type :=
+  ↥(unitary (ℤ√d))deriving CommGroup, HasDistribNeg, Inhabited
+#align pell.solution₁ Pell.Solution₁
+
+namespace Solution₁
+
+variable {d : ℤ}
+
+instance : Coe (Solution₁ d) (ℤ√d) where coe := Subtype.val
+
+/-- The `x` component of a solution to the Pell equation `x^2 - d*y^2 = 1` -/
+protected def x (a : Solution₁ d) : ℤ :=
+  (a : ℤ√d).re
+#align pell.solution₁.x Pell.Solution₁.x
+
+/-- The `y` component of a solution to the Pell equation `x^2 - d*y^2 = 1` -/
+protected def y (a : Solution₁ d) : ℤ :=
+  (a : ℤ√d).im
+#align pell.solution₁.y Pell.Solution₁.y
+
+/-- The proof that `a` is a solution to the Pell equation `x^2 - d*y^2 = 1` -/
+theorem prop (a : Solution₁ d) : a.x ^ 2 - d * a.y ^ 2 = 1 :=
+  is_pell_solution_iff_mem_unitary.mpr a.property
+#align pell.solution₁.prop Pell.Solution₁.prop
+
+/-- An alternative form of the equation, suitable for rewriting `x^2`. -/
+theorem prop_x (a : Solution₁ d) : a.x ^ 2 = 1 + d * a.y ^ 2 :=
+  by
+  rw [← a.prop]
+  ring
+#align pell.solution₁.prop_x Pell.Solution₁.prop_x
+
+/-- An alternative form of the equation, suitable for rewriting `d * y^2`. -/
+theorem prop_y (a : Solution₁ d) : d * a.y ^ 2 = a.x ^ 2 - 1 :=
+  by
+  rw [← a.prop]
+  ring
+#align pell.solution₁.prop_y Pell.Solution₁.prop_y
+
+/-- Two solutions are equal if their `x` and `y` components are equal. -/
+@[ext]
+theorem ext {a b : Solution₁ d} (hx : a.x = b.x) (hy : a.y = b.y) : a = b :=
+  Subtype.ext <| ext.mpr ⟨hx, hy⟩
+#align pell.solution₁.ext Pell.Solution₁.ext
+
+/-- Construct a solution from `x`, `y` and a proof that the equation is satisfied. -/
+def mk (x y : ℤ) (prop : x ^ 2 - d * y ^ 2 = 1) : Solution₁ d
+    where
+  val := ⟨x, y⟩
+  property := is_pell_solution_iff_mem_unitary.mp prop
+#align pell.solution₁.mk Pell.Solution₁.mk
+
+@[simp]
+theorem x_mk (x y : ℤ) (prop : x ^ 2 - d * y ^ 2 = 1) : (mk x y prop).x = x :=
+  rfl
+#align pell.solution₁.x_mk Pell.Solution₁.x_mk
+
+@[simp]
+theorem y_mk (x y : ℤ) (prop : x ^ 2 - d * y ^ 2 = 1) : (mk x y prop).y = y :=
+  rfl
+#align pell.solution₁.y_mk Pell.Solution₁.y_mk
+
+@[simp]
+theorem coe_mk (x y : ℤ) (prop : x ^ 2 - d * y ^ 2 = 1) : (↑(mk x y prop) : ℤ√d) = ⟨x, y⟩ :=
+  Zsqrtd.ext.mpr ⟨x_mk x y prop, y_mk x y prop⟩
+#align pell.solution₁.coe_mk Pell.Solution₁.coe_mk
+
+@[simp]
+theorem x_one : (1 : Solution₁ d).x = 1 :=
+  rfl
+#align pell.solution₁.x_one Pell.Solution₁.x_one
+
+@[simp]
+theorem y_one : (1 : Solution₁ d).y = 0 :=
+  rfl
+#align pell.solution₁.y_one Pell.Solution₁.y_one
+
+@[simp]
+theorem x_mul (a b : Solution₁ d) : (a * b).x = a.x * b.x + d * (a.y * b.y) :=
+  by
+  rw [← mul_assoc]
+  rfl
+#align pell.solution₁.x_mul Pell.Solution₁.x_mul
+
+@[simp]
+theorem y_mul (a b : Solution₁ d) : (a * b).y = a.x * b.y + a.y * b.x :=
+  rfl
+#align pell.solution₁.y_mul Pell.Solution₁.y_mul
+
+@[simp]
+theorem x_inv (a : Solution₁ d) : a⁻¹.x = a.x :=
+  rfl
+#align pell.solution₁.x_inv Pell.Solution₁.x_inv
+
+@[simp]
+theorem y_inv (a : Solution₁ d) : a⁻¹.y = -a.y :=
+  rfl
+#align pell.solution₁.y_inv Pell.Solution₁.y_inv
+
+@[simp]
+theorem x_neg (a : Solution₁ d) : (-a).x = -a.x :=
+  rfl
+#align pell.solution₁.x_neg Pell.Solution₁.x_neg
+
+@[simp]
+theorem y_neg (a : Solution₁ d) : (-a).y = -a.y :=
+  rfl
+#align pell.solution₁.y_neg Pell.Solution₁.y_neg
+
+end Solution₁
+
 end Pell
 
Diff
@@ -100,14 +100,14 @@ theorem exists_of_not_isSquare (h₀ : 0 < d) (hd : ¬IsSquare d) :
     prod.ext_iff.mp hqf
   have hd₁ : m ∣ q₁.1 * q₂.1 - d * (q₁.2 * q₂.2) :=
     by
-    rw [← Int.natAbs_dvd, ← ZMod.int_coe_zMod_eq_zero_iff_dvd]
+    rw [← Int.natAbs_dvd, ← ZMod.int_cast_zmod_eq_zero_iff_dvd]
     push_cast
     rw [hq1, hq2, ← sq, ← sq]
     norm_cast
-    rw [ZMod.int_coe_zMod_eq_zero_iff_dvd, Int.natAbs_dvd, Nat.cast_pow, ← h₂]
+    rw [ZMod.int_cast_zmod_eq_zero_iff_dvd, Int.natAbs_dvd, Nat.cast_pow, ← h₂]
   have hd₂ : m ∣ q₁.1 * q₂.2 - q₂.1 * q₁.2 :=
     by
-    rw [← Int.natAbs_dvd, ← ZMod.int_coe_eq_int_coe_iff_dvd_sub]
+    rw [← Int.natAbs_dvd, ← ZMod.int_cast_eq_int_cast_iff_dvd_sub]
     push_cast
     rw [hq1, hq2]
   replace hm₀ : (m : ℚ) ≠ 0 := int.cast_ne_zero.mpr hm₀
Diff
@@ -4,7 +4,7 @@ Released under Apache 2.0 license as described in the file LICENSE.
 Authors: Michael Geißer, Michael Stoll
 
 ! This file was ported from Lean 3 source module number_theory.pell
-! leanprover-community/mathlib commit 35c1956cb727c474aa8863c13ca3abca4c2f885e
+! leanprover-community/mathlib commit 5b05c634aa9ed56cce0f5dedd4ccf4ca0c1dcd95
 ! Please do not edit these lines, except to modify the commit id
 ! if you have ported upstream changes.
 -/
@@ -47,11 +47,13 @@ namespace Pell
 
 section Existence
 
+variable {d : ℤ}
+
 open Set Real
 
 /-- If `d` is a positive integer that is not a square, then there is a nontrivial solution
 to the Pell equation `x^2 - d*y^2 = 1`. -/
-theorem exists_of_not_isSquare {d : ℤ} (h₀ : 0 < d) (hd : ¬IsSquare d) :
+theorem exists_of_not_isSquare (h₀ : 0 < d) (hd : ¬IsSquare d) :
     ∃ x y : ℤ, x ^ 2 - d * y ^ 2 = 1 ∧ y ≠ 0 :=
   by
   let ξ : ℝ := sqrt d
@@ -129,7 +131,7 @@ theorem exists_of_not_isSquare {d : ℤ} (h₀ : 0 < d) (hd : ¬IsSquare d) :
 
 /-- If `d` is a positive integer, then there is a nontrivial solution
 to the Pell equation `x^2 - d*y^2 = 1` if and only if `d` is not a square. -/
-theorem exists_iff_not_isSquare {d : ℤ} (h₀ : 0 < d) :
+theorem exists_iff_not_isSquare (h₀ : 0 < d) :
     (∃ x y : ℤ, x ^ 2 - d * y ^ 2 = 1 ∧ y ≠ 0) ↔ ¬IsSquare d :=
   by
   refine' ⟨_, exists_of_not_is_square h₀⟩
@@ -138,6 +140,17 @@ theorem exists_iff_not_isSquare {d : ℤ} (h₀ : 0 < d) :
   simpa [mul_self_pos.mp h₀, sub_eq_add_neg, eq_neg_self_iff] using Int.eq_of_mul_eq_one hxy
 #align pell.exists_iff_not_is_square Pell.exists_iff_not_isSquare
 
+/-- If `d` is a positive integer that is not a square, then there exists a solution
+to the Pell equation `x^2 - d*y^2 = 1` with `x > 1` and `y > 0`. -/
+theorem exists_pos_of_not_isSquare (h₀ : 0 < d) (hd : ¬IsSquare d) :
+    ∃ x y : ℤ, x ^ 2 - d * y ^ 2 = 1 ∧ 1 < x ∧ 0 < y :=
+  by
+  obtain ⟨x, y, h, hy⟩ := exists_of_not_is_square h₀ hd
+  refine' ⟨|x|, |y|, by rwa [sq_abs, sq_abs], _, abs_pos.mpr hy⟩
+  rw [← one_lt_sq_iff_one_lt_abs, eq_add_of_sub_eq h, lt_add_iff_pos_right]
+  exact mul_pos h₀ (sq_pos_of_ne_zero y hy)
+#align pell.exists_pos_of_not_is_square Pell.exists_pos_of_not_isSquare
+
 end Existence
 
 end Pell
Diff
@@ -4,7 +4,7 @@ Released under Apache 2.0 license as described in the file LICENSE.
 Authors: Michael Geißer, Michael Stoll
 
 ! This file was ported from Lean 3 source module number_theory.pell
-! leanprover-community/mathlib commit a66d07e27d5b5b8ac1147cacfe353478e5c14002
+! leanprover-community/mathlib commit 35c1956cb727c474aa8863c13ca3abca4c2f885e
 ! Please do not edit these lines, except to modify the commit id
 ! if you have ported upstream changes.
 -/
@@ -134,9 +134,8 @@ theorem exists_iff_not_isSquare {d : ℤ} (h₀ : 0 < d) :
   by
   refine' ⟨_, exists_of_not_is_square h₀⟩
   rintro ⟨x, y, hxy, hy⟩ ⟨a, rfl⟩
-  rw [← sq, ← mul_pow, sq_sub_sq, Int.mul_eq_one_iff_eq_one_or_neg_one] at hxy
-  replace hxy := hxy.elim (fun h => h.1.trans h.2.symm) fun h => h.1.trans h.2.symm
-  simpa [mul_self_pos.mp h₀, sub_eq_add_neg, eq_neg_self_iff] using hxy
+  rw [← sq, ← mul_pow, sq_sub_sq] at hxy
+  simpa [mul_self_pos.mp h₀, sub_eq_add_neg, eq_neg_self_iff] using Int.eq_of_mul_eq_one hxy
 #align pell.exists_iff_not_is_square Pell.exists_iff_not_isSquare
 
 end Existence
Diff
@@ -1,1050 +1,145 @@
 /-
-Copyright (c) 2017 Mario Carneiro. All rights reserved.
+Copyright (c) 2023 Michael Stoll. All rights reserved.
 Released under Apache 2.0 license as described in the file LICENSE.
-Authors: Mario Carneiro
+Authors: Michael Geißer, Michael Stoll
 
 ! This file was ported from Lean 3 source module number_theory.pell
-! leanprover-community/mathlib commit 5a1fa97e87785d3d0b268769f71076ccec900fa2
+! leanprover-community/mathlib commit a66d07e27d5b5b8ac1147cacfe353478e5c14002
 ! Please do not edit these lines, except to modify the commit id
 ! if you have ported upstream changes.
 -/
-import Mathbin.Data.Nat.Modeq
-import Mathbin.NumberTheory.Zsqrtd.Basic
+import Mathbin.Tactic.Qify
+import Mathbin.Data.Zmod.Basic
+import Mathbin.NumberTheory.DiophantineApproximation
 
 /-!
-# Pell's equation and Matiyasevic's theorem
+# Pell's Equation
 
-This file solves Pell's equation, i.e. integer solutions to `x ^ 2 - d * y ^ 2 = 1` in the special
-case that `d = a ^ 2 - 1`. This is then applied to prove Matiyasevic's theorem that the power
-function is Diophantine, which is the last key ingredient in the solution to Hilbert's tenth
-problem. For the definition of Diophantine function, see `dioph.lean`.
+We prove the following
 
-## Main definition
+**Theorem.** Let $d$ be a positive integer that is not a square. Then the equation
+$x^2 - d y^2 = 1$ has a nontrivial (i.e., with $y \ne 0$) solution in integers.
 
-* `pell` is a function assigning to a natural number `n` the `n`-th solution to Pell's equation
-  constructed recursively from the initial solution `(0, 1)`.
+See `pell.exists_of_not_is_square`.
 
-## Main statements
-
-* `eq_pell` shows that every solution to Pell's equation is recursively obtained using `pell`
-* `matiyasevic` shows that a certain system of Diophantine equations has a solution if and only if
-  the first variable is the `x`-component in a solution to Pell's equation - the key step towards
-  Hilbert's tenth problem in Davis' version of Matiyasevic's theorem.
-* `eq_pow_of_pell` shows that the power function is Diophantine.
-
-## Implementation notes
-
-The proof of Matiyasevic's theorem doesn't follow Matiyasevic's original account of using Fibonacci
-numbers but instead Davis' variant of using solutions to Pell's equation.
+This is the beginning of a development that aims at providing all of the essential theory
+of Pell's Equation for general $d$ (as opposed to the contents of `number_theory.pell_matiyasevic`,
+which is specific to the case $d = a^2 - 1$ for some $a > 1$).
 
 ## References
 
-* [M. Carneiro, _A Lean formalization of Matiyasevič's theorem_][carneiro2018matiyasevic]
-* [M. Davis, _Hilbert's tenth problem is unsolvable_][MR317916]
+* [K. Ireland, M. Rosen, *A classical introduction to modern number theory*
+   (Section 17.5)][IrelandRosen1990]
 
 ## Tags
 
-Pell's equation, Matiyasevic's theorem, Hilbert's tenth problem
+Pell's equation
 
 ## TODO
 
-* Provide solutions to Pell's equation for the case of arbitrary `d` (not just `d = a ^ 2 - 1` like
-  in the current version) and furthermore also for `x ^ 2 - d * y ^ 2 = -1`.
+* Provide the structure theory of the solution set to Pell's equation
+  and furthermore also for `x ^ 2 - d * y ^ 2 = -1` and further generalizations.
 * Connect solutions to the continued fraction expansion of `√d`.
 -/
 
 
 namespace Pell
 
-open Nat
-
-section
-
-parameter {a : ℕ}(a1 : 1 < a)
-
-include a1
-
-private def d :=
-  a * a - 1
-#align pell.d pell.d
-
-@[simp]
-theorem d_pos : 0 < d :=
-  tsub_pos_of_lt (mul_lt_mul a1 (le_of_lt a1) (by decide) (by decide) : 1 * 1 < a * a)
-#align pell.d_pos Pell.d_pos
-
--- TODO(lint): Fix double namespace issue
-/-- The Pell sequences, i.e. the sequence of integer solutions to `x ^ 2 - d * y ^ 2 = 1`, where
-`d = a ^ 2 - 1`, defined together in mutual recursion. -/
-@[nolint dup_namespace]
-def pell : ℕ → ℕ × ℕ := fun n =>
-  Nat.recOn n (1, 0) fun n xy => (xy.1 * a + d * xy.2, xy.1 + xy.2 * a)
-#align pell.pell Pell.pell
-
-/-- The Pell `x` sequence. -/
-def xn (n : ℕ) : ℕ :=
-  (pell n).1
-#align pell.xn Pell.xn
-
-/-- The Pell `y` sequence. -/
-def yn (n : ℕ) : ℕ :=
-  (pell n).2
-#align pell.yn Pell.yn
-
-@[simp]
-theorem pell_val (n : ℕ) : pell n = (xn n, yn n) :=
-  show pell n = ((pell n).1, (pell n).2) from
-    match pell n with
-    | (a, b) => rfl
-#align pell.pell_val Pell.pell_val
-
-@[simp]
-theorem xn_zero : xn 0 = 1 :=
-  rfl
-#align pell.xn_zero Pell.xn_zero
-
-@[simp]
-theorem yn_zero : yn 0 = 0 :=
-  rfl
-#align pell.yn_zero Pell.yn_zero
-
-@[simp]
-theorem xn_succ (n : ℕ) : xn (n + 1) = xn n * a + d * yn n :=
-  rfl
-#align pell.xn_succ Pell.xn_succ
-
-@[simp]
-theorem yn_succ (n : ℕ) : yn (n + 1) = xn n + yn n * a :=
-  rfl
-#align pell.yn_succ Pell.yn_succ
-
-@[simp]
-theorem xn_one : xn 1 = a := by simp
-#align pell.xn_one Pell.xn_one
-
-@[simp]
-theorem yn_one : yn 1 = 1 := by simp
-#align pell.yn_one Pell.yn_one
-
-/-- The Pell `x` sequence, considered as an integer sequence.-/
-def xz (n : ℕ) : ℤ :=
-  xn n
-#align pell.xz Pell.xz
-
-/-- The Pell `y` sequence, considered as an integer sequence.-/
-def yz (n : ℕ) : ℤ :=
-  yn n
-#align pell.yz Pell.yz
-
-section
-
-omit a1
-
-/-- The element `a` such that `d = a ^ 2 - 1`, considered as an integer.-/
-def az : ℤ :=
-  a
-#align pell.az Pell.az
-
-end
-
-theorem asq_pos : 0 < a * a :=
-  le_trans (le_of_lt a1)
-    (by have := @Nat.mul_le_mul_left 1 a a (le_of_lt a1) <;> rwa [mul_one] at this)
-#align pell.asq_pos Pell.asq_pos
-
-theorem dz_val : ↑d = az * az - 1 :=
-  have : 1 ≤ a * a := asq_pos
-  show ↑(a * a - 1) = _ by rw [Int.ofNat_sub this] <;> rfl
-#align pell.dz_val Pell.dz_val
+section Existence
 
-@[simp]
-theorem xz_succ (n : ℕ) : xz (n + 1) = xz n * az + ↑d * yz n :=
-  rfl
-#align pell.xz_succ Pell.xz_succ
+open Set Real
 
-@[simp]
-theorem yz_succ (n : ℕ) : yz (n + 1) = xz n + yz n * az :=
-  rfl
-#align pell.yz_succ Pell.yz_succ
-
-/-- The Pell sequence can also be viewed as an element of `ℤ√d` -/
-def pellZd (n : ℕ) : ℤ√d :=
-  ⟨xn n, yn n⟩
-#align pell.pell_zd Pell.pellZd
-
-@[simp]
-theorem pellZd_re (n : ℕ) : (pell_zd n).re = xn n :=
-  rfl
-#align pell.pell_zd_re Pell.pellZd_re
-
-@[simp]
-theorem pellZd_im (n : ℕ) : (pell_zd n).im = yn n :=
-  rfl
-#align pell.pell_zd_im Pell.pellZd_im
-
-/-- The property of being a solution to the Pell equation, expressed
-  as a property of elements of `ℤ√d`. -/
-def IsPell : ℤ√d → Prop
-  | ⟨x, y⟩ => x * x - d * y * y = 1
-#align pell.is_pell Pell.IsPell
-
-theorem isPell_nat {x y : ℕ} : is_pell ⟨x, y⟩ ↔ x * x - d * y * y = 1 :=
-  ⟨fun h =>
-    Int.ofNat.inj
-      (by rw [Int.ofNat_sub (Int.le_of_ofNat_le_ofNat <| Int.le.intro_sub h)] <;> exact h),
-    fun h =>
-    show ((x * x : ℕ) - (d * y * y : ℕ) : ℤ) = 1 by
-      rw [← Int.ofNat_sub <| le_of_lt <| Nat.lt_of_sub_eq_succ h, h] <;> rfl⟩
-#align pell.is_pell_nat Pell.isPell_nat
-
-theorem isPell_norm : ∀ {b : ℤ√d}, is_pell b ↔ b * b.conj = 1
-  | ⟨x, y⟩ => by simp [Zsqrtd.ext, is_pell, mul_comm] <;> ring_nf
-#align pell.is_pell_norm Pell.isPell_norm
-
-theorem isPell_mul {b c : ℤ√d} (hb : is_pell b) (hc : is_pell c) : is_pell (b * c) :=
-  is_pell_norm.2
-    (by
-      simp [mul_comm, mul_left_comm, Zsqrtd.conj_mul, Pell.isPell_norm.1 hb, Pell.isPell_norm.1 hc])
-#align pell.is_pell_mul Pell.isPell_mul
-
-theorem isPell_conj : ∀ {b : ℤ√d}, is_pell b ↔ is_pell b.conj
-  | ⟨x, y⟩ => by simp [is_pell, Zsqrtd.conj]
-#align pell.is_pell_conj Pell.isPell_conj
-
-@[simp]
-theorem pellZd_succ (n : ℕ) : pell_zd (n + 1) = pell_zd n * ⟨a, 1⟩ := by simp [Zsqrtd.ext]
-#align pell.pell_zd_succ Pell.pellZd_succ
-
-theorem isPell_one : is_pell ⟨a, 1⟩ :=
-  show az * az - d * 1 * 1 = 1 by simp [dz_val] <;> ring
-#align pell.is_pell_one Pell.isPell_one
-
-theorem isPell_pellZd : ∀ n : ℕ, is_pell (pell_zd n)
-  | 0 => rfl
-  | n + 1 => by
-    let o := is_pell_one
-    simp <;> exact Pell.isPell_mul (is_pell_pell_zd n) o
-#align pell.is_pell_pell_zd Pell.isPell_pellZd
-
-@[simp]
-theorem pell_eqz (n : ℕ) : xz n * xz n - d * yz n * yz n = 1 :=
-  is_pell_pell_zd n
-#align pell.pell_eqz Pell.pell_eqz
-
-@[simp]
-theorem pell_eq (n : ℕ) : xn n * xn n - d * yn n * yn n = 1 :=
-  let pn := pell_eqz n
-  have h : (↑(xn n * xn n) : ℤ) - ↑(d * yn n * yn n) = 1 := by
-    repeat' rw [Int.ofNat_mul] <;> exact pn
-  have hl : d * yn n * yn n ≤ xn n * xn n :=
-    Int.le_of_ofNat_le_ofNat <| Int.le.intro <| add_eq_of_eq_sub' <| Eq.symm h
-  Int.ofNat.inj (by rw [Int.ofNat_sub hl] <;> exact h)
-#align pell.pell_eq Pell.pell_eq
-
-instance dnsq : Zsqrtd.Nonsquare d :=
-  ⟨fun n h =>
-    have : n * n + 1 = a * a := by rw [← h] <;> exact Nat.succ_pred_eq_of_pos (asq_pos a1)
-    have na : n < a := Nat.mul_self_lt_mul_self_iff.2 (by rw [← this] <;> exact Nat.lt_succ_self _)
-    have : (n + 1) * (n + 1) ≤ n * n + 1 := by rw [this] <;> exact Nat.mul_self_le_mul_self na
-    have : n + n ≤ 0 :=
-      @Nat.le_of_add_le_add_right (n * n + 1) _ _ (by ring_nf  at this⊢ <;> assumption)
-    ne_of_gt d_pos <| by rwa [Nat.eq_zero_of_le_zero ((Nat.le_add_left _ _).trans this)] at h⟩
-#align pell.dnsq Pell.dnsq
-
-theorem xn_ge_a_pow : ∀ n : ℕ, a ^ n ≤ xn n
-  | 0 => le_refl 1
-  | n + 1 => by
-    simp [pow_succ'] <;>
-      exact le_trans (Nat.mul_le_mul_right _ (xn_ge_a_pow n)) (Nat.le_add_right _ _)
-#align pell.xn_ge_a_pow Pell.xn_ge_a_pow
-
-theorem n_lt_a_pow : ∀ n : ℕ, n < a ^ n
-  | 0 => Nat.le_refl 1
-  | n + 1 => by
-    have IH := n_lt_a_pow n
-    have : a ^ n + a ^ n ≤ a ^ n * a := by
-      rw [← mul_two]
-      exact Nat.mul_le_mul_left _ a1
-    simp [pow_succ']
-    refine' lt_of_lt_of_le _ this
-    exact add_lt_add_of_lt_of_le IH (lt_of_le_of_lt (Nat.zero_le _) IH)
-#align pell.n_lt_a_pow Pell.n_lt_a_pow
-
-theorem n_lt_xn (n) : n < xn n :=
-  lt_of_lt_of_le (n_lt_a_pow n) (xn_ge_a_pow n)
-#align pell.n_lt_xn Pell.n_lt_xn
-
-theorem x_pos (n) : 0 < xn n :=
-  lt_of_le_of_lt (Nat.zero_le n) (n_lt_xn n)
-#align pell.x_pos Pell.x_pos
-
-theorem eq_pell_lem : ∀ (n) (b : ℤ√d), 1 ≤ b → is_pell b → b ≤ pell_zd n → ∃ n, b = pell_zd n
-  | 0, b => fun h1 hp hl => ⟨0, @Zsqrtd.le_antisymm _ dnsq _ _ hl h1⟩
-  | n + 1, b => fun h1 hp h =>
-    have a1p : (0 : ℤ√d) ≤ ⟨a, 1⟩ := trivial
-    have am1p : (0 : ℤ√d) ≤ ⟨a, -1⟩ := show (_ : Nat) ≤ _ by simp <;> exact Nat.pred_le _
-    have a1m : (⟨a, 1⟩ * ⟨a, -1⟩ : ℤ√d) = 1 := is_pell_norm.1 is_pell_one
-    if ha : (⟨↑a, 1⟩ : ℤ√d) ≤ b then
-      let ⟨m, e⟩ :=
-        eq_pell_lem n (b * ⟨a, -1⟩) (by rw [← a1m] <;> exact mul_le_mul_of_nonneg_right ha am1p)
-          (is_pell_mul hp (is_pell_conj.1 is_pell_one))
-          (by
-            have t := mul_le_mul_of_nonneg_right h am1p <;>
-              rwa [pell_zd_succ, mul_assoc, a1m, mul_one] at t)
-      ⟨m + 1, by
-        rw [show b = b * ⟨a, -1⟩ * ⟨a, 1⟩ by rw [mul_assoc, Eq.trans (mul_comm _ _) a1m] <;> simp,
-          pell_zd_succ, e]⟩
-    else
-      suffices ¬1 < b from ⟨0, show b = 1 from (Or.resolve_left (lt_or_eq_of_le h1) this).symm⟩
-      fun h1l => by
-      cases' b with x y <;>
-        exact by
-          have bm : (_ * ⟨_, _⟩ : ℤ√d a1) = 1 := Pell.isPell_norm.1 hp
-          have y0l : (0 : ℤ√d a1) < ⟨x - x, y - -y⟩ :=
-            sub_lt_sub h1l fun hn : (1 : ℤ√d a1) ≤ ⟨x, -y⟩ => by
-              have t := mul_le_mul_of_nonneg_left hn (le_trans zero_le_one h1) <;>
-                  rw [bm, mul_one] at t <;>
-                exact h1l t
-          have yl2 : (⟨_, _⟩ : ℤ√_) < ⟨_, _⟩ :=
-            show (⟨x, y⟩ - ⟨x, -y⟩ : ℤ√d a1) < ⟨a, 1⟩ - ⟨a, -1⟩ from
-              sub_lt_sub ha fun hn : (⟨x, -y⟩ : ℤ√d a1) ≤ ⟨a, -1⟩ => by
-                have t :=
-                      mul_le_mul_of_nonneg_right
-                        (mul_le_mul_of_nonneg_left hn (le_trans zero_le_one h1)) a1p <;>
-                    rw [bm, one_mul, mul_assoc, Eq.trans (mul_comm _ _) a1m, mul_one] at t <;>
-                  exact ha t
-          simp at y0l <;> simp at yl2 <;>
-            exact
-              match y, y0l, (yl2 : (⟨_, _⟩ : ℤ√_) < ⟨_, _⟩) with
-              | 0, y0l, yl2 => y0l (le_refl 0)
-              | (y + 1 : ℕ), y0l, yl2 =>
-                yl2
-                  (Zsqrtd.le_of_le_le (le_refl 0)
-                    (let t := Int.ofNat_le_ofNat_of_le (Nat.succ_pos y)
-                    add_le_add t t))
-              | -[y+1], y0l, yl2 => y0l trivial
-#align pell.eq_pell_lem Pell.eq_pell_lem
-
-theorem eq_pellZd (b : ℤ√d) (b1 : 1 ≤ b) (hp : is_pell b) : ∃ n, b = pell_zd n :=
-  let ⟨n, h⟩ := @Zsqrtd.le_arch d b
-  eq_pell_lem n b b1 hp <|
-    h.trans <| by
-      rw [Zsqrtd.coe_nat_val] <;>
-        exact
-          Zsqrtd.le_of_le_le (Int.ofNat_le_ofNat_of_le <| le_of_lt <| n_lt_xn _ _)
-            (Int.ofNat_zero_le _)
-#align pell.eq_pell_zd Pell.eq_pellZd
-
-/-- Every solution to **Pell's equation** is recursively obtained from the initial solution
-`(1,0)` using the recursion `pell`. -/
-theorem eq_pell {x y : ℕ} (hp : x * x - d * y * y = 1) : ∃ n, x = xn n ∧ y = yn n :=
-  have : (1 : ℤ√d) ≤ ⟨x, y⟩ :=
-    match x, hp with
-    | 0, (hp : 0 - _ = 1) => by rw [zero_tsub] at hp <;> contradiction
-    | x + 1, hp =>
-      Zsqrtd.le_of_le_le (Int.ofNat_le_ofNat_of_le <| Nat.succ_pos x) (Int.ofNat_zero_le _)
-  let ⟨m, e⟩ := eq_pell_zd ⟨x, y⟩ this (is_pell_nat.2 hp)
-  ⟨m,
-    match x, y, e with
-    | _, _, rfl => ⟨rfl, rfl⟩⟩
-#align pell.eq_pell Pell.eq_pell
-
-theorem pellZd_add (m) : ∀ n, pell_zd (m + n) = pell_zd m * pell_zd n
-  | 0 => (mul_one _).symm
-  | n + 1 => by rw [← add_assoc, pell_zd_succ, pell_zd_succ, pell_zd_add n, ← mul_assoc]
-#align pell.pell_zd_add Pell.pellZd_add
-
-theorem xn_add (m n) : xn (m + n) = xn m * xn n + d * yn m * yn n := by
-  injection pell_zd_add _ m n with h _ <;>
-      repeat' first |rw [← Int.ofNat_add] at h|rw [← Int.ofNat_mul] at h <;>
-    exact Int.ofNat.inj h
-#align pell.xn_add Pell.xn_add
-
-theorem yn_add (m n) : yn (m + n) = xn m * yn n + yn m * xn n := by
-  injection pell_zd_add _ m n with _ h <;>
-      repeat' first |rw [← Int.ofNat_add] at h|rw [← Int.ofNat_mul] at h <;>
-    exact Int.ofNat.inj h
-#align pell.yn_add Pell.yn_add
-
-theorem pellZd_sub {m n} (h : n ≤ m) : pell_zd (m - n) = pell_zd m * (pell_zd n).conj :=
+/-- If `d` is a positive integer that is not a square, then there is a nontrivial solution
+to the Pell equation `x^2 - d*y^2 = 1`. -/
+theorem exists_of_not_isSquare {d : ℤ} (h₀ : 0 < d) (hd : ¬IsSquare d) :
+    ∃ x y : ℤ, x ^ 2 - d * y ^ 2 = 1 ∧ y ≠ 0 :=
   by
-  let t := pell_zd_add n (m - n)
-  rw [add_tsub_cancel_of_le h] at t <;>
-    rw [t, mul_comm (pell_zd _ n) _, mul_assoc, (is_pell_norm _).1 (is_pell_pell_zd _ _), mul_one]
-#align pell.pell_zd_sub Pell.pellZd_sub
-
-theorem xz_sub {m n} (h : n ≤ m) : xz (m - n) = xz m * xz n - d * yz m * yz n :=
-  by
-  rw [sub_eq_add_neg, ← mul_neg]
-  exact congr_arg Zsqrtd.re (pell_zd_sub a1 h)
-#align pell.xz_sub Pell.xz_sub
-
-theorem yz_sub {m n} (h : n ≤ m) : yz (m - n) = xz n * yz m - xz m * yz n :=
-  by
-  rw [sub_eq_add_neg, ← mul_neg, mul_comm, add_comm]
-  exact congr_arg Zsqrtd.im (pell_zd_sub a1 h)
-#align pell.yz_sub Pell.yz_sub
-
-theorem xy_coprime (n) : (xn n).coprime (yn n) :=
-  Nat.coprime_of_dvd' fun k kp kx ky => by
-    let p := pell_eq n
-    rw [← p] <;>
-      exact Nat.dvd_sub (le_of_lt <| Nat.lt_of_sub_eq_succ p) (kx.mul_left _) (ky.mul_left _)
-#align pell.xy_coprime Pell.xy_coprime
-
-theorem strictMono_y : StrictMono yn
-  | m, 0, h => absurd h <| Nat.not_lt_zero _
-  | m, n + 1, h =>
+  let ξ : ℝ := sqrt d
+  have hξ : Irrational ξ :=
     by
-    have : yn m ≤ yn n :=
-      Or.elim (lt_or_eq_of_le <| Nat.le_of_succ_le_succ h) (fun hl => le_of_lt <| strict_mono_y hl)
-        fun e => by rw [e]
-    simp <;> refine' lt_of_le_of_lt _ (Nat.lt_add_of_pos_left <| x_pos a1 n) <;>
-        rw [← mul_one (yn a1 m)] <;>
-      exact mul_le_mul this (le_of_lt a1) (Nat.zero_le _) (Nat.zero_le _)
-#align pell.strict_mono_y Pell.strictMono_y
-
-theorem strictMono_x : StrictMono xn
-  | m, 0, h => absurd h <| Nat.not_lt_zero _
-  | m, n + 1, h =>
+    refine' irrational_nrt_of_notint_nrt 2 d (sq_sqrt <| int.cast_nonneg.mpr h₀.le) _ two_pos
+    rintro ⟨x, hx⟩
+    refine' hd ⟨x, @Int.cast_injective ℝ _ _ d (x * x) _⟩
+    rw [← sq_sqrt <| int.cast_nonneg.mpr h₀.le, Int.cast_mul, ← hx, sq]
+  obtain ⟨M, hM₁⟩ := exists_int_gt (2 * |ξ| + 1)
+  have hM : { q : ℚ | |q.1 ^ 2 - d * q.2 ^ 2| < M }.Infinite :=
     by
-    have : xn m ≤ xn n :=
-      Or.elim (lt_or_eq_of_le <| Nat.le_of_succ_le_succ h) (fun hl => le_of_lt <| strict_mono_x hl)
-        fun e => by rw [e]
-    simp <;> refine' lt_of_lt_of_le (lt_of_le_of_lt this _) (Nat.le_add_right _ _) <;>
-        have t := Nat.mul_lt_mul_of_pos_left a1 (x_pos a1 n) <;>
-      rwa [mul_one] at t
-#align pell.strict_mono_x Pell.strictMono_x
-
-theorem yn_ge_n : ∀ n, n ≤ yn n
-  | 0 => Nat.zero_le _
-  | n + 1 =>
-    show n < yn (n + 1) from lt_of_le_of_lt (yn_ge_n n) (strict_mono_y <| Nat.lt_succ_self n)
-#align pell.yn_ge_n Pell.yn_ge_n
-
-theorem y_mul_dvd (n) : ∀ k, yn n ∣ yn (n * k)
-  | 0 => dvd_zero _
-  | k + 1 => by
-    rw [Nat.mul_succ, yn_add] <;> exact dvd_add (dvd_mul_left _ _) ((y_mul_dvd k).mul_right _)
-#align pell.y_mul_dvd Pell.y_mul_dvd
-
-theorem y_dvd_iff (m n) : yn m ∣ yn n ↔ m ∣ n :=
-  ⟨fun h =>
-    Nat.dvd_of_mod_eq_zero <|
-      (Nat.eq_zero_or_pos _).resolve_right fun hp =>
-        by
-        have co : Nat.coprime (yn m) (xn (m * (n / m))) :=
-          Nat.coprime.symm <| (xy_coprime _).coprime_dvd_right (y_mul_dvd m (n / m))
-        have m0 : 0 < m :=
-          m.eq_zero_or_pos.resolve_left fun e => by
-            rw [e, Nat.mod_zero] at hp <;> rw [e] at h <;>
-              exact ne_of_lt (strict_mono_y a1 hp) (eq_zero_of_zero_dvd h).symm
-        rw [← Nat.mod_add_div n m, yn_add] at h <;>
-          exact
-            not_le_of_gt (strict_mono_y _ <| Nat.mod_lt n m0)
-              (Nat.le_of_dvd (strict_mono_y _ hp) <|
-                co.dvd_of_dvd_mul_right <|
-                  (Nat.dvd_add_iff_right <| (y_mul_dvd _ _ _).mul_left _).2 h),
-    fun ⟨k, e⟩ => by rw [e] <;> apply y_mul_dvd⟩
-#align pell.y_dvd_iff Pell.y_dvd_iff
-
-theorem xy_modEq_yn (n) :
-    ∀ k,
-      xn (n * k) ≡ xn n ^ k [MOD yn n ^ 2] ∧ yn (n * k) ≡ k * xn n ^ (k - 1) * yn n [MOD yn n ^ 3]
-  | 0 => by constructor <;> simp
-  | k + 1 => by
-    let ⟨hx, hy⟩ := xy_modeq_yn k
-    have L : xn (n * k) * xn n + d * yn (n * k) * yn n ≡ xn n ^ k * xn n + 0 [MOD yn n ^ 2] :=
-      (hx.mul_right _).add <|
-        modEq_zero_iff_dvd.2 <| by
-          rw [pow_succ'] <;>
-            exact
-              mul_dvd_mul_right
-                (dvd_mul_of_dvd_right
-                  (modeq_zero_iff_dvd.1 <|
-                    (hy.of_dvd <| by simp [pow_succ']).trans <|
-                      modeq_zero_iff_dvd.2 <| by simp [-mul_comm, -mul_assoc])
-                  _)
-                _
-    have R :
-      xn (n * k) * yn n + yn (n * k) * xn n ≡ xn n ^ k * yn n + k * xn n ^ k * yn n [MOD
-        yn n ^ 3] :=
-      ModEq.add
-          (by
-            rw [pow_succ']
-            exact hx.mul_right' _) <|
-        by
-        have : k * xn n ^ (k - 1) * yn n * xn n = k * xn n ^ k * yn n := by
-          clear _let_match <;> cases' k with k <;> simp [pow_succ', mul_comm, mul_left_comm]
-        rw [← this]
-        exact hy.mul_right _
-    rw [add_tsub_cancel_right, Nat.mul_succ, xn_add, yn_add, pow_succ' (xn _ n), Nat.succ_mul,
-      add_comm (k * xn _ n ^ k) (xn _ n ^ k), right_distrib]
-    exact ⟨L, R⟩
-#align pell.xy_modeq_yn Pell.xy_modEq_yn
-
-theorem ysq_dvd_yy (n) : yn n * yn n ∣ yn (n * yn n) :=
-  modEq_zero_iff_dvd.1 <|
-    ((xy_modeq_yn n (yn n)).right.of_dvd <| by simp [pow_succ]).trans
-      (modEq_zero_iff_dvd.2 <| by simp [mul_dvd_mul_left, mul_assoc])
-#align pell.ysq_dvd_yy Pell.ysq_dvd_yy
-
-theorem dvd_of_ysq_dvd {n t} (h : yn n * yn n ∣ yn t) : yn n ∣ t :=
-  have nt : n ∣ t := (y_dvd_iff n t).1 <| dvd_of_mul_left_dvd h
-  n.eq_zero_or_pos.elim (fun n0 => by rwa [n0] at nt⊢) fun n0l : 0 < n =>
+    refine' infinite.mono (fun q h => _) (infinite_rat_abs_sub_lt_one_div_denom_sq_of_irrational hξ)
+    have h0 : 0 < (q.2 : ℝ) ^ 2 := pow_pos (nat.cast_pos.mpr q.pos) 2
+    have h1 : (q.num : ℝ) / (q.denom : ℝ) = q := by exact_mod_cast q.num_div_denom
+    rw [mem_set_of, abs_sub_comm, ← @Int.cast_lt ℝ, ← div_lt_div_right (abs_pos_of_pos h0)]
+    push_cast
+    rw [← abs_div, abs_sq, sub_div, mul_div_cancel _ h0.ne', ← div_pow, h1, ←
+      sq_sqrt (int.cast_pos.mpr h₀).le, sq_sub_sq, abs_mul, ← mul_one_div]
+    refine' mul_lt_mul'' (((abs_add ξ q).trans _).trans_lt hM₁) h (abs_nonneg _) (abs_nonneg _)
+    rw [two_mul, add_assoc, add_le_add_iff_left, ← sub_le_iff_le_add']
+    rw [mem_set_of, abs_sub_comm] at h
+    refine' (abs_sub_abs_le_abs_sub (q : ℝ) ξ).trans (h.le.trans _)
+    rw [div_le_one h0, one_le_sq_iff_one_le_abs, Nat.abs_cast, Nat.one_le_cast]
+    exact q.pos
+  obtain ⟨m, hm⟩ : ∃ m : ℤ, { q : ℚ | q.1 ^ 2 - d * q.2 ^ 2 = m }.Infinite :=
     by
-    let ⟨k, ke⟩ := nt
-    have : yn n ∣ k * xn n ^ (k - 1) :=
-      Nat.dvd_of_mul_dvd_mul_right (strict_mono_y n0l) <|
-        modEq_zero_iff_dvd.1 <| by
-          have xm := (xy_modeq_yn a1 n k).right <;> rw [← ke] at xm <;>
-            exact (xm.of_dvd <| by simp [pow_succ]).symm.trans h.modeq_zero_nat
-    rw [ke] <;>
-      exact dvd_mul_of_dvd_right (((xy_coprime _ _).pow_leftₓ _).symm.dvd_of_dvd_mul_right this) _
-#align pell.dvd_of_ysq_dvd Pell.dvd_of_ysq_dvd
-
-theorem pellZd_succ_succ (n) : pell_zd (n + 2) + pell_zd n = (2 * a : ℕ) * pell_zd (n + 1) :=
-  by
-  have : (1 : ℤ√d) + ⟨a, 1⟩ * ⟨a, 1⟩ = ⟨a, 1⟩ * (2 * a) :=
+    contrapose! hM
+    simp only [not_infinite] at hM⊢
+    refine' (congr_arg _ (ext fun x => _)).mp (finite.bUnion (finite_Ioo (-M) M) fun m _ => hM m)
+    simp only [abs_lt, mem_set_of_eq, mem_Ioo, mem_Union, exists_prop, exists_eq_right']
+  have hm₀ : m ≠ 0 := by
+    rintro rfl
+    obtain ⟨q, hq⟩ := hm.nonempty
+    rw [mem_set_of, sub_eq_zero, mul_comm] at hq
+    obtain ⟨a, ha⟩ := (Int.pow_dvd_pow_iff two_pos).mp ⟨d, hq⟩
+    rw [ha, mul_pow, mul_right_inj' (pow_pos (int.coe_nat_pos.mpr q.pos) 2).ne'] at hq
+    exact hd ⟨a, sq a ▸ hq.symm⟩
+  haveI := ne_zero_iff.mpr (int.nat_abs_ne_zero.mpr hm₀)
+  let f : ℚ → ZMod m.nat_abs × ZMod m.nat_abs := fun q => (q.1, q.2)
+  obtain ⟨q₁, h₁ : q₁.1 ^ 2 - d * q₁.2 ^ 2 = m, q₂, h₂ : q₂.1 ^ 2 - d * q₂.2 ^ 2 = m, hne, hqf⟩ :=
+    hm.exists_ne_map_eq_of_maps_to (maps_to_univ f _) finite_univ
+  obtain ⟨hq1 : (q₁.1 : ZMod m.nat_abs) = q₂.1, hq2 : (q₁.2 : ZMod m.nat_abs) = q₂.2⟩ :=
+    prod.ext_iff.mp hqf
+  have hd₁ : m ∣ q₁.1 * q₂.1 - d * (q₁.2 * q₂.2) :=
     by
-    rw [Zsqrtd.coe_nat_val]
-    change (⟨_, _⟩ : ℤ√d a1) = ⟨_, _⟩
-    rw [dz_val]
-    dsimp [az]
-    rw [Zsqrtd.ext]
-    dsimp
-    constructor <;> ring
-  simpa [mul_add, mul_comm, mul_left_comm, add_comm] using congr_arg (· * pell_zd a1 n) this
-#align pell.pell_zd_succ_succ Pell.pellZd_succ_succ
-
-theorem xy_succ_succ (n) :
-    xn (n + 2) + xn n = 2 * a * xn (n + 1) ∧ yn (n + 2) + yn n = 2 * a * yn (n + 1) :=
-  by
-  have := pell_zd_succ_succ a1 n; unfold pell_zd at this
-  erw [Zsqrtd.smul_val (2 * a : ℕ)] at this
-  injection this with h₁ h₂
-  constructor <;> apply Int.ofNat.inj <;> [simpa using h₁, simpa using h₂]
-#align pell.xy_succ_succ Pell.xy_succ_succ
-
-theorem xn_succ_succ (n) : xn (n + 2) + xn n = 2 * a * xn (n + 1) :=
-  (xy_succ_succ n).1
-#align pell.xn_succ_succ Pell.xn_succ_succ
-
-theorem yn_succ_succ (n) : yn (n + 2) + yn n = 2 * a * yn (n + 1) :=
-  (xy_succ_succ n).2
-#align pell.yn_succ_succ Pell.yn_succ_succ
-
-theorem xz_succ_succ (n) : xz (n + 2) = (2 * a : ℕ) * xz (n + 1) - xz n :=
-  eq_sub_of_add_eq <| by delta xz <;> rw [← Int.ofNat_add, ← Int.ofNat_mul, xn_succ_succ]
-#align pell.xz_succ_succ Pell.xz_succ_succ
-
-theorem yz_succ_succ (n) : yz (n + 2) = (2 * a : ℕ) * yz (n + 1) - yz n :=
-  eq_sub_of_add_eq <| by delta yz <;> rw [← Int.ofNat_add, ← Int.ofNat_mul, yn_succ_succ]
-#align pell.yz_succ_succ Pell.yz_succ_succ
-
-theorem yn_modEq_a_sub_one : ∀ n, yn n ≡ n [MOD a - 1]
-  | 0 => by simp
-  | 1 => by simp
-  | n + 2 =>
-    (yn_modeq_a_sub_one n).add_right_cancel <|
-      by
-      rw [yn_succ_succ, (by ring : n + 2 + n = 2 * (n + 1))]
-      exact ((modeq_sub a1.le).mul_left 2).mul (yn_modeq_a_sub_one (n + 1))
-#align pell.yn_modeq_a_sub_one Pell.yn_modEq_a_sub_one
-
-theorem yn_modEq_two : ∀ n, yn n ≡ n [MOD 2]
-  | 0 => by simp
-  | 1 => by simp
-  | n + 2 =>
-    (yn_modeq_two n).add_right_cancel <|
-      by
-      rw [yn_succ_succ, mul_assoc, (by ring : n + 2 + n = 2 * (n + 1))]
-      exact (dvd_mul_right 2 _).modEq_zero_nat.trans (dvd_mul_right 2 _).zero_modEq_nat
-#align pell.yn_modeq_two Pell.yn_modEq_two
-
-section
-
-omit a1
-
-theorem x_sub_y_dvd_pow_lem (y2 y1 y0 yn1 yn0 xn1 xn0 ay a2 : ℤ) :
-    (a2 * yn1 - yn0) * ay + y2 - (a2 * xn1 - xn0) =
-      y2 - a2 * y1 + y0 + a2 * (yn1 * ay + y1 - xn1) - (yn0 * ay + y0 - xn0) :=
-  by ring
-#align pell.x_sub_y_dvd_pow_lem Pell.x_sub_y_dvd_pow_lem
-
-end
-
-theorem x_sub_y_dvd_pow (y : ℕ) :
-    ∀ n, (2 * a * y - y * y - 1 : ℤ) ∣ yz n * (a - y) + ↑(y ^ n) - xz n
-  | 0 => by simp [xz, yz, Int.ofNat_zero, Int.ofNat_one]
-  | 1 => by simp [xz, yz, Int.ofNat_zero, Int.ofNat_one]
-  | n + 2 =>
-    by
-    have : (2 * a * y - y * y - 1 : ℤ) ∣ ↑(y ^ (n + 2)) - ↑(2 * a) * ↑(y ^ (n + 1)) + ↑(y ^ n) :=
-      ⟨-↑(y ^ n),
-        by
-        simp [pow_succ, mul_add, Int.ofNat_mul, show ((2 : ℕ) : ℤ) = 2 from rfl, mul_comm,
-          mul_left_comm]
-        ring⟩
-    rw [xz_succ_succ, yz_succ_succ, x_sub_y_dvd_pow_lem ↑(y ^ (n + 2)) ↑(y ^ (n + 1)) ↑(y ^ n)]
-    exact dvd_sub (dvd_add this <| (x_sub_y_dvd_pow (n + 1)).mul_left _) (x_sub_y_dvd_pow n)
-#align pell.x_sub_y_dvd_pow Pell.x_sub_y_dvd_pow
-
-theorem xn_modeq_x2n_add_lem (n j) : xn n ∣ d * yn n * (yn n * xn j) + xn j :=
-  by
-  have h1 : d * yn n * (yn n * xn j) + xn j = (d * yn n * yn n + 1) * xn j := by
-    simp [add_mul, mul_assoc]
-  have h2 : d * yn n * yn n + 1 = xn n * xn n := by
-    apply Int.ofNat.inj <;> repeat' first |rw [Int.ofNat_add]|rw [Int.ofNat_mul] <;>
-      exact add_eq_of_eq_sub' (Eq.symm <| pell_eqz _ _)
-  rw [h2] at h1 <;> rw [h1, mul_assoc] <;> exact dvd_mul_right _ _
-#align pell.xn_modeq_x2n_add_lem Pell.xn_modeq_x2n_add_lem
-
-theorem xn_modEq_x2n_add (n j) : xn (2 * n + j) + xn j ≡ 0 [MOD xn n] :=
-  by
-  rw [two_mul, add_assoc, xn_add, add_assoc, ← zero_add 0]
-  refine' (dvd_mul_right (xn a1 n) (xn a1 (n + j))).modEq_zero_nat.add _
-  rw [yn_add, left_distrib, add_assoc, ← zero_add 0]
-  exact
-    ((dvd_mul_right _ _).mul_left _).modEq_zero_nat.add (xn_modeq_x2n_add_lem _ _ _).modEq_zero_nat
-#align pell.xn_modeq_x2n_add Pell.xn_modEq_x2n_add
-
-theorem xn_modEq_x2n_sub_lem {n j} (h : j ≤ n) : xn (2 * n - j) + xn j ≡ 0 [MOD xn n] :=
-  by
-  have h1 : xz n ∣ ↑d * yz n * yz (n - j) + xz j := by
-    rw [yz_sub _ h, mul_sub_left_distrib, sub_add_eq_add_sub] <;>
-      exact
-        dvd_sub
-          (by
-            delta xz <;> delta yz <;> repeat' first |rw [← Int.ofNat_add]|rw [← Int.ofNat_mul] <;>
-                rw [mul_comm (xn a1 j) (yn a1 n)] <;>
-              exact Int.coe_nat_dvd.2 (xn_modeq_x2n_add_lem _ _ _))
-          ((dvd_mul_right _ _).mul_left _)
-  rw [two_mul, add_tsub_assoc_of_le h, xn_add, add_assoc, ← zero_add 0]
-  exact
-    (dvd_mul_right _ _).modEq_zero_nat.add
-      (Int.coe_nat_dvd.1 <| by simpa [xz, yz] using h1).modEq_zero_nat
-#align pell.xn_modeq_x2n_sub_lem Pell.xn_modEq_x2n_sub_lem
-
-theorem xn_modEq_x2n_sub {n j} (h : j ≤ 2 * n) : xn (2 * n - j) + xn j ≡ 0 [MOD xn n] :=
-  (le_total j n).elim xn_modeq_x2n_sub_lem fun jn =>
-    by
-    have : 2 * n - j + j ≤ n + j := by
-      rw [tsub_add_cancel_of_le h, two_mul] <;> exact Nat.add_le_add_left jn _
-    let t := xn_modeq_x2n_sub_lem (Nat.le_of_add_le_add_right this)
-    rwa [tsub_tsub_cancel_of_le h, add_comm] at t
-#align pell.xn_modeq_x2n_sub Pell.xn_modEq_x2n_sub
-
-theorem xn_modEq_x4n_add (n j) : xn (4 * n + j) ≡ xn j [MOD xn n] :=
-  ModEq.add_right_cancel' (xn (2 * n + j)) <| by
-    refine' @modeq.trans _ _ 0 _ _ (by rw [add_comm] <;> exact (xn_modeq_x2n_add _ _ _).symm) <;>
-        rw [show 4 * n = 2 * n + 2 * n from right_distrib 2 2 n, add_assoc] <;>
-      apply xn_modeq_x2n_add
-#align pell.xn_modeq_x4n_add Pell.xn_modEq_x4n_add
-
-theorem xn_modEq_x4n_sub {n j} (h : j ≤ 2 * n) : xn (4 * n - j) ≡ xn j [MOD xn n] :=
-  have h' : j ≤ 2 * n := le_trans h (by rw [Nat.succ_mul] <;> apply Nat.le_add_left)
-  ModEq.add_right_cancel' (xn (2 * n - j)) <| by
-    refine' @modeq.trans _ _ 0 _ _ (by rw [add_comm] <;> exact (xn_modeq_x2n_sub _ h).symm) <;>
-        rw [show 4 * n = 2 * n + 2 * n from right_distrib 2 2 n, add_tsub_assoc_of_le h'] <;>
-      apply xn_modeq_x2n_add
-#align pell.xn_modeq_x4n_sub Pell.xn_modEq_x4n_sub
-
-theorem eq_of_xn_modeq_lem1 {i n} : ∀ {j}, i < j → j < n → xn i % xn n < xn j % xn n
-  | 0, ij, _ => absurd ij (Nat.not_lt_zero _)
-  | j + 1, ij, jn =>
+    rw [← Int.natAbs_dvd, ← ZMod.int_coe_zMod_eq_zero_iff_dvd]
+    push_cast
+    rw [hq1, hq2, ← sq, ← sq]
+    norm_cast
+    rw [ZMod.int_coe_zMod_eq_zero_iff_dvd, Int.natAbs_dvd, Nat.cast_pow, ← h₂]
+  have hd₂ : m ∣ q₁.1 * q₂.2 - q₂.1 * q₁.2 :=
     by
-    suffices xn j % xn n < xn (j + 1) % xn n from
-      (lt_or_eq_of_le (Nat.le_of_succ_le_succ ij)).elim
-        (fun h => lt_trans (eq_of_xn_modeq_lem1 h (le_of_lt jn)) this) fun h => by
-        rw [h] <;> exact this
-    rw [Nat.mod_eq_of_lt (strict_mono_x _ (Nat.lt_of_succ_lt jn)),
-        Nat.mod_eq_of_lt (strict_mono_x _ jn)] <;>
-      exact strict_mono_x _ (Nat.lt_succ_self _)
-#align pell.eq_of_xn_modeq_lem1 Pell.eq_of_xn_modeq_lem1
-
-theorem eq_of_xn_modeq_lem2 {n} (h : 2 * xn n = xn (n + 1)) : a = 2 ∧ n = 0 := by
-  rw [xn_succ, mul_comm] at h <;>
-    exact
-      by
-      have : n = 0 :=
-        n.eq_zero_or_pos.resolve_right fun np =>
-          ne_of_lt
-            (lt_of_le_of_lt (Nat.mul_le_mul_left _ a1)
-              (Nat.lt_add_of_pos_right <| mul_pos (d_pos a1) (strict_mono_y a1 np)))
-            h
-      cases this <;> simp at h <;> exact ⟨h.symm, rfl⟩
-#align pell.eq_of_xn_modeq_lem2 Pell.eq_of_xn_modeq_lem2
-
-theorem eq_of_xn_modeq_lem3 {i n} (npos : 0 < n) :
-    ∀ {j}, i < j → j ≤ 2 * n → j ≠ n → ¬(a = 2 ∧ n = 1 ∧ i = 0 ∧ j = 2) → xn i % xn n < xn j % xn n
-  | 0, ij, _, _, _ => absurd ij (Nat.not_lt_zero _)
-  | j + 1, ij, j2n, jnn, ntriv =>
-    have lem2 : ∀ k > n, k ≤ 2 * n → (↑(xn k % xn n) : ℤ) = xn n - xn (2 * n - k) := fun k kn k2n =>
-      by
-      let k2nl :=
-        lt_of_add_lt_add_right <|
-          show 2 * n - k + k < n + k by
-            rw [tsub_add_cancel_of_le]
-            rw [two_mul] <;> exact add_lt_add_left kn n
-            exact k2n
-      have xle : xn (2 * n - k) ≤ xn n := le_of_lt <| strict_mono_x k2nl
-      suffices xn k % xn n = xn n - xn (2 * n - k) by rw [this, Int.ofNat_sub xle]
-      rw [← Nat.mod_eq_of_lt (Nat.sub_lt (x_pos a1 n) (x_pos a1 (2 * n - k)))]
-      apply modeq.add_right_cancel' (xn a1 (2 * n - k))
-      rw [tsub_add_cancel_of_le xle]
-      have t := xn_modeq_x2n_sub_lem a1 k2nl.le
-      rw [tsub_tsub_cancel_of_le k2n] at t
-      exact t.trans dvd_rfl.zero_modeq_nat
-    (lt_trichotomy j n).elim (fun jn : j < n => eq_of_xn_modeq_lem1 ij (lt_of_le_of_ne jn jnn))
-      fun o =>
-      o.elim
-        (fun jn : j = n => by
-          cases jn
-          apply Int.lt_of_ofNat_lt_ofNat
-          rw [lem2 (n + 1) (Nat.lt_succ_self _) j2n,
-            show 2 * n - (n + 1) = n - 1 by
-              rw [two_mul, tsub_add_eq_tsub_tsub, add_tsub_cancel_right]]
-          refine' lt_sub_left_of_add_lt (Int.ofNat_lt_ofNat_of_lt _)
-          cases' lt_or_eq_of_le <| Nat.le_of_succ_le_succ ij with lin ein
-          · rw [Nat.mod_eq_of_lt (strict_mono_x _ lin)]
-            have ll : xn a1 (n - 1) + xn a1 (n - 1) ≤ xn a1 n :=
-              by
-              rw [← two_mul, mul_comm,
-                show xn a1 n = xn a1 (n - 1 + 1) by rw [tsub_add_cancel_of_le (succ_le_of_lt npos)],
-                xn_succ]
-              exact le_trans (Nat.mul_le_mul_left _ a1) (Nat.le_add_right _ _)
-            have npm : (n - 1).succ = n := Nat.succ_pred_eq_of_pos npos
-            have il : i ≤ n - 1 := by
-              apply Nat.le_of_succ_le_succ
-              rw [npm]
-              exact lin
-            cases' lt_or_eq_of_le il with ill ile
-            · exact lt_of_lt_of_le (Nat.add_lt_add_left (strict_mono_x a1 ill) _) ll
-            · rw [ile]
-              apply lt_of_le_of_ne ll
-              rw [← two_mul]
-              exact fun e =>
-                ntriv <|
-                  by
-                  let ⟨a2, s1⟩ :=
-                    @eq_of_xn_modeq_lem2 _ a1 (n - 1)
-                      (by rwa [tsub_add_cancel_of_le (succ_le_of_lt npos)])
-                  have n1 : n = 1 := le_antisymm (tsub_eq_zero_iff_le.mp s1) npos
-                  rw [ile, a2, n1] <;> exact ⟨rfl, rfl, rfl, rfl⟩
-          · rw [ein, Nat.mod_self, add_zero]
-            exact strict_mono_x _ (Nat.pred_lt npos.ne'))
-        fun jn : j > n =>
-        have lem1 : j ≠ n → xn j % xn n < xn (j + 1) % xn n → xn i % xn n < xn (j + 1) % xn n :=
-          fun jn s =>
-          (lt_or_eq_of_le (Nat.le_of_succ_le_succ ij)).elim
-            (fun h =>
-              lt_trans
-                (eq_of_xn_modeq_lem3 h (le_of_lt j2n) jn fun ⟨a1, n1, i0, j2⟩ => by
-                  rw [n1, j2] at j2n <;> exact absurd j2n (by decide))
-                s)
-            fun h => by rw [h] <;> exact s
-        lem1 (ne_of_gt jn) <|
-          Int.lt_of_ofNat_lt_ofNat <|
-            by
-            rw [lem2 j jn (le_of_lt j2n), lem2 (j + 1) (Nat.le_succ_of_le jn) j2n]
-            refine' sub_lt_sub_left (Int.ofNat_lt_ofNat_of_lt <| strict_mono_x _ _) _
-            rw [Nat.sub_succ]
-            exact Nat.pred_lt (ne_of_gt <| tsub_pos_of_lt j2n)
-#align pell.eq_of_xn_modeq_lem3 Pell.eq_of_xn_modeq_lem3
-
-theorem eq_of_xn_modEq_le {i j n} (ij : i ≤ j) (j2n : j ≤ 2 * n) (h : xn i ≡ xn j [MOD xn n])
-    (ntriv : ¬(a = 2 ∧ n = 1 ∧ i = 0 ∧ j = 2)) : i = j :=
-  if npos : n = 0 then by simp_all
-  else
-    (lt_or_eq_of_le ij).resolve_left fun ij' =>
-      if jn : j = n then by
-        refine' ne_of_gt _ h
-        rw [jn, Nat.mod_self]
-        have x0 : 0 < xn a1 0 % xn a1 n := by
-          rw [Nat.mod_eq_of_lt (strict_mono_x a1 (Nat.pos_of_ne_zero npos))] <;> exact by decide
-        cases' i with i
-        exact x0
-        rw [jn] at ij'
-        exact
-          x0.trans
-            (eq_of_xn_modeq_lem3 _ (Nat.pos_of_ne_zero npos) (Nat.succ_pos _) (le_trans ij j2n)
-              (ne_of_lt ij') fun ⟨a1, n1, _, i2⟩ => by
-              rw [n1, i2] at ij' <;> exact absurd ij' (by decide))
-      else ne_of_lt (eq_of_xn_modeq_lem3 (Nat.pos_of_ne_zero npos) ij' j2n jn ntriv) h
-#align pell.eq_of_xn_modeq_le Pell.eq_of_xn_modEq_le
-
-theorem eq_of_xn_modEq {i j n} (i2n : i ≤ 2 * n) (j2n : j ≤ 2 * n) (h : xn i ≡ xn j [MOD xn n])
-    (ntriv : a = 2 → n = 1 → (i = 0 → j ≠ 2) ∧ (i = 2 → j ≠ 0)) : i = j :=
-  (le_total i j).elim
-    (fun ij => eq_of_xn_modeq_le ij j2n h fun ⟨a2, n1, i0, j2⟩ => (ntriv a2 n1).left i0 j2)
-    fun ij =>
-    (eq_of_xn_modeq_le ij i2n h.symm fun ⟨a2, n1, j0, i2⟩ => (ntriv a2 n1).right i2 j0).symm
-#align pell.eq_of_xn_modeq Pell.eq_of_xn_modEq
-
-theorem eq_of_xn_modeq' {i j n} (ipos : 0 < i) (hin : i ≤ n) (j4n : j ≤ 4 * n)
-    (h : xn j ≡ xn i [MOD xn n]) : j = i ∨ j + i = 4 * n :=
-  have i2n : i ≤ 2 * n := by apply le_trans hin <;> rw [two_mul] <;> apply Nat.le_add_left
-  (le_or_gt j (2 * n)).imp
-    (fun j2n : j ≤ 2 * n =>
-      eq_of_xn_modeq j2n i2n h fun a2 n1 =>
-        ⟨fun j0 i2 => by rw [n1, i2] at hin <;> exact absurd hin (by decide), fun j2 i0 =>
-          ne_of_gt ipos i0⟩)
-    fun j2n : 2 * n < j =>
-    suffices i = 4 * n - j by rw [this, add_tsub_cancel_of_le j4n]
-    have j42n : 4 * n - j ≤ 2 * n :=
-      @Nat.le_of_add_le_add_right j _ _ <| by
-        rw [tsub_add_cancel_of_le j4n, show 4 * n = 2 * n + 2 * n from right_distrib 2 2 n] <;>
-          exact Nat.add_le_add_left (le_of_lt j2n) _
-    eq_of_xn_modeq i2n j42n
-      (h.symm.trans <| by
-        let t := xn_modeq_x4n_sub j42n
-        rwa [tsub_tsub_cancel_of_le j4n] at t)
-      fun a2 n1 =>
-      ⟨fun i0 => absurd i0 (ne_of_gt ipos), fun i2 =>
-        by
-        rw [n1, i2] at hin
-        exact absurd hin (by decide)⟩
-#align pell.eq_of_xn_modeq' Pell.eq_of_xn_modeq'
-
-theorem modEq_of_xn_modEq {i j n} (ipos : 0 < i) (hin : i ≤ n) (h : xn j ≡ xn i [MOD xn n]) :
-    j ≡ i [MOD 4 * n] ∨ j + i ≡ 0 [MOD 4 * n] :=
-  let j' := j % (4 * n)
-  have n4 : 0 < 4 * n := mul_pos (by decide) (ipos.trans_le hin)
-  have jl : j' < 4 * n := Nat.mod_lt _ n4
-  have jj : j ≡ j' [MOD 4 * n] := by delta modeq <;> rw [Nat.mod_eq_of_lt jl]
-  have : ∀ j q, xn (j + 4 * n * q) ≡ xn j [MOD xn n] :=
-    by
-    intro j q; induction' q with q IH; · simp
-    rw [Nat.mul_succ, ← add_assoc, add_comm]
-    exact (xn_modeq_x4n_add _ _ _).trans IH
-  Or.imp (fun ji : j' = i => by rwa [← ji])
-    (fun ji : j' + i = 4 * n =>
-      (jj.add_right _).trans <| by
-        rw [ji]
-        exact dvd_rfl.modeq_zero_nat)
-    (eq_of_xn_modeq' ipos hin jl.le <|
-      (h.symm.trans <| by
-          rw [← Nat.mod_add_div j (4 * n)]
-          exact this j' _).symm)
-#align pell.modeq_of_xn_modeq Pell.modEq_of_xn_modEq
-
-end
-
-theorem xy_modEq_of_modEq {a b c} (a1 : 1 < a) (b1 : 1 < b) (h : a ≡ b [MOD c]) :
-    ∀ n, xn a1 n ≡ xn b1 n [MOD c] ∧ yn a1 n ≡ yn b1 n [MOD c]
-  | 0 => by constructor <;> rfl
-  | 1 => by simp <;> exact ⟨h, modeq.refl 1⟩
-  | n + 2 =>
-    ⟨(xy_modeq_of_modeq n).left.add_right_cancel <|
-        by
-        rw [xn_succ_succ a1, xn_succ_succ b1]
-        exact (h.mul_left _).mul (xy_modeq_of_modeq (n + 1)).left,
-      (xy_modeq_of_modeq n).right.add_right_cancel <|
-        by
-        rw [yn_succ_succ a1, yn_succ_succ b1]
-        exact (h.mul_left _).mul (xy_modeq_of_modeq (n + 1)).right⟩
-#align pell.xy_modeq_of_modeq Pell.xy_modEq_of_modEq
-
-theorem matiyasevic {a k x y} :
-    (∃ a1 : 1 < a, xn a1 k = x ∧ yn a1 k = y) ↔
-      1 < a ∧
-        k ≤ y ∧
-          (x = 1 ∧ y = 0 ∨
-            ∃ u v s t b : ℕ,
-              x * x - (a * a - 1) * y * y = 1 ∧
-                u * u - (a * a - 1) * v * v = 1 ∧
-                  s * s - (b * b - 1) * t * t = 1 ∧
-                    1 < b ∧
-                      b ≡ 1 [MOD 4 * y] ∧
-                        b ≡ a [MOD u] ∧ 0 < v ∧ y * y ∣ v ∧ s ≡ x [MOD u] ∧ t ≡ k [MOD 4 * y]) :=
-  ⟨fun ⟨a1, hx, hy⟩ => by
-    rw [← hx, ← hy] <;>
-        refine'
-          ⟨a1,
-            (Nat.eq_zero_or_pos k).elim (fun k0 => by rw [k0] <;> exact ⟨le_rfl, Or.inl ⟨rfl, rfl⟩⟩)
-              fun kpos => _⟩ <;>
-      exact
-        let x := xn a1 k
-        let y := yn a1 k
-        let m := 2 * (k * y)
-        let u := xn a1 m
-        let v := yn a1 m
-        have ky : k ≤ y := yn_ge_n a1 k
-        have yv : y * y ∣ v := (ysq_dvd_yy a1 k).trans <| (y_dvd_iff _ _ _).2 <| dvd_mul_left _ _
-        have uco : Nat.coprime u (4 * y) :=
-          have : 2 ∣ v :=
-            modeq_zero_iff_dvd.1 <| (yn_modeq_two _ _).trans (dvd_mul_right _ _).modEq_zero_nat
-          have : Nat.coprime u 2 := (xy_coprime a1 m).coprime_dvd_right this
-          (this.mul_right this).mul_right <|
-            (xy_coprime _ _).coprime_dvd_right (dvd_of_mul_left_dvd yv)
-        let ⟨b, ba, bm1⟩ := chinese_remainder uco a 1
-        have m1 : 1 < m :=
-          have : 0 < k * y := mul_pos kpos (strict_mono_y a1 kpos)
-          Nat.mul_le_mul_left 2 this
-        have vp : 0 < v := strict_mono_y a1 (lt_trans zero_lt_one m1)
-        have b1 : 1 < b :=
-          have : xn a1 1 < u := strict_mono_x a1 m1
-          have : a < u := by simp at this <;> exact this
-          lt_of_lt_of_le a1 <| by
-            delta modeq at ba <;> rw [Nat.mod_eq_of_lt this] at ba <;> rw [← ba] <;>
-              apply Nat.mod_le
-        let s := xn b1 k
-        let t := yn b1 k
-        have sx : s ≡ x [MOD u] := (xy_modeq_of_modeq b1 a1 ba k).left
-        have tk : t ≡ k [MOD 4 * y] :=
-          have : 4 * y ∣ b - 1 :=
-            Int.coe_nat_dvd.1 <| by rw [Int.ofNat_sub (le_of_lt b1)] <;> exact bm1.symm.dvd
-          (yn_modeq_a_sub_one _ _).of_dvd this
-        ⟨ky,
-          Or.inr
-            ⟨u, v, s, t, b, pell_eq _ _, pell_eq _ _, pell_eq _ _, b1, bm1, ba, vp, yv, sx, tk⟩⟩,
-    fun ⟨a1, ky, o⟩ =>
-    ⟨a1,
-      match o with
-      | Or.inl ⟨x1, y0⟩ => by
-        rw [y0] at ky <;> rw [Nat.eq_zero_of_le_zero ky, x1, y0] <;> exact ⟨rfl, rfl⟩
-      | Or.inr ⟨u, v, s, t, b, xy, uv, st, b1, rem⟩ =>
-        match x, y, eq_pell a1 xy, u, v, eq_pell a1 uv, s, t, eq_pell b1 st, rem, ky with
-        | _, _, ⟨i, rfl, rfl⟩, _, _, ⟨n, rfl, rfl⟩, _, _, ⟨j, rfl, rfl⟩,
-          ⟨(bm1 : b ≡ 1 [MOD 4 * yn a1 i]), (ba : b ≡ a [MOD xn a1 n]), (vp : 0 < yn a1 n),
-            (yv : yn a1 i * yn a1 i ∣ yn a1 n), (sx : xn b1 j ≡ xn a1 i [MOD xn a1 n]),
-            (tk : yn b1 j ≡ k [MOD 4 * yn a1 i])⟩,
-          (ky : k ≤ yn a1 i) =>
-          (Nat.eq_zero_or_pos i).elim
-            (fun i0 => by simp [i0] at ky <;> rw [i0, ky] <;> exact ⟨rfl, rfl⟩) fun ipos =>
-            by
-            suffices i = k by rw [this] <;> exact ⟨rfl, rfl⟩
-            clear _x o rem xy uv st _match _match _fun_match <;>
-              exact
-                by
-                have iln : i ≤ n :=
-                  le_of_not_gt fun hin =>
-                    not_lt_of_ge (Nat.le_of_dvd vp (dvd_of_mul_left_dvd yv)) (strict_mono_y a1 hin)
-                have yd : 4 * yn a1 i ∣ 4 * n := mul_dvd_mul_left _ <| dvd_of_ysq_dvd a1 yv
-                have jk : j ≡ k [MOD 4 * yn a1 i] :=
-                  have : 4 * yn a1 i ∣ b - 1 :=
-                    Int.coe_nat_dvd.1 <| by rw [Int.ofNat_sub (le_of_lt b1)] <;> exact bm1.symm.dvd
-                  ((yn_modeq_a_sub_one b1 _).of_dvd this).symm.trans tk
-                have ki : k + i < 4 * yn a1 i :=
-                  lt_of_le_of_lt (add_le_add ky (yn_ge_n a1 i)) <| by
-                    rw [← two_mul] <;>
-                      exact Nat.mul_lt_mul_of_pos_right (by decide) (strict_mono_y a1 ipos)
-                have ji : j ≡ i [MOD 4 * n] :=
-                  have : xn a1 j ≡ xn a1 i [MOD xn a1 n] :=
-                    (xy_modeq_of_modeq b1 a1 ba j).left.symm.trans sx
-                  (modeq_of_xn_modeq a1 ipos iln this).resolve_right
-                    fun ji : j + i ≡ 0 [MOD 4 * n] =>
-                    not_le_of_gt ki <|
-                      Nat.le_of_dvd (lt_of_lt_of_le ipos <| Nat.le_add_left _ _) <|
-                        modeq_zero_iff_dvd.1 <| (jk.symm.add_right i).trans <| ji.of_dvd yd
-                have : i % (4 * yn a1 i) = k % (4 * yn a1 i) := (ji.of_dvd yd).symm.trans jk <;>
-                  rwa [Nat.mod_eq_of_lt (lt_of_le_of_lt (Nat.le_add_left _ _) ki),
-                    Nat.mod_eq_of_lt (lt_of_le_of_lt (Nat.le_add_right _ _) ki)] at this⟩⟩
-#align pell.matiyasevic Pell.matiyasevic
-
-theorem eq_pow_of_pell_lem {a y k} (hy0 : y ≠ 0) (hk0 : k ≠ 0) (hyk : y ^ k < a) :
-    (↑(y ^ k) : ℤ) < 2 * a * y - y * y - 1 :=
-  have hya : y < a := (Nat.le_self_pow hk0 _).trans_lt hyk
-  calc
-    (↑(y ^ k) : ℤ) < a := Nat.cast_lt.2 hyk
-    _ ≤ a ^ 2 - (a - 1) ^ 2 - 1 :=
-      by
-      rw [sub_sq, mul_one, one_pow, sub_add, sub_sub_cancel, two_mul, sub_sub, ← add_sub,
-        le_add_iff_nonneg_right, ← bit0, sub_nonneg, ← Nat.cast_two, Nat.cast_le, Nat.succ_le_iff]
-      exact (one_le_iff_ne_zero.2 hy0).trans_lt hya
-    _ ≤ a ^ 2 - (a - y) ^ 2 - 1 := by
-      have := hya.le
-      mono* <;> simpa only [sub_nonneg, Nat.cast_le, Nat.one_le_cast, Nat.one_le_iff_ne_zero]
-    _ = 2 * a * y - y * y - 1 := by ring
-    
-#align pell.eq_pow_of_pell_lem Pell.eq_pow_of_pell_lem
-
-theorem eq_pow_of_pell {m n k} :
-    n ^ k = m ↔
-      k = 0 ∧ m = 1 ∨
-        0 < k ∧
-          (n = 0 ∧ m = 0 ∨
-            0 < n ∧
-              ∃ (w a t z : ℕ)(a1 : 1 < a),
-                xn a1 k ≡ yn a1 k * (a - n) + m [MOD t] ∧
-                  2 * a * n = t + (n * n + 1) ∧
-                    m < t ∧
-                      n ≤ w ∧ k ≤ w ∧ a * a - ((w + 1) * (w + 1) - 1) * (w * z) * (w * z) = 1) :=
+    rw [← Int.natAbs_dvd, ← ZMod.int_coe_eq_int_coe_iff_dvd_sub]
+    push_cast
+    rw [hq1, hq2]
+  replace hm₀ : (m : ℚ) ≠ 0 := int.cast_ne_zero.mpr hm₀
+  refine' ⟨(q₁.1 * q₂.1 - d * (q₁.2 * q₂.2)) / m, (q₁.1 * q₂.2 - q₂.1 * q₁.2) / m, _, _⟩
+  · qify [hd₁, hd₂]
+    field_simp [hm₀]
+    norm_cast
+    conv_rhs =>
+      congr
+      rw [sq]
+      congr
+      rw [← h₁]
+      skip
+      rw [← h₂]
+    push_cast
+    ring
+  · qify [hd₂]
+    refine' div_ne_zero_iff.mpr ⟨_, hm₀⟩
+    exact_mod_cast mt sub_eq_zero.mp (mt rat.eq_iff_mul_eq_mul.mpr hne)
+#align pell.exists_of_not_is_square Pell.exists_of_not_isSquare
+
+/-- If `d` is a positive integer, then there is a nontrivial solution
+to the Pell equation `x^2 - d*y^2 = 1` if and only if `d` is not a square. -/
+theorem exists_iff_not_isSquare {d : ℤ} (h₀ : 0 < d) :
+    (∃ x y : ℤ, x ^ 2 - d * y ^ 2 = 1 ∧ y ≠ 0) ↔ ¬IsSquare d :=
   by
-  constructor
-  · rintro rfl
-    refine' k.eq_zero_or_pos.imp (fun k0 => k0.symm ▸ ⟨rfl, rfl⟩) fun hk => ⟨hk, _⟩
-    refine' n.eq_zero_or_pos.imp (fun n0 => n0.symm ▸ ⟨rfl, zero_pow hk⟩) fun hn => ⟨hn, _⟩
-    set w := max n k
-    have nw : n ≤ w := le_max_left _ _
-    have kw : k ≤ w := le_max_right _ _
-    have wpos : 0 < w := hn.trans_le nw
-    have w1 : 1 < w + 1 := Nat.succ_lt_succ wpos
-    set a := xn w1 w
-    have a1 : 1 < a := strict_mono_x w1 wpos
-    have na : n ≤ a := nw.trans (n_lt_xn w1 w).le
-    set x := xn a1 k
-    set y := yn a1 k
-    obtain ⟨z, ze⟩ : w ∣ yn w1 w
-    exact modeq_zero_iff_dvd.1 ((yn_modeq_a_sub_one w1 w).trans dvd_rfl.modeq_zero_nat)
-    have nt : (↑(n ^ k) : ℤ) < 2 * a * n - n * n - 1 :=
-      by
-      refine' eq_pow_of_pell_lem hn.ne' hk.ne' _
-      calc
-        n ^ k ≤ n ^ w := Nat.pow_le_pow_of_le_right hn kw
-        _ < (w + 1) ^ w := Nat.pow_lt_pow_of_lt_left (Nat.lt_succ_of_le nw) wpos
-        _ ≤ a := xn_ge_a_pow w1 w
-        
-    lift (2 * a * n - n * n - 1 : ℤ) to ℕ using (Nat.cast_nonneg _).trans nt.le with t te
-    have tm : x ≡ y * (a - n) + n ^ k [MOD t] :=
-      by
-      apply modeq_of_dvd
-      rw [Int.ofNat_add, Int.ofNat_mul, Int.ofNat_sub na, te]
-      exact x_sub_y_dvd_pow a1 n k
-    have ta : 2 * a * n = t + (n * n + 1) :=
-      by
-      rw [← @Nat.cast_inj ℤ, Int.ofNat_add, te, sub_sub]
-      repeat' first |rw [Nat.cast_add]|rw [Nat.cast_mul]
-      rw [Nat.cast_one, sub_add_cancel, Nat.cast_two]
-    have zp : a * a - ((w + 1) * (w + 1) - 1) * (w * z) * (w * z) = 1 := ze ▸ pell_eq w1 w
-    exact ⟨w, a, t, z, a1, tm, ta, Nat.cast_lt.1 nt, nw, kw, zp⟩
-  · rintro (⟨rfl, rfl⟩ | ⟨hk0, ⟨rfl, rfl⟩ | ⟨hn0, w, a, t, z, a1, tm, ta, mt, nw, kw, zp⟩⟩)
-    · exact pow_zero n
-    · exact zero_pow hk0
-    have hw0 : 0 < w := hn0.trans_le nw
-    have hw1 : 1 < w + 1 := Nat.succ_lt_succ hw0
-    rcases eq_pell hw1 zp with ⟨j, rfl, yj⟩
-    have hj0 : 0 < j := by
-      apply Nat.pos_of_ne_zero
-      rintro rfl
-      exact lt_irrefl 1 a1
-    have wj : w ≤ j :=
-      Nat.le_of_dvd hj0
-        (modeq_zero_iff_dvd.1 <|
-          (yn_modeq_a_sub_one hw1 j).symm.trans <| modeq_zero_iff_dvd.2 ⟨z, yj.symm⟩)
-    have hnka : n ^ k < xn hw1 j
-    calc
-      n ^ k ≤ n ^ j := Nat.pow_le_pow_of_le_right hn0 (le_trans kw wj)
-      _ < (w + 1) ^ j := Nat.pow_lt_pow_of_lt_left (Nat.lt_succ_of_le nw) hj0
-      _ ≤ xn hw1 j := xn_ge_a_pow hw1 j
-      
-    have nt : (↑(n ^ k) : ℤ) < 2 * xn hw1 j * n - n * n - 1 :=
-      eq_pow_of_pell_lem hn0.ne' hk0.ne' hnka
-    have na : n ≤ xn hw1 j := (Nat.le_self_pow hk0.ne' _).trans hnka.le
-    have te : (t : ℤ) = 2 * xn hw1 j * n - n * n - 1 :=
-      by
-      rw [sub_sub, eq_sub_iff_add_eq]
-      exact_mod_cast ta.symm
-    have : xn a1 k ≡ yn a1 k * (xn hw1 j - n) + n ^ k [MOD t] :=
-      by
-      apply modeq_of_dvd
-      rw [te, Nat.cast_add, Nat.cast_mul, Int.ofNat_sub na]
-      exact x_sub_y_dvd_pow a1 n k
-    have : n ^ k % t = m % t := (this.symm.trans tm).add_left_cancel' _
-    rw [← te] at nt
-    rwa [Nat.mod_eq_of_lt (Nat.cast_lt.1 nt), Nat.mod_eq_of_lt mt] at this
-#align pell.eq_pow_of_pell Pell.eq_pow_of_pell
+  refine' ⟨_, exists_of_not_is_square h₀⟩
+  rintro ⟨x, y, hxy, hy⟩ ⟨a, rfl⟩
+  rw [← sq, ← mul_pow, sq_sub_sq, Int.mul_eq_one_iff_eq_one_or_neg_one] at hxy
+  replace hxy := hxy.elim (fun h => h.1.trans h.2.symm) fun h => h.1.trans h.2.symm
+  simpa [mul_self_pos.mp h₀, sub_eq_add_neg, eq_neg_self_iff] using hxy
+#align pell.exists_iff_not_is_square Pell.exists_iff_not_isSquare
+
+end Existence
 
 end Pell
 

Changes in mathlib4

mathlib3
mathlib4
chore: make argument to sq_pos_of_ne_zero/sq_pos_iff implicit (#12288)

This matches our general policy and zpow_two_pos_of_ne_zero.

Also define sq_pos_of_ne_zero as an alias.

Diff
@@ -209,8 +209,8 @@ theorem y_neg (a : Solution₁ d) : (-a).y = -a.y :=
 theorem eq_zero_of_d_neg (h₀ : d < 0) (a : Solution₁ d) : a.x = 0 ∨ a.y = 0 := by
   have h := a.prop
   contrapose! h
-  have h1 := sq_pos_of_ne_zero a.x h.1
-  have h2 := sq_pos_of_ne_zero a.y h.2
+  have h1 := sq_pos_of_ne_zero h.1
+  have h2 := sq_pos_of_ne_zero h.2
   nlinarith
 #align pell.solution₁.eq_zero_of_d_neg Pell.Solution₁.eq_zero_of_d_neg
 
@@ -462,7 +462,7 @@ theorem exists_pos_of_not_isSquare (h₀ : 0 < d) (hd : ¬IsSquare d) :
   obtain ⟨x, y, h, hy⟩ := exists_of_not_isSquare h₀ hd
   refine' ⟨mk |x| |y| (by rwa [sq_abs, sq_abs]), _, abs_pos.mpr hy⟩
   rw [x_mk, ← one_lt_sq_iff_one_lt_abs, eq_add_of_sub_eq h, lt_add_iff_pos_right]
-  exact mul_pos h₀ (sq_pos_of_ne_zero y hy)
+  exact mul_pos h₀ (sq_pos_of_ne_zero hy)
 #align pell.solution₁.exists_pos_of_not_is_square Pell.Solution₁.exists_pos_of_not_isSquare
 
 end Solution₁
chore: Rename nat_cast/int_cast/rat_cast to natCast/intCast/ratCast (#11486)

Now that I am defining NNRat.cast, I want a definitive answer to this naming issue. Plenty of lemmas in mathlib already use natCast/intCast/ratCast over nat_cast/int_cast/rat_cast, and this matches with the general expectation that underscore-separated name parts correspond to a single declaration.

Diff
@@ -407,13 +407,13 @@ theorem exists_of_not_isSquare (h₀ : 0 < d) (hd : ¬IsSquare d) :
   obtain ⟨hq1 : (q₁.num : ZMod m.natAbs) = q₂.num, hq2 : (q₁.den : ZMod m.natAbs) = q₂.den⟩ :=
     Prod.ext_iff.mp hqf
   have hd₁ : m ∣ q₁.num * q₂.num - d * (q₁.den * q₂.den) := by
-    rw [← Int.natAbs_dvd, ← ZMod.int_cast_zmod_eq_zero_iff_dvd]
+    rw [← Int.natAbs_dvd, ← ZMod.intCast_zmod_eq_zero_iff_dvd]
     push_cast
     rw [hq1, hq2, ← sq, ← sq]
     norm_cast
-    rw [ZMod.int_cast_zmod_eq_zero_iff_dvd, Int.natAbs_dvd, Nat.cast_pow, ← h₂]
+    rw [ZMod.intCast_zmod_eq_zero_iff_dvd, Int.natAbs_dvd, Nat.cast_pow, ← h₂]
   have hd₂ : m ∣ q₁.num * q₂.den - q₂.num * q₁.den := by
-    rw [← Int.natAbs_dvd, ← ZMod.int_cast_eq_int_cast_iff_dvd_sub]
+    rw [← Int.natAbs_dvd, ← ZMod.intCast_eq_intCast_iff_dvd_sub]
     push_cast
     rw [hq1, hq2]
   replace hm₀ : (m : ℚ) ≠ 0 := Int.cast_ne_zero.mpr hm₀
Feat: add fermatLastTheoremThree_of_three_dvd_only_c (#11767)

We add fermatLastTheoremThree_of_three_dvd_only_c: To prove FermatLastTheoremFor 3, we may assume that ¬ 3 ∣ a, ¬ 3 ∣ b, a and b are coprime and 3 ∣ c.

From the flt3 project in LFTCM2024.

Co-authored-by: Pietro Monticone <38562595+pitmonticone@users.noreply.github.com>

Diff
@@ -396,7 +396,7 @@ theorem exists_of_not_isSquare (h₀ : 0 < d) (hd : ¬IsSquare d) :
     rintro rfl
     obtain ⟨q, hq⟩ := hm.nonempty
     rw [mem_setOf, sub_eq_zero, mul_comm] at hq
-    obtain ⟨a, ha⟩ := (Int.pow_dvd_pow_iff two_pos).mp ⟨d, hq⟩
+    obtain ⟨a, ha⟩ := (Int.pow_dvd_pow_iff two_ne_zero).mp ⟨d, hq⟩
     rw [ha, mul_pow, mul_right_inj' (pow_pos (Int.natCast_pos.mpr q.pos) 2).ne'] at hq
     exact hd ⟨a, sq a ▸ hq.symm⟩
   haveI := neZero_iff.mpr (Int.natAbs_ne_zero.mpr hm₀)
chore: superfluous parentheses part 2 (#12131)

Co-authored-by: Moritz Firsching <firsching@google.com>

Diff
@@ -650,8 +650,8 @@ theorem mul_inv_x_lt_x {a₁ : Solution₁ d} (h : IsFundamental a₁) {a : Solu
     abs_mul, ← sq_lt_sq, mul_pow, a.prop_x]
   calc
     a.y ^ 2 = 1 * a.y ^ 2 := (one_mul _).symm
-    _ ≤ d * a.y ^ 2 := ((mul_le_mul_right <| sq_pos_of_pos hay).mpr h.d_pos)
-    _ < d * a.y ^ 2 + 1 := (lt_add_one _)
+    _ ≤ d * a.y ^ 2 := (mul_le_mul_right <| sq_pos_of_pos hay).mpr h.d_pos
+    _ < d * a.y ^ 2 + 1 := lt_add_one _
     _ = (1 + d * a.y ^ 2) * 1 := by rw [add_comm, mul_one]
     _ ≤ (1 + d * a.y ^ 2) * a₁.y ^ 2 :=
       (mul_le_mul_left (by have := h.d_pos; positivity)).mpr (sq_pos_of_pos h.2.1)
feat: add notation for Real.sqrt (#12056)

This adds the notation √r for Real.sqrt r. The precedence is such that √x⁻¹ is parsed as √(x⁻¹); not because this is particularly desirable, but because it's the default and the choice doesn't really matter.

This is extracted from #7907, which adds a more general nth root typeclass. The idea is to perform all the boring substitutions downstream quickly, so that we can play around with custom elaborators with a much slower rate of code-rot. This PR also won't rot as quickly, as it does not forbid writing x.sqrt as that PR does.

While perhaps claiming for Real.sqrt is greedy; it:

  • Is far more common thatn NNReal.sqrt and Nat.sqrt
  • Is far more interesting to mathlib than sqrt on Float
  • Can be overloaded anyway, so this does not prevent downstream code using the notation on their own types.
  • Will be replaced by a more general typeclass in a future PR.

Zulip

Co-authored-by: Yury G. Kudryashov <urkud@urkud.name>

Diff
@@ -366,7 +366,7 @@ open Set Real
 to the Pell equation `x^2 - d*y^2 = 1`. -/
 theorem exists_of_not_isSquare (h₀ : 0 < d) (hd : ¬IsSquare d) :
     ∃ x y : ℤ, x ^ 2 - d * y ^ 2 = 1 ∧ y ≠ 0 := by
-  let ξ : ℝ := sqrt d
+  let ξ : ℝ := √d
   have hξ : Irrational ξ := by
     refine' irrational_nrt_of_notint_nrt 2 d (sq_sqrt <| Int.cast_nonneg.mpr h₀.le) _ two_pos
     rintro ⟨x, hx⟩
chore: Rename coe_nat/coe_int/coe_rat to natCast/intCast/ratCast (#11499)

This is less exhaustive than its sibling #11486 because edge cases are harder to classify. No fundamental difficulty, just me being a bit fast and lazy.

Reduce the diff of #11203

Diff
@@ -397,7 +397,7 @@ theorem exists_of_not_isSquare (h₀ : 0 < d) (hd : ¬IsSquare d) :
     obtain ⟨q, hq⟩ := hm.nonempty
     rw [mem_setOf, sub_eq_zero, mul_comm] at hq
     obtain ⟨a, ha⟩ := (Int.pow_dvd_pow_iff two_pos).mp ⟨d, hq⟩
-    rw [ha, mul_pow, mul_right_inj' (pow_pos (Int.coe_nat_pos.mpr q.pos) 2).ne'] at hq
+    rw [ha, mul_pow, mul_right_inj' (pow_pos (Int.natCast_pos.mpr q.pos) 2).ne'] at hq
     exact hd ⟨a, sq a ▸ hq.symm⟩
   haveI := neZero_iff.mpr (Int.natAbs_ne_zero.mpr hm₀)
   let f : ℚ → ZMod m.natAbs × ZMod m.natAbs := fun q => (q.num, q.den)
change the order of operation in zsmulRec and nsmulRec (#11451)

We change the following field in the definition of an additive commutative monoid:

 nsmul_succ : ∀ (n : ℕ) (x : G),
-  AddMonoid.nsmul (n + 1) x = x + AddMonoid.nsmul n x
+  AddMonoid.nsmul (n + 1) x = AddMonoid.nsmul n x + x

where the latter is more natural

We adjust the definitions of ^ in monoids, groups, etc. Originally there was a warning comment about why this natural order was preferred

use x * npowRec n x and not npowRec n x * x in the definition to make sure that definitional unfolding of npowRec is blocked, to avoid deep recursion issues.

but it seems to no longer apply.

Remarks on the PR :

  • pow_succ and pow_succ' have switched their meanings.
  • Most of the time, the proofs were adjusted by priming/unpriming one lemma, or exchanging left and right; a few proofs were more complicated to adjust.
  • In particular, [Mathlib/NumberTheory/RamificationInertia.lean] used Ideal.IsPrime.mul_mem_pow which is defined in [Mathlib/RingTheory/DedekindDomain/Ideal.lean]. Changing the order of operation forced me to add the symmetric lemma Ideal.IsPrime.mem_pow_mul.
  • the docstring for Cauchy condensation test in [Mathlib/Analysis/PSeries.lean] was mathematically incorrect, I added the mention that the function is antitone.
Diff
@@ -290,7 +290,7 @@ theorem x_pow_pos {a : Solution₁ d} (hax : 0 < a.x) (n : ℕ) : 0 < (a ^ n).x
   induction' n with n ih
   · simp only [Nat.zero_eq, pow_zero, x_one, zero_lt_one]
   · rw [pow_succ]
-    exact x_mul_pos hax ih
+    exact x_mul_pos ih hax
 #align pell.solution₁.x_pow_pos Pell.Solution₁.x_pow_pos
 
 /-- If `(x, y)` is a solution with `x` and `y` positive, then all its powers with positive
@@ -299,7 +299,7 @@ theorem y_pow_succ_pos {a : Solution₁ d} (hax : 0 < a.x) (hay : 0 < a.y) (n :
     0 < (a ^ n.succ).y := by
   induction' n with n ih
   · simp only [Nat.zero_eq, ← Nat.one_eq_succ_zero, hay, pow_one]
-  · rw [pow_succ]
+  · rw [pow_succ']
     exact y_mul_pos hax hay (x_pow_pos hax _) ih
 #align pell.solution₁.y_pow_succ_pos Pell.Solution₁.y_pow_succ_pos
 
@@ -684,7 +684,7 @@ theorem eq_pow_of_nonneg {a₁ : Solution₁ d} (h : IsFundamental a₁) {a : So
     lift (a * a₁⁻¹).x to ℕ using hxx₁.le with x' hx'
     -- Porting note: `ih` has its arguments in a different order compared to lean 3.
     obtain ⟨n, hn⟩ := ih x' (mod_cast hxx₂.trans_eq hax'.symm) hyy hx' hxx₁
-    exact ⟨n + 1, by rw [pow_succ, ← hn, mul_comm a, ← mul_assoc, mul_inv_self, one_mul]⟩
+    exact ⟨n + 1, by rw [pow_succ', ← hn, mul_comm a, ← mul_assoc, mul_inv_self, one_mul]⟩
 #align pell.is_fundamental.eq_pow_of_nonneg Pell.IsFundamental.eq_pow_of_nonneg
 
 /-- Every solution is, up to a sign, a power of a given fundamental solution. -/
chore: Rename mul-div cancellation lemmas (#11530)

Lemma names around cancellation of multiplication and division are a mess.

This PR renames a handful of them according to the following table (each big row contains the multiplicative statement, then the three rows contain the GroupWithZero lemma name, the Group lemma, the AddGroup lemma name).

| Statement | New name | Old name | |

Diff
@@ -379,7 +379,7 @@ theorem exists_of_not_isSquare (h₀ : 0 < d) (hd : ¬IsSquare d) :
     have h1 : (q.num : ℝ) / (q.den : ℝ) = q := mod_cast q.num_div_den
     rw [mem_setOf, abs_sub_comm, ← @Int.cast_lt ℝ, ← div_lt_div_right (abs_pos_of_pos h0)]
     push_cast
-    rw [← abs_div, abs_sq, sub_div, mul_div_cancel _ h0.ne', ← div_pow, h1, ←
+    rw [← abs_div, abs_sq, sub_div, mul_div_cancel_right₀ _ h0.ne', ← div_pow, h1, ←
       sq_sqrt (Int.cast_pos.mpr h₀).le, sq_sub_sq, abs_mul, ← mul_one_div]
     refine' mul_lt_mul'' (((abs_add ξ q).trans _).trans_lt hM₁) h (abs_nonneg _) (abs_nonneg _)
     rw [two_mul, add_assoc, add_le_add_iff_left, ← sub_le_iff_le_add']
chore: Rename zpow_coe_nat to zpow_natCast (#11528)

... and add a deprecated alias for the old name. This is mostly just me discovering the power of F2

Diff
@@ -317,7 +317,7 @@ theorem y_zpow_pos {a : Solution₁ d} (hax : 0 < a.x) (hay : 0 < a.y) {n : ℤ}
 theorem x_zpow_pos {a : Solution₁ d} (hax : 0 < a.x) (n : ℤ) : 0 < (a ^ n).x := by
   cases n with
   | ofNat n =>
-    rw [Int.ofNat_eq_coe, zpow_coe_nat]
+    rw [Int.ofNat_eq_coe, zpow_natCast]
     exact x_pow_pos hax n
   | negSucc n =>
     rw [zpow_negSucc]
@@ -330,7 +330,7 @@ theorem sign_y_zpow_eq_sign_of_x_pos_of_y_pos {a : Solution₁ d} (hax : 0 < a.x
     (n : ℤ) : (a ^ n).y.sign = n.sign := by
   rcases n with ((_ | n) | n)
   · rfl
-  · rw [Int.ofNat_eq_coe, zpow_coe_nat]
+  · rw [Int.ofNat_eq_coe, zpow_natCast]
     exact Int.sign_eq_one_of_pos (y_pow_succ_pos hax hay n)
   · rw [zpow_negSucc]
     exact Int.sign_eq_neg_one_of_neg (neg_neg_of_pos (y_pow_succ_pos hax hay n))
refactor: optimize proofs with omega (#11093)

I ran tryAtEachStep on all files under Mathlib to find all locations where omega succeeds. For each that was a linarith without an only, I tried replacing it with omega, and I verified that elaboration time got smaller. (In almost all cases, there was a noticeable speedup.) I also replaced some slow aesops along the way.

Diff
@@ -242,7 +242,7 @@ theorem d_nonsquare_of_one_lt_x {a : Solution₁ d} (ha : 1 < a.x) : ¬IsSquare
   have hp := a.prop
   rintro ⟨b, rfl⟩
   simp_rw [← sq, ← mul_pow, sq_sub_sq, Int.mul_eq_one_iff_eq_one_or_neg_one] at hp
-  rcases hp with (⟨hp₁, hp₂⟩ | ⟨hp₁, hp₂⟩) <;> linarith [ha, hp₁, hp₂]
+  rcases hp with (⟨hp₁, hp₂⟩ | ⟨hp₁, hp₂⟩) <;> omega
 #align pell.solution₁.d_nonsquare_of_one_lt_x Pell.Solution₁.d_nonsquare_of_one_lt_x
 
 /-- A solution with `x = 1` is trivial. -/
@@ -557,7 +557,7 @@ theorem y_strictMono {a : Solution₁ d} (h : IsFundamental a) :
   · let m : ℤ := -n - 1
     have hm : n = -m - 1 := by simp only [m, neg_sub, sub_neg_eq_add, add_tsub_cancel_left]
     rw [hm, sub_add_cancel, ← neg_add', zpow_neg, zpow_neg, y_inv, y_inv, neg_lt_neg_iff]
-    exact H _ (by linarith [hn])
+    exact H _ (by omega)
 #align pell.is_fundamental.y_strict_mono Pell.IsFundamental.y_strictMono
 
 /-- If `a` is a fundamental solution, then `(a^m).y < (a^n).y` if and only if `m < n`. -/
fix: correct statement of zpow_ofNat and ofNat_zsmul (#10969)

Previously these were syntactically identical to the corresponding zpow_coe_nat and coe_nat_zsmul lemmas, now they are about OfNat.ofNat.

Unfortunately, almost every call site uses the ofNat name to refer to Nat.cast, so the downstream proofs had to be adjusted too.

Diff
@@ -317,7 +317,7 @@ theorem y_zpow_pos {a : Solution₁ d} (hax : 0 < a.x) (hay : 0 < a.y) {n : ℤ}
 theorem x_zpow_pos {a : Solution₁ d} (hax : 0 < a.x) (n : ℤ) : 0 < (a ^ n).x := by
   cases n with
   | ofNat n =>
-    rw [Int.ofNat_eq_coe, zpow_ofNat]
+    rw [Int.ofNat_eq_coe, zpow_coe_nat]
     exact x_pow_pos hax n
   | negSucc n =>
     rw [zpow_negSucc]
@@ -330,7 +330,7 @@ theorem sign_y_zpow_eq_sign_of_x_pos_of_y_pos {a : Solution₁ d} (hax : 0 < a.x
     (n : ℤ) : (a ^ n).y.sign = n.sign := by
   rcases n with ((_ | n) | n)
   · rfl
-  · rw [Int.ofNat_eq_coe, zpow_ofNat]
+  · rw [Int.ofNat_eq_coe, zpow_coe_nat]
     exact Int.sign_eq_one_of_pos (y_pow_succ_pos hax hay n)
   · rw [zpow_negSucc]
     exact Int.sign_eq_neg_one_of_neg (neg_neg_of_pos (y_pow_succ_pos hax hay n))
chore: more backporting of simp changes from #10995 (#11001)

Co-authored-by: Patrick Massot <patrickmassot@free.fr> Co-authored-by: Scott Morrison <scott.morrison@gmail.com>

Diff
@@ -555,7 +555,7 @@ theorem y_strictMono {a : Solution₁ d} (h : IsFundamental a) :
   rcases le_or_lt 0 n with hn | hn
   · exact H n hn
   · let m : ℤ := -n - 1
-    have hm : n = -m - 1 := by simp only [neg_sub, sub_neg_eq_add, add_tsub_cancel_left]
+    have hm : n = -m - 1 := by simp only [m, neg_sub, sub_neg_eq_add, add_tsub_cancel_left]
     rw [hm, sub_add_cancel, ← neg_add', zpow_neg, zpow_neg, y_inv, y_inv, neg_lt_neg_iff]
     exact H _ (by linarith [hn])
 #align pell.is_fundamental.y_strict_mono Pell.IsFundamental.y_strictMono
feat: The support of f ^ n (#9617)

This involves moving lemmas from Algebra.GroupPower.Ring to Algebra.GroupWithZero.Basic and changing some 0 < n assumptions to n ≠ 0.

From LeanAPAP

Diff
@@ -271,7 +271,7 @@ theorem x_mul_pos {a b : Solution₁ d} (ha : 0 < a.x) (hb : 0 < b.x) : 0 < (a *
   · positivity
   · rw [(eq_zero_of_d_neg h a).resolve_left ha.ne', (eq_zero_of_d_neg h b).resolve_left hb.ne']
     -- Porting note: was
-    -- rw [zero_pow two_pos, zero_add, zero_mul, zero_add]
+    -- rw [zero_pow two_ne_zero, zero_add, zero_mul, zero_add]
     -- exact one_pos
     -- but this relied on the exact output of `ring_nf`
     simp
chore(NumberTheory/Zsqrtd): use @[ext] (#9299)

Added @[ext] to definition structure Zsqrtd (d : ℤ). (also added lemma sub_re, sub_im)

Diff
@@ -140,7 +140,7 @@ theorem prop_y (a : Solution₁ d) : d * a.y ^ 2 = a.x ^ 2 - 1 := by rw [← a.p
 /-- Two solutions are equal if their `x` and `y` components are equal. -/
 @[ext]
 theorem ext {a b : Solution₁ d} (hx : a.x = b.x) (hy : a.y = b.y) : a = b :=
-  Subtype.ext <| ext.mpr ⟨hx, hy⟩
+  Subtype.ext <| Zsqrtd.ext _ _ hx hy
 #align pell.solution₁.ext Pell.Solution₁.ext
 
 /-- Construct a solution from `x`, `y` and a proof that the equation is satisfied. -/
@@ -161,7 +161,7 @@ theorem y_mk (x y : ℤ) (prop : x ^ 2 - d * y ^ 2 = 1) : (mk x y prop).y = y :=
 
 @[simp]
 theorem coe_mk (x y : ℤ) (prop : x ^ 2 - d * y ^ 2 = 1) : (↑(mk x y prop) : ℤ√d) = ⟨x, y⟩ :=
-  Zsqrtd.ext.mpr ⟨x_mk x y prop, y_mk x y prop⟩
+  Zsqrtd.ext _ _ (x_mk x y prop) (y_mk x y prop)
 #align pell.solution₁.coe_mk Pell.Solution₁.coe_mk
 
 @[simp]
chore: remove uses of cases' (#9171)

I literally went through and regex'd some uses of cases', replacing them with rcases; this is meant to be a low effort PR as I hope that tools can do this in the future.

rcases is an easier replacement than cases, though with better tools we could in future do a second pass converting simple rcases added here (and existing ones) to cases.

Diff
@@ -267,7 +267,7 @@ theorem x_mul_pos {a b : Solution₁ d} (ha : 0 < a.x) (hb : 0 < b.x) : 0 < (a *
   rw [← abs_of_pos ha, ← abs_of_pos hb, ← abs_mul, ← sq_lt_sq, mul_pow a.x, a.prop_x, b.prop_x, ←
     sub_pos]
   ring_nf
-  cases' le_or_lt 0 d with h h
+  rcases le_or_lt 0 d with h | h
   · positivity
   · rw [(eq_zero_of_d_neg h a).resolve_left ha.ne', (eq_zero_of_d_neg h b).resolve_left hb.ne']
     -- Porting note: was
@@ -552,7 +552,7 @@ theorem y_strictMono {a : Solution₁ d} (h : IsFundamental a) :
     · simp only [zpow_zero, y_one, le_refl]
     · exact (y_zpow_pos h.x_pos h.2.1 hn).le
   refine' strictMono_int_of_lt_succ fun n => _
-  cases' le_or_lt 0 n with hn hn
+  rcases le_or_lt 0 n with hn | hn
   · exact H n hn
   · let m : ℤ := -n - 1
     have hm : n = -m - 1 := by simp only [neg_sub, sub_neg_eq_add, add_tsub_cancel_left]
@@ -664,7 +664,7 @@ theorem eq_pow_of_nonneg {a₁ : Solution₁ d} (h : IsFundamental a₁) {a : So
   -- Porting note: added
   clear hax
   induction' ax using Nat.strong_induction_on with x ih generalizing a
-  cases' hay.eq_or_lt with hy hy
+  rcases hay.eq_or_lt with hy | hy
   · -- case 1: `a = 1`
     refine' ⟨0, _⟩
     simp only [pow_zero]
chore: remove now-unneeded line that worked around linarith preprocessing bug (#9009)

After #8310, the workaround in eq_zero_of_d_neg is no longer needed. I observed (via trace.profiler) no performance difference with this change.

Diff
@@ -211,8 +211,6 @@ theorem eq_zero_of_d_neg (h₀ : d < 0) (a : Solution₁ d) : a.x = 0 ∨ a.y =
   contrapose! h
   have h1 := sq_pos_of_ne_zero a.x h.1
   have h2 := sq_pos_of_ne_zero a.y h.2
-  -- Porting note: added this to help `nlinarith`
-  obtain ⟨d', rfl⟩ : ∃ d', d = -d' := ⟨-d, by exact Iff.mp neg_eq_iff_eq_neg rfl⟩
   nlinarith
 #align pell.solution₁.eq_zero_of_d_neg Pell.Solution₁.eq_zero_of_d_neg
 
chore: replace exact_mod_cast tactic with mod_cast elaborator where possible (#8404)

We still have the exact_mod_cast tactic, used in a few places, which somehow (?) works a little bit harder to prevent the expected type influencing the elaboration of the term. I would like to get to the bottom of this, and it will be easier once the only usages of exact_mod_cast are the ones that don't work using the term elaborator by itself.

Co-authored-by: Scott Morrison <scott.morrison@gmail.com>

Diff
@@ -378,7 +378,7 @@ theorem exists_of_not_isSquare (h₀ : 0 < d) (hd : ¬IsSquare d) :
   have hM : {q : ℚ | |q.1 ^ 2 - d * (q.2 : ℤ) ^ 2| < M}.Infinite := by
     refine' Infinite.mono (fun q h => _) (infinite_rat_abs_sub_lt_one_div_den_sq_of_irrational hξ)
     have h0 : 0 < (q.2 : ℝ) ^ 2 := pow_pos (Nat.cast_pos.mpr q.pos) 2
-    have h1 : (q.num : ℝ) / (q.den : ℝ) = q := by exact_mod_cast q.num_div_den
+    have h1 : (q.num : ℝ) / (q.den : ℝ) = q := mod_cast q.num_div_den
     rw [mem_setOf, abs_sub_comm, ← @Int.cast_lt ℝ, ← div_lt_div_right (abs_pos_of_pos h0)]
     push_cast
     rw [← abs_div, abs_sq, sub_div, mul_div_cancel _ h0.ne', ← div_pow, h1, ←
@@ -433,7 +433,7 @@ theorem exists_of_not_isSquare (h₀ : 0 < d) (hd : ¬IsSquare d) :
     ring
   · qify [hd₂]
     refine' div_ne_zero_iff.mpr ⟨_, hm₀⟩
-    exact_mod_cast mt sub_eq_zero.mp (mt Rat.eq_iff_mul_eq_mul.mpr hne)
+    exact mod_cast mt sub_eq_zero.mp (mt Rat.eq_iff_mul_eq_mul.mpr hne)
 #align pell.exists_of_not_is_square Pell.exists_of_not_isSquare
 
 /-- If `d` is a positive integer, then there is a nontrivial solution
@@ -528,7 +528,7 @@ theorem exists_of_not_isSquare (h₀ : 0 < d) (hd : ¬IsSquare d) :
   -- to avoid having to show that the predicate is decidable
   let x₁ := Nat.find P
   obtain ⟨hx, y₁, hy₀, hy₁⟩ := Nat.find_spec P
-  refine' ⟨mk x₁ y₁ hy₁, by rw [x_mk]; exact_mod_cast hx, hy₀, fun {b} hb => _⟩
+  refine' ⟨mk x₁ y₁ hy₁, by rw [x_mk]; exact mod_cast hx, hy₀, fun {b} hb => _⟩
   rw [x_mk]
   have hb' := (Int.toNat_of_nonneg <| zero_le_one.trans hb.le).symm
   have hb'' := hb
@@ -685,7 +685,7 @@ theorem eq_pow_of_nonneg {a₁ : Solution₁ d} (h : IsFundamental a₁) {a : So
     have hyy := h.mul_inv_y_nonneg hx₁ hy
     lift (a * a₁⁻¹).x to ℕ using hxx₁.le with x' hx'
     -- Porting note: `ih` has its arguments in a different order compared to lean 3.
-    obtain ⟨n, hn⟩ := ih x' (by exact_mod_cast hxx₂.trans_eq hax'.symm) hyy hx' hxx₁
+    obtain ⟨n, hn⟩ := ih x' (mod_cast hxx₂.trans_eq hax'.symm) hyy hx' hxx₁
     exact ⟨n + 1, by rw [pow_succ, ← hn, mul_comm a, ← mul_assoc, mul_inv_self, one_mul]⟩
 #align pell.is_fundamental.eq_pow_of_nonneg Pell.IsFundamental.eq_pow_of_nonneg
 
@@ -695,7 +695,7 @@ theorem eq_zpow_or_neg_zpow {a₁ : Solution₁ d} (h : IsFundamental a₁) (a :
   obtain ⟨b, hbx, hby, hb⟩ := exists_pos_variant h.d_pos a
   obtain ⟨n, hn⟩ := h.eq_pow_of_nonneg hbx hby
   rcases hb with (rfl | rfl | rfl | hb)
-  · exact ⟨n, Or.inl (by exact_mod_cast hn)⟩
+  · exact ⟨n, Or.inl (mod_cast hn)⟩
   · exact ⟨-n, Or.inl (by simp [hn])⟩
   · exact ⟨n, Or.inr (by simp [hn])⟩
   · rw [Set.mem_singleton_iff] at hb
chore: bump to v4.3.0-rc2 (#8366)

PR contents

This is the supremum of

along with some minor fixes from failures on nightly-testing as Mathlib master is merged into it.

Note that some PRs for changes that are already compatible with the current toolchain and will be necessary have already been split out: #8380.

I am hopeful that in future we will be able to progressively merge adaptation PRs into a bump/v4.X.0 branch, so we never end up with a "big merge" like this. However one of these adaptation PRs (#8056) predates my new scheme for combined CI, and it wasn't possible to keep that PR viable in the meantime.

Lean PRs involved in this bump

In particular this includes adjustments for the Lean PRs

leanprover/lean4#2778

We can get rid of all the

local macro_rules | `($x ^ $y) => `(HPow.hPow $x $y) -- Porting note: See issue [lean4#2220](https://github.com/leanprover/lean4/pull/2220)

macros across Mathlib (and in any projects that want to write natural number powers of reals).

leanprover/lean4#2722

Changes the default behaviour of simp to (config := {decide := false}). This makes simp (and consequentially norm_num) less powerful, but also more consistent, and less likely to blow up in long failures. This requires a variety of changes: changing some previously by simp or norm_num to decide or rfl, or adding (config := {decide := true}).

leanprover/lean4#2783

This changed the behaviour of simp so that simp [f] will only unfold "fully applied" occurrences of f. The old behaviour can be recovered with simp (config := { unfoldPartialApp := true }). We may in future add a syntax for this, e.g. simp [!f]; please provide feedback! In the meantime, we have made the following changes:

  • switching to using explicit lemmas that have the intended level of application
  • (config := { unfoldPartialApp := true }) in some places, to recover the old behaviour
  • Using @[eqns] to manually adjust the equation lemmas for a particular definition, recovering the old behaviour just for that definition. See #8371, where we do this for Function.comp and Function.flip.

This change in Lean may require further changes down the line (e.g. adding the !f syntax, and/or upstreaming the special treatment for Function.comp and Function.flip, and/or removing this special treatment). Please keep an open and skeptical mind about these changes!

Co-authored-by: leanprover-community-mathlib4-bot <leanprover-community-mathlib4-bot@users.noreply.github.com> Co-authored-by: Scott Morrison <scott.morrison@gmail.com> Co-authored-by: Eric Wieser <wieser.eric@gmail.com> Co-authored-by: Mauricio Collares <mauricio@collares.org>

Diff
@@ -551,7 +551,7 @@ theorem y_strictMono {a : Solution₁ d} (h : IsFundamental a) :
       add_pos_of_pos_of_nonneg (mul_pos (x_zpow_pos h.x_pos _) h.2.1)
         (mul_nonneg _ (by rw [sub_nonneg]; exact h.1.le))
     rcases hn.eq_or_lt with (rfl | hn)
-    · simp only [zpow_zero, y_one]
+    · simp only [zpow_zero, y_one, le_refl]
     · exact (y_zpow_pos h.x_pos h.2.1 hn).le
   refine' strictMono_int_of_lt_succ fun n => _
   cases' le_or_lt 0 n with hn hn
chore: drop MulZeroClass. in mul_zero/zero_mul (#6682)

Search&replace MulZeroClass.mul_zero -> mul_zero, MulZeroClass.zero_mul -> zero_mul.

These were introduced by Mathport, as the full name of mul_zero is actually MulZeroClass.mul_zero (it's exported with the short name).

Diff
@@ -220,7 +220,7 @@ theorem eq_zero_of_d_neg (h₀ : d < 0) (a : Solution₁ d) : a.x = 0 ∨ a.y =
 theorem x_ne_zero (h₀ : 0 ≤ d) (a : Solution₁ d) : a.x ≠ 0 := by
   intro hx
   have h : 0 ≤ d * a.y ^ 2 := mul_nonneg h₀ (sq_nonneg _)
-  rw [a.prop_y, hx, sq, MulZeroClass.zero_mul, zero_sub] at h
+  rw [a.prop_y, hx, sq, zero_mul, zero_sub] at h
   exact not_le.mpr (neg_one_lt_zero : (-1 : ℤ) < 0) h
 #align pell.solution₁.x_ne_zero Pell.Solution₁.x_ne_zero
 
@@ -228,7 +228,7 @@ theorem x_ne_zero (h₀ : 0 ≤ d) (a : Solution₁ d) : a.x ≠ 0 := by
 theorem y_ne_zero_of_one_lt_x {a : Solution₁ d} (ha : 1 < a.x) : a.y ≠ 0 := by
   intro hy
   have prop := a.prop
-  rw [hy, sq (0 : ℤ), MulZeroClass.zero_mul, MulZeroClass.mul_zero, sub_zero] at prop
+  rw [hy, sq (0 : ℤ), zero_mul, mul_zero, sub_zero] at prop
   exact lt_irrefl _ (((one_lt_sq_iff <| zero_le_one.trans ha.le).mpr ha).trans_eq prop)
 #align pell.solution₁.y_ne_zero_of_one_lt_x Pell.Solution₁.y_ne_zero_of_one_lt_x
 
@@ -258,7 +258,7 @@ theorem eq_one_of_x_eq_one (h₀ : d ≠ 0) {a : Solution₁ d} (ha : a.x = 1) :
 theorem eq_one_or_neg_one_iff_y_eq_zero {a : Solution₁ d} : a = 1 ∨ a = -1 ↔ a.y = 0 := by
   refine' ⟨fun H => H.elim (fun h => by simp [h]) fun h => by simp [h], fun H => _⟩
   have prop := a.prop
-  rw [H, sq (0 : ℤ), MulZeroClass.mul_zero, MulZeroClass.mul_zero, sub_zero, sq_eq_one_iff] at prop
+  rw [H, sq (0 : ℤ), mul_zero, mul_zero, sub_zero, sq_eq_one_iff] at prop
   exact prop.imp (fun h => ext h H) fun h => ext h H
 #align pell.solution₁.eq_one_or_neg_one_iff_y_eq_zero Pell.Solution₁.eq_one_or_neg_one_iff_y_eq_zero
 
@@ -273,7 +273,7 @@ theorem x_mul_pos {a b : Solution₁ d} (ha : 0 < a.x) (hb : 0 < b.x) : 0 < (a *
   · positivity
   · rw [(eq_zero_of_d_neg h a).resolve_left ha.ne', (eq_zero_of_d_neg h b).resolve_left hb.ne']
     -- Porting note: was
-    -- rw [zero_pow two_pos, zero_add, MulZeroClass.zero_mul, zero_add]
+    -- rw [zero_pow two_pos, zero_add, zero_mul, zero_add]
     -- exact one_pos
     -- but this relied on the exact output of `ring_nf`
     simp
@@ -672,7 +672,7 @@ theorem eq_pow_of_nonneg {a₁ : Solution₁ d} (h : IsFundamental a₁) {a : So
     simp only [pow_zero]
     ext <;> simp only [x_one, y_one]
     · have prop := a.prop
-      rw [← hy, sq (0 : ℤ), MulZeroClass.zero_mul, MulZeroClass.mul_zero, sub_zero,
+      rw [← hy, sq (0 : ℤ), zero_mul, mul_zero, sub_zero,
         sq_eq_one_iff] at prop
       refine' prop.resolve_right fun hf => _
       have := (hax.trans_eq hax').le.trans_eq hf
chore: script to replace headers with #align_import statements (#5979)

Open in Gitpod

Co-authored-by: Eric Wieser <wieser.eric@gmail.com> Co-authored-by: Scott Morrison <scott.morrison@gmail.com>

Diff
@@ -2,17 +2,14 @@
 Copyright (c) 2023 Michael Stoll. All rights reserved.
 Released under Apache 2.0 license as described in the file LICENSE.
 Authors: Michael Geißer, Michael Stoll
-
-! This file was ported from Lean 3 source module number_theory.pell
-! leanprover-community/mathlib commit 7ad820c4997738e2f542f8a20f32911f52020e26
-! Please do not edit these lines, except to modify the commit id
-! if you have ported upstream changes.
 -/
 import Mathlib.Tactic.Qify
 import Mathlib.Data.ZMod.Basic
 import Mathlib.NumberTheory.DiophantineApproximation
 import Mathlib.NumberTheory.Zsqrtd.Basic
 
+#align_import number_theory.pell from "leanprover-community/mathlib"@"7ad820c4997738e2f542f8a20f32911f52020e26"
+
 /-!
 # Pell's Equation
 
chore: cleanup whitespace (#5988)

Grepping for [^ .:{-] [^ :] and reviewing the results. Once I started I couldn't stop. :-)

Co-authored-by: Scott Morrison <scott.morrison@gmail.com>

Diff
@@ -456,7 +456,7 @@ to the Pell equation `x^2 - d*y^2 = 1`. -/
 theorem exists_nontrivial_of_not_isSquare (h₀ : 0 < d) (hd : ¬IsSquare d) :
     ∃ a : Solution₁ d, a ≠ 1 ∧ a ≠ -1 := by
   obtain ⟨x, y, prop, hy⟩ := exists_of_not_isSquare h₀ hd
-  refine' ⟨mk x y prop, fun H => _, fun H => _⟩ <;> apply_fun Solution₁.y at H  <;>
+  refine' ⟨mk x y prop, fun H => _, fun H => _⟩ <;> apply_fun Solution₁.y at H <;>
     simp [hy] at H
 #align pell.solution₁.exists_nontrivial_of_not_is_square Pell.Solution₁.exists_nontrivial_of_not_isSquare
 
fix: filenames with typos in doc (#5836)
Diff
@@ -20,7 +20,7 @@ import Mathlib.NumberTheory.Zsqrtd.Basic
 that is not a square, and one is interested in solutions in integers $x$ and $y$.
 
 In this file, we aim at providing all of the essential theory of Pell's Equation for general $d$
-(as opposed to the contents of `number_theory.pell_matiyasevic`, which is specific to the case
+(as opposed to the contents of `NumberTheory.PellMatiyasevic`, which is specific to the case
 $d = a^2 - 1$ for some $a > 1$).
 
 We begin by defining a type `Pell.Solution₁ d` for solutions of the equation,
fix: precedence of , and abs (#5619)
Diff
@@ -465,7 +465,7 @@ to the Pell equation `x^2 - d*y^2 = 1` with `x > 1` and `y > 0`. -/
 theorem exists_pos_of_not_isSquare (h₀ : 0 < d) (hd : ¬IsSquare d) :
     ∃ a : Solution₁ d, 1 < a.x ∧ 0 < a.y := by
   obtain ⟨x, y, h, hy⟩ := exists_of_not_isSquare h₀ hd
-  refine' ⟨mk (|x|) (|y|) (by rwa [sq_abs, sq_abs]), _, abs_pos.mpr hy⟩
+  refine' ⟨mk |x| |y| (by rwa [sq_abs, sq_abs]), _, abs_pos.mpr hy⟩
   rw [x_mk, ← one_lt_sq_iff_one_lt_abs, eq_add_of_sub_eq h, lt_add_iff_pos_right]
   exact mul_pos h₀ (sq_pos_of_ne_zero y hy)
 #align pell.solution₁.exists_pos_of_not_is_square Pell.Solution₁.exists_pos_of_not_isSquare
feat: port NumberTheory.Pell (#5137)

Dependencies 13 + 771

772 files ported (98.3%)
335058 lines ported (98.3%)
Show graph

The unported dependencies are

The following 1 dependencies have changed in mathlib3 since they were ported, which may complicate porting this file