l3lab/ntp-mathlib huggingface dataset:
theorem hasseDeriv_mul (f g : R[X]) :
    hasseDeriv k (f * g) = ∑ ij in antidiagonal k, hasseDeriv ij.1 f * hasseDeriv ij.2 g := by
  let D k := (@hasseDeriv R _ k).toAddMonoidHom
  let Φ := @AddMonoidHom.mul R[X] _
  show
    (compHom (D k)).comp Φ f g =
      ∑ ij : ℕ × ℕ in antidiagonal k, ((compHom.comp ((compHom Φ) (D ij.1))).flip (D ij.2) f) g
  simp only [← finset_sum_apply]
  congr 2
  clear f g
  ext m r n s : 4
  simp only [finset_sum_apply, coe_mulLeft, coe_comp, flip_apply, Function.comp_apply,
             hasseDeriv_monomial, LinearMap.toAddMonoidHom_coe, compHom_apply_apply,
             coe_mul, monomial_mul_monomial]
  have aux :
    ∀ x : ℕ × ℕ,
      x ∈ antidiagonal k →
        monomial (m - x.1 + (n - x.2)) (↑(m.choose x.1) * r * (↑(n.choose x.2) * s)) =
          monomial (m + n - k) (↑(m.choose x.1) * ↑(n.choose x.2) * (r * s)) := by
    intro x hx
    rw [mem_antidiagonal] at hx
    subst hx
    by_cases hm : m < x.1
    · simp only [Nat.choose_eq_zero_of_lt hm, Nat.cast_zero, zero_mul,
                 monomial_zero_right]
    by_cases hn : n < x.2
    · simp only [Nat.choose_eq_zero_of_lt hn, Nat.cast_zero, zero_mul,
                 mul_zero, monomial_zero_right]
    push_neg at hm hn
    rw [tsub_add_eq_add_tsub hm, ← add_tsub_assoc_of_le hn, ← tsub_add_eq_tsub_tsub,
      add_comm x.2 x.1, mul_assoc, ← mul_assoc r, ← (Nat.cast_commute _ r).eq, mul_assoc, mul_assoc]
  rw [Finset.sum_congr rfl aux]
  rw [← map_sum, ← Finset.sum_mul]
  congr
  

Proof state:
case e_a.e_a.h.h.h.h.h.e_6.h.e_a
R : Type u_1
inst✝ : Semiring R
k : ℕ
f : R[X]
D : ℕ → R[X] →+ R[X] := fun k => LinearMap.toAddMonoidHom (hasseDeriv k)
Φ : R[X] →+ R[X] →+ R[X] := mul
m : ℕ
r : R
n : ℕ
s : R
aux :
  ∀ x ∈ antidiagonal k,
    (monomial (m - x.1 + (n - x.2))) (↑(choose m x.1) * r * (↑(choose n x.2) * s)) =
      (monomial (m + n - k)) (↑(choose m x.1) * ↑(choose n x.2) * (r * s))
⊢ ↑(choose (m + n) k) = ∑ x in antidiagonal k, ↑(choose m x.1) * ↑(choose n x.2)

Next tactic:
rw_mod_cast [← Nat.add_choose_eq]
/-- 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.isPell_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
  

Proof state:
d : ℤ
a : ℤ√d
⊢ a.re ^ 2 - d * a.im ^ 2 = 1 ↔ a ∈ unitary (ℤ√d)

Next tactic:
rw [← norm_eq_one_iff_mem_unitary, norm_def, sq, sq, ← mul_assoc]
/-- 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 

Proof state:
d : ℤ
a : Solution₁ d
⊢ Solution₁.x a ^ 2 = 1 + d * Solution₁.y a ^ 2

Next tactic:
rw [← a.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]; 

Proof state:
d : ℤ
a : Solution₁ d
⊢ Solution₁.x a ^ 2 = Solution₁.x a ^ 2 - d * Solution₁.y a ^ 2 + d * Solution₁.y a ^ 2

Next tactic:
ring
/-- 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 

Proof state:
d : ℤ
a : Solution₁ d
⊢ d * Solution₁.y a ^ 2 = Solution₁.x a ^ 2 - 1

Next tactic:
rw [← a.prop]
/-- 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]; 

Proof state:
d : ℤ
a : Solution₁ d
⊢ d * Solution₁.y a ^ 2 = Solution₁.x a ^ 2 - (Solution₁.x a ^ 2 - d * Solution₁.y a ^ 2)

