l3lab/ntp-mathlib huggingface dataset:
theorem sq_mul_squarefree_of_pos {n : ℕ} (hn : 0 < n) :
    ∃ a b : ℕ, 0 < a ∧ 0 < b ∧ b ^ 2 * a = n ∧ Squarefree a := by
  classical -- Porting note: This line is not needed in Lean 3
  set S := (Finset.range (n + 1)).filter (fun s => s ∣ n ∧ ∃ x, s = x ^ 2)
  have hSne : S.Nonempty := by
    use 1
    have h1 : 0 < n ∧ ∃ x : ℕ, 1 = x ^ 2 := ⟨hn, ⟨1, (one_pow 2).symm⟩⟩
    simp [h1]
  let s := Finset.max' S hSne
  have hs : s ∈ S := Finset.max'_mem S hSne
  simp only [Finset.mem_filter, Finset.mem_range] at hs
  obtain ⟨-, ⟨a, hsa⟩, ⟨b, hsb⟩⟩ := hs
  rw [hsa] at hn
  obtain ⟨hlts, hlta⟩ := CanonicallyOrderedCommSemiring.mul_pos.mp hn
  rw [hsb] at hsa hn hlts
  refine' ⟨a, b, hlta, (pow_pos_iff zero_lt_two).mp hlts, hsa.symm, _⟩
  rintro x ⟨y, hy⟩
  rw [Nat.isUnit_iff]
  by_contra hx
  refine' Nat.lt_le_asymm _ (Finset.le_max' S ((b * x) ^ 2) _)
  -- Porting note: these two goals were in the opposite order in Lean 3
  · convert lt_mul_of_one_lt_right hlts
      (one_lt_pow 2 x two_ne_zero (one_lt_iff_ne_zero_and_ne_one.mpr ⟨fun h => by simp_all, hx⟩))
      using 1
    

Proof state:
case h.e'_4
s✝ : Finset ℕ
m n✝ p n : ℕ
S : Finset ℕ := filter (fun s => s ∣ n ∧ ∃ x, s = x ^ 2) (range (n + 1))
hSne : Finset.Nonempty S
s : ℕ := max' S hSne
a b : ℕ
hn : 0 < b ^ 2 * a
hsa : n = b ^ 2 * a
hsb : max' (filter (fun s => s ∣ n ∧ ∃ x, s = x ^ 2) (range (n + 1))) hSne = b ^ 2
hlts : 0 < b ^ 2
hlta : 0 < a
x y : ℕ
hy : a = x * x * y
hx : ¬x = 1
⊢ (b * x) ^ 2 = b ^ 2 * x ^ 2

Next tactic:
rw [mul_pow]
theorem sq_mul_squarefree_of_pos {n : ℕ} (hn : 0 < n) :
    ∃ a b : ℕ, 0 < a ∧ 0 < b ∧ b ^ 2 * a = n ∧ Squarefree a := by
  classical -- Porting note: This line is not needed in Lean 3
  set S := (Finset.range (n + 1)).filter (fun s => s ∣ n ∧ ∃ x, s = x ^ 2)
  have hSne : S.Nonempty := by
    use 1
    have h1 : 0 < n ∧ ∃ x : ℕ, 1 = x ^ 2 := ⟨hn, ⟨1, (one_pow 2).symm⟩⟩
    simp [h1]
  let s := Finset.max' S hSne
  have hs : s ∈ S := Finset.max'_mem S hSne
  simp only [Finset.mem_filter, Finset.mem_range] at hs
  obtain ⟨-, ⟨a, hsa⟩, ⟨b, hsb⟩⟩ := hs
  rw [hsa] at hn
  obtain ⟨hlts, hlta⟩ := CanonicallyOrderedCommSemiring.mul_pos.mp hn
  rw [hsb] at hsa hn hlts
  refine' ⟨a, b, hlta, (pow_pos_iff zero_lt_two).mp hlts, hsa.symm, _⟩
  rintro x ⟨y, hy⟩
  rw [Nat.isUnit_iff]
  by_contra hx
  refine' Nat.lt_le_asymm _ (Finset.le_max' S ((b * x) ^ 2) _)
  -- Porting note: these two goals were in the opposite order in Lean 3
  · convert lt_mul_of_one_lt_right hlts
      (one_lt_pow 2 x two_ne_zero (one_lt_iff_ne_zero_and_ne_one.mpr ⟨fun h => by simp_all, hx⟩))
      using 1
    rw [mul_pow]
  · 

Proof state:
case intro.intro.intro.intro.intro.intro.refine'_2
s✝ : Finset ℕ
m n✝ p n : ℕ
S : Finset ℕ := filter (fun s => s ∣ n ∧ ∃ x, s = x ^ 2) (range (n + 1))
hSne : Finset.Nonempty S
s : ℕ := max' S hSne
a b : ℕ
hn : 0 < b ^ 2 * a
hsa : n = b ^ 2 * a
hsb : max' (filter (fun s => s ∣ n ∧ ∃ x, s = x ^ 2) (range (n + 1))) hSne = b ^ 2
hlts : 0 < b ^ 2
hlta : 0 < a
x y : ℕ
hy : a = x * x * y
hx : ¬x = 1
⊢ (b * x) ^ 2 ∈ S

Next tactic:
simp_rw [hsa, Finset.mem_filter, Finset.mem_range]
theorem sq_mul_squarefree_of_pos {n : ℕ} (hn : 0 < n) :
    ∃ a b : ℕ, 0 < a ∧ 0 < b ∧ b ^ 2 * a = n ∧ Squarefree a := by
  classical -- Porting note: This line is not needed in Lean 3
  set S := (Finset.range (n + 1)).filter (fun s => s ∣ n ∧ ∃ x, s = x ^ 2)
  have hSne : S.Nonempty := by
    use 1
    have h1 : 0 < n ∧ ∃ x : ℕ, 1 = x ^ 2 := ⟨hn, ⟨1, (one_pow 2).symm⟩⟩
    simp [h1]
  let s := Finset.max' S hSne
  have hs : s ∈ S := Finset.max'_mem S hSne
  simp only [Finset.mem_filter, Finset.mem_range] at hs
  obtain ⟨-, ⟨a, hsa⟩, ⟨b, hsb⟩⟩ := hs
  rw [hsa] at hn
  obtain ⟨hlts, hlta⟩ := CanonicallyOrderedCommSemiring.mul_pos.mp hn
  rw [hsb] at hsa hn hlts
  refine' ⟨a, b, hlta, (pow_pos_iff zero_lt_two).mp hlts, hsa.symm, _⟩
  rintro x ⟨y, hy⟩
  rw [Nat.isUnit_iff]
  by_contra hx
  refine' Nat.lt_le_asymm _ (Finset.le_max' S ((b * x) ^ 2) _)
  -- Porting note: these two goals were in the opposite order in Lean 3
  · convert lt_mul_of_one_lt_right hlts
      (one_lt_pow 2 x two_ne_zero (one_lt_iff_ne_zero_and_ne_one.mpr ⟨fun h => by simp_all, hx⟩))
      using 1
    rw [mul_pow]
  · simp_rw [hsa, Finset.mem_filter, Finset.mem_range]
    

Proof state:
case intro.intro.intro.intro.intro.intro.refine'_2
s✝ : Finset ℕ
m n✝ p n : ℕ
S : Finset ℕ := filter (fun s => s ∣ n ∧ ∃ x, s = x ^ 2) (range (n + 1))
hSne : Finset.Nonempty S
s : ℕ := max' S hSne
a b : ℕ
hn : 0 < b ^ 2 * a
hsa : n = b ^ 2 * a
hsb : max' (filter (fun s => s ∣ n ∧ ∃ x, s = x ^ 2) (range (n + 1))) hSne = b ^ 2
hlts : 0 < b ^ 2
hlta : 0 < a
x y : ℕ
hy : a = x * x * y
hx : ¬x = 1
⊢ (b * x) ^ 2 < b ^ 2 * a + 1 ∧ (b * x) ^ 2 ∣ b ^ 2 * a ∧ ∃ x_1, (b * x) ^ 2 = x_1 ^ 2

Next tactic:
refine' ⟨lt_succ_iff.mpr (le_of_dvd hn _), _, ⟨b * x, rfl⟩⟩
theorem sq_mul_squarefree_of_pos {n : ℕ} (hn : 0 < n) :
    ∃ a b : ℕ, 0 < a ∧ 0 < b ∧ b ^ 2 * a = n ∧ Squarefree a := by
  classical -- Porting note: This line is not needed in Lean 3
  set S := (Finset.range (n + 1)).filter (fun s => s ∣ n ∧ ∃ x, s = x ^ 2)
  have hSne : S.Nonempty := by
    use 1
    have h1 : 0 < n ∧ ∃ x : ℕ, 1 = x ^ 2 := ⟨hn, ⟨1, (one_pow 2).symm⟩⟩
    simp [h1]
  let s := Finset.max' S hSne
  have hs : s ∈ S := Finset.max'_mem S hSne
  simp only [Finset.mem_filter, Finset.mem_range] at hs
  obtain ⟨-, ⟨a, hsa⟩, ⟨b, hsb⟩⟩ := hs
  rw [hsa] at hn
  obtain ⟨hlts, hlta⟩ := CanonicallyOrderedCommSemiring.mul_pos.mp hn
  rw [hsb] at hsa hn hlts
  refine' ⟨a, b, hlta, (pow_pos_iff zero_lt_two).mp hlts, hsa.symm, _⟩
  rintro x ⟨y, hy⟩
  rw [Nat.isUnit_iff]
  by_contra hx
  refine' Nat.lt_le_asymm _ (Finset.le_max' S ((b * x) ^ 2) _)
  -- Porting note: these two goals were in the opposite order in Lean 3
  · convert lt_mul_of_one_lt_right hlts
      (one_lt_pow 2 x two_ne_zero (one_lt_iff_ne_zero_and_ne_one.mpr ⟨fun h => by simp_all, hx⟩))
      using 1
    rw [mul_pow]
  · simp_rw [hsa, Finset.mem_filter, Finset.mem_range]
    refine' ⟨lt_succ_iff.mpr (le_of_dvd hn _), _, ⟨b * x, rfl⟩⟩ <;> 