Next tactic:
ring
@[simp]
theorem x_mul (a b : Solution₁ d) : (a * b).x = a.x * b.x + d * (a.y * b.y) := by
  

Proof state:
d : ℤ
a b : Solution₁ d
⊢ Solution₁.x (a * b) = Solution₁.x a * Solution₁.x b + d * (Solution₁.y a * Solution₁.y b)

Next tactic:
rw [← mul_assoc]
@[simp]
theorem x_mul (a b : Solution₁ d) : (a * b).x = a.x * b.x + d * (a.y * b.y) := by
  rw [← mul_assoc]
  

Proof state:
d : ℤ
a b : Solution₁ d
⊢ Solution₁.x (a * b) = Solution₁.x a * Solution₁.x b + d * Solution₁.y a * Solution₁.y b

Next tactic:
rfl
/-- 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
  

Proof state:
d : ℤ
h₀ : d < 0
a : Solution₁ d
⊢ Solution₁.x a = 0 ∨ Solution₁.y a = 0

Next tactic:
have h := a.prop
/-- 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
  

Proof state:
d : ℤ
h₀ : d < 0
a : Solution₁ d
h : Solution₁.x a ^ 2 - d * Solution₁.y a ^ 2 = 1
⊢ Solution₁.x a = 0 ∨ Solution₁.y a = 0

Next tactic:
contrapose! h
/-- 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
  

Proof state:
d : ℤ
h₀ : d < 0
a : Solution₁ d
h : Solution₁.x a ≠ 0 ∧ Solution₁.y a ≠ 0
⊢ Solution₁.x a ^ 2 - d * Solution₁.y a ^ 2 ≠ 1

Next tactic:
have h1 := sq_pos_of_ne_zero a.x h.1
/-- 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
  

Proof state:
d : ℤ
h₀ : d < 0
a : Solution₁ d
h : Solution₁.x a ≠ 0 ∧ Solution₁.y a ≠ 0
h1 : 0 < Solution₁.x a ^ 2
⊢ Solution₁.x a ^ 2 - d * Solution₁.y a ^ 2 ≠ 1

Next tactic:
have h2 := sq_pos_of_ne_zero a.y h.2
/-- 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
  

Proof state:
d : ℤ
h₀ : d < 0
a : Solution₁ d
h : Solution₁.x a ≠ 0 ∧ Solution₁.y a ≠ 0
h1 : 0 < Solution₁.x a ^ 2
h2 : 0 < Solution₁.y a ^ 2
⊢ Solution₁.x a ^ 2 - d * Solution₁.y a ^ 2 ≠ 1

Next tactic:
nlinarith
/-- A solution has `x ≠ 0`. -/
theorem x_ne_zero (h₀ : 0 ≤ d) (a : Solution₁ d) : a.x ≠ 0 := by
  

Proof state:
d : ℤ
h₀ : 0 ≤ d
a : Solution₁ d
⊢ Solution₁.x a ≠ 0

Next tactic:
intro hx
/-- A solution has `x ≠ 0`. -/
theorem x_ne_zero (h₀ : 0 ≤ d) (a : Solution₁ d) : a.x ≠ 0 := by
  intro hx
  

Proof state:
d : ℤ
h₀ : 0 ≤ d
a : Solution₁ d
hx : Solution₁.x a = 0
⊢ False

Next tactic:
have h : 0 ≤ d * a.y ^ 2 := mul_nonneg h₀ (sq_nonneg _)
/-- 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 _)
  

Proof state:
d : ℤ
h₀ : 0 ≤ d
a : Solution₁ d
hx : Solution₁.x a = 0
h : 0 ≤ d * Solution₁.y a ^ 2
⊢ False

Next tactic:
rw [a.prop_y, hx, sq, zero_mul, zero_sub] at h
/-- 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, zero_mul, zero_sub] at h
  

Proof state:
d : ℤ
h₀ : 0 ≤ d
a : Solution₁ d
hx : Solution₁.x a = 0
h : 0 ≤ -1
⊢ False

Next tactic:
exact not_le.mpr (neg_one_lt_zero : (-1 : ℤ) < 0) h
/-- 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
  

Proof state:
d : ℤ
a : Solution₁ d
ha : 1 < Solution₁.x a
⊢ Solution₁.y a ≠ 0

Next tactic:
intro hy
/-- 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
  

Proof state:
d : ℤ
a : Solution₁ d
ha : 1 < Solution₁.x a
hy : Solution₁.y a = 0
⊢ False