Proof state:
case intro.intro.intro.intro.intro.intro.refine'_2.refine'_1
s✝ : Finset ℕ
m n✝ p n : ℕ
S : Finset ℕ := filter (fun s => s ∣ n ∧ ∃ x, s = x ^ 2) (range (n + 1))
hSne : Finset.Nonempty S
s : ℕ := max' S hSne
a b : ℕ
hn : 0 < b ^ 2 * a
hsa : n = b ^ 2 * a
hsb : max' (filter (fun s => s ∣ n ∧ ∃ x, s = x ^ 2) (range (n + 1))) hSne = b ^ 2
hlts : 0 < b ^ 2
hlta : 0 < a
x y : ℕ
hy : a = x * x * y
hx : ¬x = 1
⊢ (b * x) ^ 2 ∣ b ^ 2 * a

Next tactic:
use y
theorem sq_mul_squarefree_of_pos {n : ℕ} (hn : 0 < n) :
    ∃ a b : ℕ, 0 < a ∧ 0 < b ∧ b ^ 2 * a = n ∧ Squarefree a := by
  classical -- Porting note: This line is not needed in Lean 3
  set S := (Finset.range (n + 1)).filter (fun s => s ∣ n ∧ ∃ x, s = x ^ 2)
  have hSne : S.Nonempty := by
    use 1
    have h1 : 0 < n ∧ ∃ x : ℕ, 1 = x ^ 2 := ⟨hn, ⟨1, (one_pow 2).symm⟩⟩
    simp [h1]
  let s := Finset.max' S hSne
  have hs : s ∈ S := Finset.max'_mem S hSne
  simp only [Finset.mem_filter, Finset.mem_range] at hs
  obtain ⟨-, ⟨a, hsa⟩, ⟨b, hsb⟩⟩ := hs
  rw [hsa] at hn
  obtain ⟨hlts, hlta⟩ := CanonicallyOrderedCommSemiring.mul_pos.mp hn
  rw [hsb] at hsa hn hlts
  refine' ⟨a, b, hlta, (pow_pos_iff zero_lt_two).mp hlts, hsa.symm, _⟩
  rintro x ⟨y, hy⟩
  rw [Nat.isUnit_iff]
  by_contra hx
  refine' Nat.lt_le_asymm _ (Finset.le_max' S ((b * x) ^ 2) _)
  -- Porting note: these two goals were in the opposite order in Lean 3
  · convert lt_mul_of_one_lt_right hlts
      (one_lt_pow 2 x two_ne_zero (one_lt_iff_ne_zero_and_ne_one.mpr ⟨fun h => by simp_all, hx⟩))
      using 1
    rw [mul_pow]
  · simp_rw [hsa, Finset.mem_filter, Finset.mem_range]
    refine' ⟨lt_succ_iff.mpr (le_of_dvd hn _), _, ⟨b * x, rfl⟩⟩ <;> 

Proof state:
case intro.intro.intro.intro.intro.intro.refine'_2.refine'_2
s✝ : Finset ℕ
m n✝ p n : ℕ
S : Finset ℕ := filter (fun s => s ∣ n ∧ ∃ x, s = x ^ 2) (range (n + 1))
hSne : Finset.Nonempty S
s : ℕ := max' S hSne
a b : ℕ
hn : 0 < b ^ 2 * a
hsa : n = b ^ 2 * a
hsb : max' (filter (fun s => s ∣ n ∧ ∃ x, s = x ^ 2) (range (n + 1))) hSne = b ^ 2
hlts : 0 < b ^ 2
hlta : 0 < a
x y : ℕ
hy : a = x * x * y
hx : ¬x = 1
⊢ (b * x) ^ 2 ∣ b ^ 2 * a

Next tactic:
use y
theorem sq_mul_squarefree_of_pos {n : ℕ} (hn : 0 < n) :
    ∃ a b : ℕ, 0 < a ∧ 0 < b ∧ b ^ 2 * a = n ∧ Squarefree a := by
  classical -- Porting note: This line is not needed in Lean 3
  set S := (Finset.range (n + 1)).filter (fun s => s ∣ n ∧ ∃ x, s = x ^ 2)
  have hSne : S.Nonempty := by
    use 1
    have h1 : 0 < n ∧ ∃ x : ℕ, 1 = x ^ 2 := ⟨hn, ⟨1, (one_pow 2).symm⟩⟩
    simp [h1]
  let s := Finset.max' S hSne
  have hs : s ∈ S := Finset.max'_mem S hSne
  simp only [Finset.mem_filter, Finset.mem_range] at hs
  obtain ⟨-, ⟨a, hsa⟩, ⟨b, hsb⟩⟩ := hs
  rw [hsa] at hn
  obtain ⟨hlts, hlta⟩ := CanonicallyOrderedCommSemiring.mul_pos.mp hn
  rw [hsb] at hsa hn hlts
  refine' ⟨a, b, hlta, (pow_pos_iff zero_lt_two).mp hlts, hsa.symm, _⟩
  rintro x ⟨y, hy⟩
  rw [Nat.isUnit_iff]
  by_contra hx
  refine' Nat.lt_le_asymm _ (Finset.le_max' S ((b * x) ^ 2) _)
  -- Porting note: these two goals were in the opposite order in Lean 3
  · convert lt_mul_of_one_lt_right hlts
      (one_lt_pow 2 x two_ne_zero (one_lt_iff_ne_zero_and_ne_one.mpr ⟨fun h => by simp_all, hx⟩))
      using 1
    rw [mul_pow]
  · simp_rw [hsa, Finset.mem_filter, Finset.mem_range]
    refine' ⟨lt_succ_iff.mpr (le_of_dvd hn _), _, ⟨b * x, rfl⟩⟩ <;> use y <;> 