Next tactic:
have prop := a.prop
/-- 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
  

Proof state:
d : ℤ
a : Solution₁ d
ha : 1 < Solution₁.x a
hy : Solution₁.y a = 0
prop : Solution₁.x a ^ 2 - d * Solution₁.y a ^ 2 = 1
⊢ False

Next tactic:
rw [hy, sq (0 : ℤ), zero_mul, mul_zero, sub_zero] at prop
/-- 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 : ℤ), zero_mul, mul_zero, sub_zero] at prop
  

Proof state:
d : ℤ
a : Solution₁ d
ha : 1 < Solution₁.x a
hy : Solution₁.y a = 0
prop : Solution₁.x a ^ 2 = 1
⊢ False

Next tactic:
exact lt_irrefl _ (((one_lt_sq_iff <| zero_le_one.trans ha.le).mpr ha).trans_eq prop)
/-- 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
  

Proof state:
d : ℤ
a : Solution₁ d
ha : 1 < Solution₁.x a
⊢ 0 < d

Next tactic:
refine' pos_of_mul_pos_left _ (sq_nonneg a.y)
/-- 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)
  

Proof state:
d : ℤ
a : Solution₁ d
ha : 1 < Solution₁.x a
⊢ 0 < d * Solution₁.y a ^ 2

Next tactic:
rw [a.prop_y, sub_pos]
/-- 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]
  

Proof state:
d : ℤ
a : Solution₁ d
ha : 1 < Solution₁.x a
⊢ 1 < Solution₁.x a ^ 2

Next tactic:
exact one_lt_pow ha two_ne_zero
/-- 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
  

Proof state:
d : ℤ
a : Solution₁ d
ha : 1 < Solution₁.x a
⊢ ¬IsSquare d

Next tactic:
have hp := a.prop
/-- 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
  

Proof state:
d : ℤ
a : Solution₁ d
ha : 1 < Solution₁.x a
hp : Solution₁.x a ^ 2 - d * Solution₁.y a ^ 2 = 1
⊢ ¬IsSquare d

Next tactic:
rintro ⟨b, rfl⟩
/-- 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⟩
  

Proof state:
case intro
b : ℤ
a : Solution₁ (b * b)
ha : 1 < Solution₁.x a
hp : Solution₁.x a ^ 2 - b * b * Solution₁.y a ^ 2 = 1
⊢ False

Next tactic:
simp_rw [← sq, ← mul_pow, sq_sub_sq, Int.mul_eq_one_iff_eq_one_or_neg_one] at hp
/-- 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
  

Proof state:
case intro
b : ℤ
a : Solution₁ (b * b)
ha : 1 < Solution₁.x a
hp :
  Solution₁.x a + b * Solution₁.y a = 1 ∧ Solution₁.x a - b * Solution₁.y a = 1 ∨
    Solution₁.x a + b * Solution₁.y a = -1 ∧ Solution₁.x a - b * Solution₁.y a = -1
⊢ False

Next tactic:
rcases hp with (⟨hp₁, hp₂⟩ | ⟨hp₁, hp₂⟩)
/-- 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₂⟩) <;> 

Proof state:
case intro.inl.intro
b : ℤ
a : Solution₁ (b * b)
ha : 1 < Solution₁.x a
hp₁ : Solution₁.x a + b * Solution₁.y a = 1
hp₂ : Solution₁.x a - b * Solution₁.y a = 1
⊢ False

Next tactic:
linarith [ha, hp₁, hp₂]
/-- 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₂⟩) <;> 

Proof state:
case intro.inr.intro
b : ℤ
a : Solution₁ (b * b)
ha : 1 < Solution₁.x a
hp₁ : Solution₁.x a + b * Solution₁.y a = -1
hp₂ : Solution₁.x a - b * Solution₁.y a = -1
⊢ False

Next tactic:
linarith [ha, hp₁, hp₂]
/-- 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
  

Proof state:
d : ℤ
h₀ : d ≠ 0
a : Solution₁ d
ha : Solution₁.x a = 1
⊢ a = 1

Next tactic:
have prop := a.prop_y
/-- 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
  

Proof state:
d : ℤ
h₀ : d ≠ 0
a : Solution₁ d
ha : Solution₁.x a = 1
prop : d * Solution₁.y a ^ 2 = Solution₁.x a ^ 2 - 1
⊢ a = 1

Next tactic:
rw [ha, one_pow, sub_self, mul_eq_zero, or_iff_right h₀, sq_eq_zero_iff] at prop
/-- 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
  

Proof state:
d : ℤ
h₀ : d ≠ 0
a : Solution₁ d
ha : Solution₁.x a = 1
prop : Solution₁.y a = 0
⊢ a = 1

Next tactic:
exact ext ha prop
/-- 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
  

Proof state:
d : ℤ
a : Solution₁ d
⊢ a = 1 ∨ a = -1 ↔ Solution₁.y a = 0

Next tactic:
refine' ⟨fun H => H.elim (fun h => by simp [h]) fun h => by simp [h], fun H => _⟩
/-- 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 

Proof state:
d : ℤ
a : Solution₁ d
H : a = 1 ∨ a = -1
h : a = 1
⊢ Solution₁.y a = 0

Next tactic:
simp [h]
/-- 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 

Proof state:
d : ℤ
a : Solution₁ d
H : a = 1 ∨ a = -1
h : a = -1
⊢ Solution₁.y a = 0

Next tactic:
simp [h]
/-- 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 => _⟩
  

Proof state:
d : ℤ
a : Solution₁ d
H : Solution₁.y a = 0
⊢ a = 1 ∨ a = -1

Next tactic:
have prop := a.prop
/-- 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
  

Proof state:
d : ℤ
a : Solution₁ d
H : Solution₁.y a = 0
prop : Solution₁.x a ^ 2 - d * Solution₁.y a ^ 2 = 1
⊢ a = 1 ∨ a = -1

Next tactic:
rw [H, sq (0 : ℤ), mul_zero, mul_zero, sub_zero, sq_eq_one_iff] at prop
/-- 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 : ℤ), mul_zero, mul_zero, sub_zero, sq_eq_one_iff] at prop
  

Proof state:
d : ℤ
a : Solution₁ d
H : Solution₁.y a = 0
prop : Solution₁.x a = 1 ∨ Solution₁.x a = -1
⊢ a = 1 ∨ a = -1

Next tactic:
exact prop.imp (fun h => ext h H) fun h => ext h H
/-- 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
  

Proof state:
d : ℤ
a b : Solution₁ d
ha : 0 < Solution₁.x a
hb : 0 < Solution₁.x b
⊢ 0 < Solution₁.x (a * b)

Next tactic:
simp only [x_mul]
/-- 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]
  

Proof state:
d : ℤ
a b : Solution₁ d
ha : 0 < Solution₁.x a
hb : 0 < Solution₁.x b
⊢ 0 < Solution₁.x a * Solution₁.x b + d * (Solution₁.y a * Solution₁.y b)

Next tactic:
refine' neg_lt_iff_pos_add'.mp (abs_lt.mp _).1
/-- 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
  

Proof state:
d : ℤ
a b : Solution₁ d
ha : 0 < Solution₁.x a
hb : 0 < Solution₁.x b
⊢ |d * (Solution₁.y a * Solution₁.y b)| < Solution₁.x a * Solution₁.x b

Next tactic:
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]
/-- 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]
  

Proof state:
d : ℤ
a b : Solution₁ d
ha : 0 < Solution₁.x a
hb : 0 < Solution₁.x b
⊢ 0 < (1 + d * Solution₁.y a ^ 2) * (1 + d * Solution₁.y b ^ 2) - (d * (Solution₁.y a * Solution₁.y b)) ^ 2

Next tactic:
ring_nf
/-- 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
  

Proof state:
d : ℤ
a b : Solution₁ d
ha : 0 < Solution₁.x a
hb : 0 < Solution₁.x b
⊢ 0 < 1 + d * Solution₁.y a ^ 2 + d * Solution₁.y b ^ 2

Next tactic:
rcases le_or_lt 0 d with h | h
/-- 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
  rcases le_or_lt 0 d with h | h
  · 

Proof state:
case inl
d : ℤ
a b : Solution₁ d
ha : 0 < Solution₁.x a
hb : 0 < Solution₁.x b
h : 0 ≤ d
⊢ 0 < 1 + d * Solution₁.y a ^ 2 + d * Solution₁.y b ^ 2

Next tactic:
positivity
/-- 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
  rcases le_or_lt 0 d with h | h
  · positivity
  · 

Proof state:
case inr
d : ℤ
a b : Solution₁ d
ha : 0 < Solution₁.x a
hb : 0 < Solution₁.x b
h : d < 0
⊢ 0 < 1 + d * Solution₁.y a ^ 2 + d * Solution₁.y b ^ 2