Proof state:
case h
s✝ : Finset ℕ
m n✝ p n : ℕ
S : Finset ℕ := filter (fun s => s ∣ n ∧ ∃ x, s = x ^ 2) (range (n + 1))
hSne : Finset.Nonempty S
s : ℕ := max' S hSne
a b : ℕ
hn : 0 < b ^ 2 * a
hsa : n = b ^ 2 * a
hsb : max' (filter (fun s => s ∣ n ∧ ∃ x, s = x ^ 2) (range (n + 1))) hSne = b ^ 2
hlts : 0 < b ^ 2
hlta : 0 < a
x y : ℕ
hy : a = x * x * y
hx : ¬x = 1
⊢ b ^ 2 * a = (b * x) ^ 2 * y

Next tactic:
rw [hy]
theorem sq_mul_squarefree_of_pos {n : ℕ} (hn : 0 < n) :
    ∃ a b : ℕ, 0 < a ∧ 0 < b ∧ b ^ 2 * a = n ∧ Squarefree a := by
  classical -- Porting note: This line is not needed in Lean 3
  set S := (Finset.range (n + 1)).filter (fun s => s ∣ n ∧ ∃ x, s = x ^ 2)
  have hSne : S.Nonempty := by
    use 1
    have h1 : 0 < n ∧ ∃ x : ℕ, 1 = x ^ 2 := ⟨hn, ⟨1, (one_pow 2).symm⟩⟩
    simp [h1]
  let s := Finset.max' S hSne
  have hs : s ∈ S := Finset.max'_mem S hSne
  simp only [Finset.mem_filter, Finset.mem_range] at hs
  obtain ⟨-, ⟨a, hsa⟩, ⟨b, hsb⟩⟩ := hs
  rw [hsa] at hn
  obtain ⟨hlts, hlta⟩ := CanonicallyOrderedCommSemiring.mul_pos.mp hn
  rw [hsb] at hsa hn hlts
  refine' ⟨a, b, hlta, (pow_pos_iff zero_lt_two).mp hlts, hsa.symm, _⟩
  rintro x ⟨y, hy⟩
  rw [Nat.isUnit_iff]
  by_contra hx
  refine' Nat.lt_le_asymm _ (Finset.le_max' S ((b * x) ^ 2) _)
  -- Porting note: these two goals were in the opposite order in Lean 3
  · convert lt_mul_of_one_lt_right hlts
      (one_lt_pow 2 x two_ne_zero (one_lt_iff_ne_zero_and_ne_one.mpr ⟨fun h => by simp_all, hx⟩))
      using 1
    rw [mul_pow]
  · simp_rw [hsa, Finset.mem_filter, Finset.mem_range]
    refine' ⟨lt_succ_iff.mpr (le_of_dvd hn _), _, ⟨b * x, rfl⟩⟩ <;> use y <;> rw [hy] <;> 

Proof state:
case h
s✝ : Finset ℕ
m n✝ p n : ℕ
S : Finset ℕ := filter (fun s => s ∣ n ∧ ∃ x, s = x ^ 2) (range (n + 1))
hSne : Finset.Nonempty S
s : ℕ := max' S hSne
a b : ℕ
hn : 0 < b ^ 2 * a
hsa : n = b ^ 2 * a
hsb : max' (filter (fun s => s ∣ n ∧ ∃ x, s = x ^ 2) (range (n + 1))) hSne = b ^ 2
hlts : 0 < b ^ 2
hlta : 0 < a
x y : ℕ
hy : a = x * x * y
hx : ¬x = 1
⊢ b ^ 2 * (x * x * y) = (b * x) ^ 2 * y

Next tactic:
ring
theorem sq_mul_squarefree_of_pos' {n : ℕ} (h : 0 < n) :
    ∃ a b : ℕ, (b + 1) ^ 2 * (a + 1) = n ∧ Squarefree (a + 1) := by
  

Proof state:
s : Finset ℕ
m n✝ p n : ℕ
h : 0 < n
⊢ ∃ a b, (b + 1) ^ 2 * (a + 1) = n ∧ Squarefree (a + 1)

Next tactic:
obtain ⟨a₁, b₁, ha₁, hb₁, hab₁, hab₂⟩ := sq_mul_squarefree_of_pos h
theorem sq_mul_squarefree_of_pos' {n : ℕ} (h : 0 < n) :
    ∃ a b : ℕ, (b + 1) ^ 2 * (a + 1) = n ∧ Squarefree (a + 1) := by
  obtain ⟨a₁, b₁, ha₁, hb₁, hab₁, hab₂⟩ := sq_mul_squarefree_of_pos h
  

Proof state:
case intro.intro.intro.intro.intro
s : Finset ℕ
m n✝ p n : ℕ
h : 0 < n
a₁ b₁ : ℕ
ha₁ : 0 < a₁
hb₁ : 0 < b₁
hab₁ : b₁ ^ 2 * a₁ = n
hab₂ : Squarefree a₁
⊢ ∃ a b, (b + 1) ^ 2 * (a + 1) = n ∧ Squarefree (a + 1)

Next tactic:
refine' ⟨a₁.pred, b₁.pred, _, _⟩
theorem sq_mul_squarefree_of_pos' {n : ℕ} (h : 0 < n) :
    ∃ a b : ℕ, (b + 1) ^ 2 * (a + 1) = n ∧ Squarefree (a + 1) := by
  obtain ⟨a₁, b₁, ha₁, hb₁, hab₁, hab₂⟩ := sq_mul_squarefree_of_pos h
  refine' ⟨a₁.pred, b₁.pred, _, _⟩ <;> 

Proof state:
case intro.intro.intro.intro.intro.refine'_1
s : Finset ℕ
m n✝ p n : ℕ
h : 0 < n
a₁ b₁ : ℕ
ha₁ : 0 < a₁
hb₁ : 0 < b₁
hab₁ : b₁ ^ 2 * a₁ = n
hab₂ : Squarefree a₁
⊢ (pred b₁ + 1) ^ 2 * (pred a₁ + 1) = n

Next tactic:
simpa only [add_one, succ_pred_eq_of_pos, ha₁, hb₁]
theorem sq_mul_squarefree_of_pos' {n : ℕ} (h : 0 < n) :
    ∃ a b : ℕ, (b + 1) ^ 2 * (a + 1) = n ∧ Squarefree (a + 1) := by
  obtain ⟨a₁, b₁, ha₁, hb₁, hab₁, hab₂⟩ := sq_mul_squarefree_of_pos h
  refine' ⟨a₁.pred, b₁.pred, _, _⟩ <;> 

Proof state:
case intro.intro.intro.intro.intro.refine'_2
s : Finset ℕ
m n✝ p n : ℕ
h : 0 < n
a₁ b₁ : ℕ
ha₁ : 0 < a₁
hb₁ : 0 < b₁
hab₁ : b₁ ^ 2 * a₁ = n
hab₂ : Squarefree a₁
⊢ Squarefree (pred a₁ + 1)

Next tactic:
simpa only [add_one, succ_pred_eq_of_pos, ha₁, hb₁]
theorem sq_mul_squarefree (n : ℕ) : ∃ a b : ℕ, b ^ 2 * a = n ∧ Squarefree a := by
  

Proof state:
s : Finset ℕ
m n✝ p n : ℕ
⊢ ∃ a b, b ^ 2 * a = n ∧ Squarefree a

Next tactic:
cases' n with n
theorem sq_mul_squarefree (n : ℕ) : ∃ a b : ℕ, b ^ 2 * a = n ∧ Squarefree a := by
  cases' n with n
  · 

Proof state:
case zero
s : Finset ℕ
m n p : ℕ
⊢ ∃ a b, b ^ 2 * a = zero ∧ Squarefree a

Next tactic:
exact ⟨1, 0, by simp, squarefree_one⟩
theorem sq_mul_squarefree (n : ℕ) : ∃ a b : ℕ, b ^ 2 * a = n ∧ Squarefree a := by
  cases' n with n
  · exact ⟨1, 0, by 

Proof state:
s : Finset ℕ
m n p : ℕ
⊢ 0 ^ 2 * 1 = zero

Next tactic:
simp
theorem sq_mul_squarefree (n : ℕ) : ∃ a b : ℕ, b ^ 2 * a = n ∧ Squarefree a := by
  cases' n with n
  · exact ⟨1, 0, by simp, squarefree_one⟩
  · 

Proof state:
case succ
s : Finset ℕ
m n✝ p n : ℕ
⊢ ∃ a b, b ^ 2 * a = succ n ∧ Squarefree a

Next tactic:
obtain ⟨a, b, -, -, h₁, h₂⟩ := sq_mul_squarefree_of_pos (succ_pos n)
theorem sq_mul_squarefree (n : ℕ) : ∃ a b : ℕ, b ^ 2 * a = n ∧ Squarefree a := by
  cases' n with n
  · exact ⟨1, 0, by simp, squarefree_one⟩
  · obtain ⟨a, b, -, -, h₁, h₂⟩ := sq_mul_squarefree_of_pos (succ_pos n)
    