Next tactic:
rw [(eq_zero_of_d_neg h a).resolve_left ha.ne', (eq_zero_of_d_neg h b).resolve_left hb.ne']
/-- 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
  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
    -- rw [zero_pow two_pos, zero_add, zero_mul, zero_add]
    -- exact one_pos
    -- but this relied on the exact output of `ring_nf`
    

Proof state:
case inr
d : ℤ
a b : Solution₁ d
ha : 0 < Solution₁.x a
hb : 0 < Solution₁.x b
h : d < 0
⊢ 0 < 1 + d * 0 ^ 2 + d * 0 ^ 2

Next tactic:
simp
/-- 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
  

Proof state:
d : ℤ
a b : Solution₁ d
hax : 0 < Solution₁.x a
hay : 0 < Solution₁.y a
hbx : 0 < Solution₁.x b
hby : 0 < Solution₁.y b
⊢ 0 < Solution₁.y (a * b)

Next tactic:
simp only [y_mul]
/-- 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]
  

Proof state:
d : ℤ
a b : Solution₁ d
hax : 0 < Solution₁.x a
hay : 0 < Solution₁.y a
hbx : 0 < Solution₁.x b
hby : 0 < Solution₁.y b
⊢ 0 < Solution₁.x a * Solution₁.y b + Solution₁.y a * Solution₁.x b

Next tactic:
positivity
/-- 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
  

Proof state:
d : ℤ
a : Solution₁ d
hax : 0 < Solution₁.x a
n : ℕ
⊢ 0 < Solution₁.x (a ^ n)

Next tactic:
induction' n with n ih
/-- 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
  · 

Proof state:
case zero
d : ℤ
a : Solution₁ d
hax : 0 < Solution₁.x a
⊢ 0 < Solution₁.x (a ^ Nat.zero)

Next tactic:
simp only [Nat.zero_eq, pow_zero, x_one, zero_lt_one]
/-- 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 [Nat.zero_eq, pow_zero, x_one, zero_lt_one]
  · 

Proof state:
case succ
d : ℤ
a : Solution₁ d
hax : 0 < Solution₁.x a
n : ℕ
ih : 0 < Solution₁.x (a ^ n)
⊢ 0 < Solution₁.x (a ^ Nat.succ n)

Next tactic:
rw [pow_succ]
/-- 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 [Nat.zero_eq, pow_zero, x_one, zero_lt_one]
  · rw [pow_succ]
    

Proof state:
case succ
d : ℤ
a : Solution₁ d
hax : 0 < Solution₁.x a
n : ℕ
ih : 0 < Solution₁.x (a ^ n)
⊢ 0 < Solution₁.x (a * a ^ n)

Next tactic:
exact x_mul_pos hax ih
/-- 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
  

Proof state:
d : ℤ
a : Solution₁ d
hax : 0 < Solution₁.x a
hay : 0 < Solution₁.y a
n : ℕ
⊢ 0 < Solution₁.y (a ^ Nat.succ n)

Next tactic:
induction' n with n ih
/-- 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
  · 

Proof state:
case zero
d : ℤ
a : Solution₁ d
hax : 0 < Solution₁.x a
hay : 0 < Solution₁.y a
⊢ 0 < Solution₁.y (a ^ Nat.succ Nat.zero)

Next tactic:
simp only [Nat.zero_eq, ← Nat.one_eq_succ_zero, hay, pow_one]
/-- 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 [Nat.zero_eq, ← Nat.one_eq_succ_zero, hay, pow_one]
  · 

Proof state:
case succ
d : ℤ
a : Solution₁ d
hax : 0 < Solution₁.x a
hay : 0 < Solution₁.y a
n : ℕ
ih : 0 < Solution₁.y (a ^ Nat.succ n)
⊢ 0 < Solution₁.y (a ^ Nat.succ (Nat.succ n))

Next tactic:
rw [pow_succ]
/-- 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 [Nat.zero_eq, ← Nat.one_eq_succ_zero, hay, pow_one]
  · rw [pow_succ]
    

Proof state:
case succ
d : ℤ
a : Solution₁ d
hax : 0 < Solution₁.x a
hay : 0 < Solution₁.y a
n : ℕ
ih : 0 < Solution₁.y (a ^ Nat.succ n)
⊢ 0 < Solution₁.y (a * a ^ (n + 1))

Next tactic:
exact y_mul_pos hax hay (x_pow_pos hax _) ih