Proof state:
case succ.intro.intro.intro.intro.intro
s : Finset ℕ
m n✝ p n a b : ℕ
h₁ : b ^ 2 * a = succ n
h₂ : Squarefree a
⊢ ∃ a b, b ^ 2 * a = succ n ∧ Squarefree a

Next tactic:
exact ⟨a, b, h₁, h₂⟩
/-- `Squarefree` is multiplicative. Note that the → direction does not require `hmn`
and generalizes to arbitrary commutative monoids. See `Squarefree.of_mul_left` and
`Squarefree.of_mul_right` above for auxiliary lemmas. -/
theorem squarefree_mul {m n : ℕ} (hmn : m.Coprime n) :
    Squarefree (m * n) ↔ Squarefree m ∧ Squarefree n := by
  

Proof state:
s : Finset ℕ
m✝ n✝ p m n : ℕ
hmn : Coprime m n
⊢ Squarefree (m * n) ↔ Squarefree m ∧ Squarefree n

Next tactic:
simp only [squarefree_iff_prime_squarefree, ← sq, ← forall_and]
/-- `Squarefree` is multiplicative. Note that the → direction does not require `hmn`
and generalizes to arbitrary commutative monoids. See `Squarefree.of_mul_left` and
`Squarefree.of_mul_right` above for auxiliary lemmas. -/
theorem squarefree_mul {m n : ℕ} (hmn : m.Coprime n) :
    Squarefree (m * n) ↔ Squarefree m ∧ Squarefree n := by
  simp only [squarefree_iff_prime_squarefree, ← sq, ← forall_and]
  

Proof state:
s : Finset ℕ
m✝ n✝ p m n : ℕ
hmn : Coprime m n
⊢ (∀ (x : ℕ), Prime x → ¬x ^ 2 ∣ m * n) ↔ ∀ (x : ℕ), Prime x → ¬x ^ 2 ∣ m ∧ ¬x ^ 2 ∣ n

Next tactic:
refine' ball_congr fun p hp => _
/-- `Squarefree` is multiplicative. Note that the → direction does not require `hmn`
and generalizes to arbitrary commutative monoids. See `Squarefree.of_mul_left` and
`Squarefree.of_mul_right` above for auxiliary lemmas. -/
theorem squarefree_mul {m n : ℕ} (hmn : m.Coprime n) :
    Squarefree (m * n) ↔ Squarefree m ∧ Squarefree n := by
  simp only [squarefree_iff_prime_squarefree, ← sq, ← forall_and]
  refine' ball_congr fun p hp => _
  

Proof state:
s : Finset ℕ
m✝ n✝ p✝ m n : ℕ
hmn : Coprime m n
p : ℕ
hp : Prime p
⊢ ¬p ^ 2 ∣ m * n ↔ ¬p ^ 2 ∣ m ∧ ¬p ^ 2 ∣ n

Next tactic:
simp only [hmn.isPrimePow_dvd_mul (hp.isPrimePow.pow two_ne_zero), not_or]
lemma coprime_div_gcd_of_squarefree (hm : Squarefree m) (hn : n ≠ 0) : Coprime (m / gcd m n) n := by
  

Proof state:
s : Finset ℕ
m n p : ℕ
hm : Squarefree m
hn : n ≠ 0
⊢ Coprime (m / gcd m n) n

Next tactic:
have : Coprime (m / gcd m n) (gcd m n) :=
    coprime_of_squarefree_mul $ by simpa [Nat.div_mul_cancel, gcd_dvd_left]
lemma coprime_div_gcd_of_squarefree (hm : Squarefree m) (hn : n ≠ 0) : Coprime (m / gcd m n) n := by
  have : Coprime (m / gcd m n) (gcd m n) :=
    coprime_of_squarefree_mul $ by 

Proof state:
s : Finset ℕ
m n p : ℕ
hm : Squarefree m
hn : n ≠ 0
⊢ Squarefree (m / gcd m n * gcd m n)

Next tactic:
simpa [Nat.div_mul_cancel, gcd_dvd_left]
lemma coprime_div_gcd_of_squarefree (hm : Squarefree m) (hn : n ≠ 0) : Coprime (m / gcd m n) n := by
  have : Coprime (m / gcd m n) (gcd m n) :=
    coprime_of_squarefree_mul $ by simpa [Nat.div_mul_cancel, gcd_dvd_left]
  

Proof state:
s : Finset ℕ
m n p : ℕ
hm : Squarefree m
hn : n ≠ 0
this : Coprime (m / gcd m n) (gcd m n)
⊢ Coprime (m / gcd m n) n

Next tactic:
simpa [Nat.div_mul_cancel, gcd_dvd_right] using
    (coprime_div_gcd_div_gcd (m := m) (gcd_ne_zero_right hn).bot_lt).mul_right this
lemma prod_primeFactors_of_squarefree (hn : Squarefree n) : ∏ p in n.primeFactors, p = n := by
  

Proof state:
s : Finset ℕ
m n p : ℕ
hn : Squarefree n
⊢ ∏ p in n.primeFactors, p = n

Next tactic:
convert factorization_prod_pow_eq_self hn.ne_zero
lemma prod_primeFactors_of_squarefree (hn : Squarefree n) : ∏ p in n.primeFactors, p = n := by
  convert factorization_prod_pow_eq_self hn.ne_zero
  

Proof state:
case h.e'_2
s : Finset ℕ
m n p : ℕ
hn : Squarefree n
⊢ ∏ p in n.primeFactors, p = Finsupp.prod (factorization n) fun x x_1 => x ^ x_1

Next tactic:
refine prod_congr rfl fun p hp ↦ ?_
lemma prod_primeFactors_of_squarefree (hn : Squarefree n) : ∏ p in n.primeFactors, p = n := by
  convert factorization_prod_pow_eq_self hn.ne_zero
  refine prod_congr rfl fun p hp ↦ ?_
  

Proof state:
case h.e'_2
s : Finset ℕ
m n p✝ : ℕ
hn : Squarefree n
p : ℕ
hp : p ∈ (factorization n).support
⊢ p = (fun x x_1 => x ^ x_1) p ((factorization n) p)

Next tactic:
simp only [support_factorization, toFinset_factors, mem_primeFactors_of_ne_zero hn.ne_zero] at hp
lemma prod_primeFactors_of_squarefree (hn : Squarefree n) : ∏ p in n.primeFactors, p = n := by
  convert factorization_prod_pow_eq_self hn.ne_zero
  refine prod_congr rfl fun p hp ↦ ?_
  simp only [support_factorization, toFinset_factors, mem_primeFactors_of_ne_zero hn.ne_zero] at hp
  

Proof state:
case h.e'_2
s : Finset ℕ
m n p✝ : ℕ
hn : Squarefree n
p : ℕ
hp : Prime p ∧ p ∣ n
⊢ p = (fun x x_1 => x ^ x_1) p ((factorization n) p)

Next tactic:
simp_rw [factorization_eq_one_of_squarefree hn hp.1 hp.2, pow_one]
lemma primeFactors_prod (hs : ∀ p ∈ s, p.Prime) : primeFactors (∏ p in s, p) = s := by
  

Proof state:
s : Finset ℕ
m n p : ℕ
hs : ∀ p ∈ s, Prime p
⊢ (∏ p in s, p).primeFactors = s

Next tactic:
have hn : ∏ p in s, p ≠ 0 := prod_ne_zero_iff.2 fun p hp ↦ (hs _ hp).ne_zero
lemma primeFactors_prod (hs : ∀ p ∈ s, p.Prime) : primeFactors (∏ p in s, p) = s := by
  have hn : ∏ p in s, p ≠ 0 := prod_ne_zero_iff.2 fun p hp ↦ (hs _ hp).ne_zero
  

Proof state:
s : Finset ℕ
m n p : ℕ
hs : ∀ p ∈ s, Prime p
hn : ∏ p in s, p ≠ 0
⊢ (∏ p in s, p).primeFactors = s

Next tactic:
ext p
lemma primeFactors_prod (hs : ∀ p ∈ s, p.Prime) : primeFactors (∏ p in s, p) = s := by
  have hn : ∏ p in s, p ≠ 0 := prod_ne_zero_iff.2 fun p hp ↦ (hs _ hp).ne_zero
  ext p
  

Proof state:
case a
s : Finset ℕ
m n p✝ : ℕ
hs : ∀ p ∈ s, Prime p
hn : ∏ p in s, p ≠ 0
p : ℕ
⊢ p ∈ (∏ p in s, p).primeFactors ↔ p ∈ s

Next tactic:
rw [mem_primeFactors_of_ne_zero hn, and_congr_right (fun hp ↦ hp.prime.dvd_finset_prod_iff _)]
lemma primeFactors_prod (hs : ∀ p ∈ s, p.Prime) : primeFactors (∏ p in s, p) = s := by
  have hn : ∏ p in s, p ≠ 0 := prod_ne_zero_iff.2 fun p hp ↦ (hs _ hp).ne_zero
  ext p
  rw [mem_primeFactors_of_ne_zero hn, and_congr_right (fun hp ↦ hp.prime.dvd_finset_prod_iff _)]
  

Proof state:
case a
s : Finset ℕ
m n p✝ : ℕ
hs : ∀ p ∈ s, Prime p
hn : ∏ p in s, p ≠ 0
p : ℕ
⊢ (Prime p ∧ ∃ a ∈ s, p ∣ a) ↔ p ∈ s

Next tactic:
refine' ⟨_, fun hp ↦ ⟨hs _ hp, _, hp, dvd_rfl⟩⟩
lemma primeFactors_prod (hs : ∀ p ∈ s, p.Prime) : primeFactors (∏ p in s, p) = s := by
  have hn : ∏ p in s, p ≠ 0 := prod_ne_zero_iff.2 fun p hp ↦ (hs _ hp).ne_zero
  ext p
  rw [mem_primeFactors_of_ne_zero hn, and_congr_right (fun hp ↦ hp.prime.dvd_finset_prod_iff _)]
  refine' ⟨_, fun hp ↦ ⟨hs _ hp, _, hp, dvd_rfl⟩⟩
  

Proof state:
case a
s : Finset ℕ
m n p✝ : ℕ
hs : ∀ p ∈ s, Prime p
hn : ∏ p in s, p ≠ 0
p : ℕ
⊢ (Prime p ∧ ∃ a ∈ s, p ∣ a) → p ∈ s

Next tactic:
rintro ⟨hp, q, hq, hpq⟩
lemma primeFactors_prod (hs : ∀ p ∈ s, p.Prime) : primeFactors (∏ p in s, p) = s := by
  have hn : ∏ p in s, p ≠ 0 := prod_ne_zero_iff.2 fun p hp ↦ (hs _ hp).ne_zero
  ext p
  rw [mem_primeFactors_of_ne_zero hn, and_congr_right (fun hp ↦ hp.prime.dvd_finset_prod_iff _)]
  refine' ⟨_, fun hp ↦ ⟨hs _ hp, _, hp, dvd_rfl⟩⟩
  rintro ⟨hp, q, hq, hpq⟩
  

Proof state:
case a.intro.intro.intro
s : Finset ℕ
m n p✝ : ℕ
hs : ∀ p ∈ s, Prime p
hn : ∏ p in s, p ≠ 0
p : ℕ
hp : Prime p
q : ℕ
hq : q ∈ s
hpq : p ∣ q
⊢ p ∈ s

Next tactic:
rwa [← ((hs _ hq).dvd_iff_eq hp.ne_one).1 hpq]
lemma primeFactors_div_gcd (hm : Squarefree m) (hn : n ≠ 0) :
    primeFactors (m / m.gcd n) = primeFactors m \ primeFactors n := by
  

Proof state:
s : Finset ℕ
m n p : ℕ
hm : Squarefree m
hn : n ≠ 0
⊢ (m / gcd m n).primeFactors = m.primeFactors \ n.primeFactors

Next tactic:
ext p
lemma primeFactors_div_gcd (hm : Squarefree m) (hn : n ≠ 0) :
    primeFactors (m / m.gcd n) = primeFactors m \ primeFactors n := by
  ext p
  

Proof state:
case a
s : Finset ℕ
m n p✝ : ℕ
hm : Squarefree m
hn : n ≠ 0
p : ℕ
⊢ p ∈ (m / gcd m n).primeFactors ↔ p ∈ m.primeFactors \ n.primeFactors

Next tactic:
have : m / m.gcd n ≠ 0 :=
    (Nat.div_ne_zero_iff $ gcd_ne_zero_right hn).2 $ gcd_le_left _ hm.ne_zero.bot_lt
lemma primeFactors_div_gcd (hm : Squarefree m) (hn : n ≠ 0) :
    primeFactors (m / m.gcd n) = primeFactors m \ primeFactors n := by
  ext p
  have : m / m.gcd n ≠ 0 :=
    (Nat.div_ne_zero_iff $ gcd_ne_zero_right hn).2 $ gcd_le_left _ hm.ne_zero.bot_lt
  

Proof state:
case a
s : Finset ℕ
m n p✝ : ℕ
hm : Squarefree m
hn : n ≠ 0
p : ℕ
this : m / gcd m n ≠ 0
⊢ p ∈ (m / gcd m n).primeFactors ↔ p ∈ m.primeFactors \ n.primeFactors

Next tactic:
simp only [mem_primeFactors, ne_eq, this, not_false_eq_true, and_true, not_and, mem_sdiff,
    hm.ne_zero, hn, dvd_div_iff (gcd_dvd_left _ _)]
lemma primeFactors_div_gcd (hm : Squarefree m) (hn : n ≠ 0) :
    primeFactors (m / m.gcd n) = primeFactors m \ primeFactors n := by
  ext p
  have : m / m.gcd n ≠ 0 :=
    (Nat.div_ne_zero_iff $ gcd_ne_zero_right hn).2 $ gcd_le_left _ hm.ne_zero.bot_lt
  simp only [mem_primeFactors, ne_eq, this, not_false_eq_true, and_true, not_and, mem_sdiff,
    hm.ne_zero, hn, dvd_div_iff (gcd_dvd_left _ _)]
  

Proof state:
case a
s : Finset ℕ
m n p✝ : ℕ
hm : Squarefree m
hn : n ≠ 0
p : ℕ
this : m / gcd m n ≠ 0
⊢ Prime p ∧ gcd m n * p ∣ m ↔ (Prime p ∧ p ∣ m) ∧ (Prime p → ¬p ∣ n)

Next tactic:
refine ⟨fun hp ↦ ⟨⟨hp.1, dvd_of_mul_left_dvd hp.2⟩, fun _ hpn ↦ hp.1.not_unit $ hm _ $
    (mul_dvd_mul_right (dvd_gcd (dvd_of_mul_left_dvd hp.2) hpn) _).trans hp.2⟩, fun hp ↦
      ⟨hp.1.1, Coprime.mul_dvd_of_dvd_of_dvd ?_ (gcd_dvd_left _ _) hp.1.2⟩⟩