l3lab/ntp-mathlib huggingface dataset:
theorem gcd_eq_one_iff_coprime {a b : ℤ} : Int.gcd a b = 1 ↔ IsCoprime a b := by
  constructor
  · intro hg
    obtain ⟨ua, -, ha⟩ := exists_unit_of_abs a
    obtain ⟨ub, -, hb⟩ := exists_unit_of_abs b
    use Nat.gcdA (Int.natAbs a) (Int.natAbs b) * ua, Nat.gcdB (Int.natAbs a) (Int.natAbs b) * ub
    rw [mul_assoc, ← ha, mul_assoc, ← hb, mul_comm, mul_comm _ (Int.natAbs b : ℤ), ←
      Nat.gcd_eq_gcd_ab, ← gcd_eq_natAbs, hg, Int.ofNat_one]
  · rintro ⟨r, s, h⟩
    by_contra hg
    obtain ⟨p, ⟨hp, ha, hb⟩⟩ := Nat.Prime.not_coprime_iff_dvd.mp hg
    

Proof state:
case mpr.intro.intro.intro.intro.intro
a b r s : ℤ
h : r * a + s * b = 1
hg : ¬gcd a b = 1
p : ℕ
hp : Nat.Prime p
ha : p ∣ natAbs a
hb : p ∣ natAbs b
⊢ False

Next tactic:
apply Nat.Prime.not_dvd_one hp
theorem gcd_eq_one_iff_coprime {a b : ℤ} : Int.gcd a b = 1 ↔ IsCoprime a b := by
  constructor
  · intro hg
    obtain ⟨ua, -, ha⟩ := exists_unit_of_abs a
    obtain ⟨ub, -, hb⟩ := exists_unit_of_abs b
    use Nat.gcdA (Int.natAbs a) (Int.natAbs b) * ua, Nat.gcdB (Int.natAbs a) (Int.natAbs b) * ub
    rw [mul_assoc, ← ha, mul_assoc, ← hb, mul_comm, mul_comm _ (Int.natAbs b : ℤ), ←
      Nat.gcd_eq_gcd_ab, ← gcd_eq_natAbs, hg, Int.ofNat_one]
  · rintro ⟨r, s, h⟩
    by_contra hg
    obtain ⟨p, ⟨hp, ha, hb⟩⟩ := Nat.Prime.not_coprime_iff_dvd.mp hg
    apply Nat.Prime.not_dvd_one hp
    

Proof state:
case mpr.intro.intro.intro.intro.intro
a b r s : ℤ
h : r * a + s * b = 1
hg : ¬gcd a b = 1
p : ℕ
hp : Nat.Prime p
ha : p ∣ natAbs a
hb : p ∣ natAbs b
⊢ p ∣ 1

Next tactic:
rw [← coe_nat_dvd, Int.ofNat_one, ← h]
theorem gcd_eq_one_iff_coprime {a b : ℤ} : Int.gcd a b = 1 ↔ IsCoprime a b := by
  constructor
  · intro hg
    obtain ⟨ua, -, ha⟩ := exists_unit_of_abs a
    obtain ⟨ub, -, hb⟩ := exists_unit_of_abs b
    use Nat.gcdA (Int.natAbs a) (Int.natAbs b) * ua, Nat.gcdB (Int.natAbs a) (Int.natAbs b) * ub
    rw [mul_assoc, ← ha, mul_assoc, ← hb, mul_comm, mul_comm _ (Int.natAbs b : ℤ), ←
      Nat.gcd_eq_gcd_ab, ← gcd_eq_natAbs, hg, Int.ofNat_one]
  · rintro ⟨r, s, h⟩
    by_contra hg
    obtain ⟨p, ⟨hp, ha, hb⟩⟩ := Nat.Prime.not_coprime_iff_dvd.mp hg
    apply Nat.Prime.not_dvd_one hp
    rw [← coe_nat_dvd, Int.ofNat_one, ← h]
    

Proof state:
case mpr.intro.intro.intro.intro.intro
a b r s : ℤ
h : r * a + s * b = 1
hg : ¬gcd a b = 1
p : ℕ
hp : Nat.Prime p
ha : p ∣ natAbs a
hb : p ∣ natAbs b
⊢ ↑p ∣ r * a + s * b

Next tactic:
exact dvd_add ((coe_nat_dvd_left.mpr ha).mul_left _) ((coe_nat_dvd_left.mpr hb).mul_left _)
theorem coprime_iff_nat_coprime {a b : ℤ} : IsCoprime a b ↔ Nat.Coprime a.natAbs b.natAbs := by
  

Proof state:
a b : ℤ
⊢ IsCoprime a b ↔ Nat.Coprime (natAbs a) (natAbs b)

Next tactic:
rw [← gcd_eq_one_iff_coprime, Nat.coprime_iff_gcd_eq_one, gcd_eq_natAbs]
/-- If `gcd a (m * n) ≠ 1`, then `gcd a m ≠ 1` or `gcd a n ≠ 1`. -/
theorem gcd_ne_one_iff_gcd_mul_right_ne_one {a : ℤ} {m n : ℕ} :
    a.gcd (m * n) ≠ 1 ↔ a.gcd m ≠ 1 ∨ a.gcd n ≠ 1 := by
  

Proof state:
a : ℤ
m n : ℕ
⊢ gcd a (↑m * ↑n) ≠ 1 ↔ gcd a ↑m ≠ 1 ∨ gcd a ↑n ≠ 1

Next tactic:
simp only [gcd_eq_one_iff_coprime, ← not_and_or, not_iff_not, IsCoprime.mul_right_iff]
theorem sq_of_gcd_eq_one {a b c : ℤ} (h : Int.gcd a b = 1) (heq : a * b = c ^ 2) :
    ∃ a0 : ℤ, a = a0 ^ 2 ∨ a = -a0 ^ 2 := by
  

Proof state:
a b c : ℤ
h : gcd a b = 1
heq : a * b = c ^ 2
⊢ ∃ a0, a = a0 ^ 2 ∨ a = -a0 ^ 2

Next tactic:
have h' : IsUnit (GCDMonoid.gcd a b) := by
    rw [← coe_gcd, h, Int.ofNat_one]
    exact isUnit_one
theorem sq_of_gcd_eq_one {a b c : ℤ} (h : Int.gcd a b = 1) (heq : a * b = c ^ 2) :
    ∃ a0 : ℤ, a = a0 ^ 2 ∨ a = -a0 ^ 2 := by
  have h' : IsUnit (GCDMonoid.gcd a b) := by
    

Proof state:
a b c : ℤ
h : gcd a b = 1
heq : a * b = c ^ 2
⊢ IsUnit (GCDMonoid.gcd a b)

Next tactic:
rw [← coe_gcd, h, Int.ofNat_one]
theorem sq_of_gcd_eq_one {a b c : ℤ} (h : Int.gcd a b = 1) (heq : a * b = c ^ 2) :
    ∃ a0 : ℤ, a = a0 ^ 2 ∨ a = -a0 ^ 2 := by
  have h' : IsUnit (GCDMonoid.gcd a b) := by
    rw [← coe_gcd, h, Int.ofNat_one]
    

Proof state:
a b c : ℤ
h : gcd a b = 1
heq : a * b = c ^ 2
⊢ IsUnit 1

Next tactic:
exact isUnit_one
theorem sq_of_gcd_eq_one {a b c : ℤ} (h : Int.gcd a b = 1) (heq : a * b = c ^ 2) :
    ∃ a0 : ℤ, a = a0 ^ 2 ∨ a = -a0 ^ 2 := by
  have h' : IsUnit (GCDMonoid.gcd a b) := by
    rw [← coe_gcd, h, Int.ofNat_one]
    exact isUnit_one
  

Proof state:
a b c : ℤ
h : gcd a b = 1
heq : a * b = c ^ 2
h' : IsUnit (GCDMonoid.gcd a b)
⊢ ∃ a0, a = a0 ^ 2 ∨ a = -a0 ^ 2

Next tactic:
obtain ⟨d, ⟨u, hu⟩⟩ := exists_associated_pow_of_mul_eq_pow h' heq
theorem sq_of_gcd_eq_one {a b c : ℤ} (h : Int.gcd a b = 1) (heq : a * b = c ^ 2) :
    ∃ a0 : ℤ, a = a0 ^ 2 ∨ a = -a0 ^ 2 := by
  have h' : IsUnit (GCDMonoid.gcd a b) := by
    rw [← coe_gcd, h, Int.ofNat_one]
    exact isUnit_one
  obtain ⟨d, ⟨u, hu⟩⟩ := exists_associated_pow_of_mul_eq_pow h' heq
  

Proof state:
case intro.intro
a b c : ℤ
h : gcd a b = 1
heq : a * b = c ^ 2
h' : IsUnit (GCDMonoid.gcd a b)
d : ℤ
u : ℤˣ
hu : d ^ 2 * ↑u = a
⊢ ∃ a0, a = a0 ^ 2 ∨ a = -a0 ^ 2

Next tactic:
use d
theorem sq_of_gcd_eq_one {a b c : ℤ} (h : Int.gcd a b = 1) (heq : a * b = c ^ 2) :
    ∃ a0 : ℤ, a = a0 ^ 2 ∨ a = -a0 ^ 2 := by
  have h' : IsUnit (GCDMonoid.gcd a b) := by
    rw [← coe_gcd, h, Int.ofNat_one]
    exact isUnit_one
  obtain ⟨d, ⟨u, hu⟩⟩ := exists_associated_pow_of_mul_eq_pow h' heq
  use d
  

Proof state:
case h
a b c : ℤ
h : gcd a b = 1
heq : a * b = c ^ 2
h' : IsUnit (GCDMonoid.gcd a b)
d : ℤ
u : ℤˣ
hu : d ^ 2 * ↑u = a
⊢ a = d ^ 2 ∨ a = -d ^ 2

Next tactic:
rw [← hu]
theorem sq_of_gcd_eq_one {a b c : ℤ} (h : Int.gcd a b = 1) (heq : a * b = c ^ 2) :
    ∃ a0 : ℤ, a = a0 ^ 2 ∨ a = -a0 ^ 2 := by
  have h' : IsUnit (GCDMonoid.gcd a b) := by
    rw [← coe_gcd, h, Int.ofNat_one]
    exact isUnit_one
  obtain ⟨d, ⟨u, hu⟩⟩ := exists_associated_pow_of_mul_eq_pow h' heq
  use d
  rw [← hu]
  

Proof state:
case h
a b c : ℤ
h : gcd a b = 1
heq : a * b = c ^ 2
h' : IsUnit (GCDMonoid.gcd a b)
d : ℤ
u : ℤˣ
hu : d ^ 2 * ↑u = a
⊢ d ^ 2 * ↑u = d ^ 2 ∨ d ^ 2 * ↑u = -d ^ 2

Next tactic:
cases' Int.units_eq_one_or u with hu' hu'
theorem sq_of_gcd_eq_one {a b c : ℤ} (h : Int.gcd a b = 1) (heq : a * b = c ^ 2) :
    ∃ a0 : ℤ, a = a0 ^ 2 ∨ a = -a0 ^ 2 := by
  have h' : IsUnit (GCDMonoid.gcd a b) := by
    rw [← coe_gcd, h, Int.ofNat_one]
    exact isUnit_one
  obtain ⟨d, ⟨u, hu⟩⟩ := exists_associated_pow_of_mul_eq_pow h' heq
  use d
  rw [← hu]
  cases' Int.units_eq_one_or u with hu' hu' <;>
    · 

Proof state:
case h.inl
a b c : ℤ
h : gcd a b = 1
heq : a * b = c ^ 2
h' : IsUnit (GCDMonoid.gcd a b)
d : ℤ
u : ℤˣ
hu : d ^ 2 * ↑u = a
hu' : u = 1
⊢ d ^ 2 * ↑u = d ^ 2 ∨ d ^ 2 * ↑u = -d ^ 2

Next tactic:
rw [hu']
theorem sq_of_gcd_eq_one {a b c : ℤ} (h : Int.gcd a b = 1) (heq : a * b = c ^ 2) :
    ∃ a0 : ℤ, a = a0 ^ 2 ∨ a = -a0 ^ 2 := by
  have h' : IsUnit (GCDMonoid.gcd a b) := by
    rw [← coe_gcd, h, Int.ofNat_one]
    exact isUnit_one
  obtain ⟨d, ⟨u, hu⟩⟩ := exists_associated_pow_of_mul_eq_pow h' heq
  use d
  rw [← hu]
  cases' Int.units_eq_one_or u with hu' hu' <;>
    · rw [hu']
      

Proof state:
case h.inl
a b c : ℤ
h : gcd a b = 1
heq : a * b = c ^ 2
h' : IsUnit (GCDMonoid.gcd a b)
d : ℤ
u : ℤˣ
hu : d ^ 2 * ↑u = a
hu' : u = 1
⊢ d ^ 2 * ↑1 = d ^ 2 ∨ d ^ 2 * ↑1 = -d ^ 2

Next tactic:
simp
theorem sq_of_gcd_eq_one {a b c : ℤ} (h : Int.gcd a b = 1) (heq : a * b = c ^ 2) :
    ∃ a0 : ℤ, a = a0 ^ 2 ∨ a = -a0 ^ 2 := by
  have h' : IsUnit (GCDMonoid.gcd a b) := by
    rw [← coe_gcd, h, Int.ofNat_one]
    exact isUnit_one
  obtain ⟨d, ⟨u, hu⟩⟩ := exists_associated_pow_of_mul_eq_pow h' heq
  use d
  rw [← hu]
  cases' Int.units_eq_one_or u with hu' hu' <;>
    · 

Proof state:
case h.inr
a b c : ℤ
h : gcd a b = 1
heq : a * b = c ^ 2
h' : IsUnit (GCDMonoid.gcd a b)
d : ℤ
u : ℤˣ
hu : d ^ 2 * ↑u = a
hu' : u = -1
⊢ d ^ 2 * ↑u = d ^ 2 ∨ d ^ 2 * ↑u = -d ^ 2

Next tactic:
rw [hu']
theorem sq_of_gcd_eq_one {a b c : ℤ} (h : Int.gcd a b = 1) (heq : a * b = c ^ 2) :
    ∃ a0 : ℤ, a = a0 ^ 2 ∨ a = -a0 ^ 2 := by
  have h' : IsUnit (GCDMonoid.gcd a b) := by
    rw [← coe_gcd, h, Int.ofNat_one]
    exact isUnit_one
  obtain ⟨d, ⟨u, hu⟩⟩ := exists_associated_pow_of_mul_eq_pow h' heq
  use d
  rw [← hu]
  cases' Int.units_eq_one_or u with hu' hu' <;>
    · rw [hu']
      

Proof state:
case h.inr
a b c : ℤ
h : gcd a b = 1
heq : a * b = c ^ 2
h' : IsUnit (GCDMonoid.gcd a b)
d : ℤ
u : ℤˣ
hu : d ^ 2 * ↑u = a
hu' : u = -1
⊢ d ^ 2 * ↑(-1) = d ^ 2 ∨ d ^ 2 * ↑(-1) = -d ^ 2

Next tactic:
simp
theorem natAbs_euclideanDomain_gcd (a b : ℤ) :
    Int.natAbs (EuclideanDomain.gcd a b) = Int.gcd a b := by
  

Proof state:
a b : ℤ
⊢ natAbs (EuclideanDomain.gcd a b) = gcd a b

Next tactic:
apply Nat.dvd_antisymm
theorem natAbs_euclideanDomain_gcd (a b : ℤ) :
    Int.natAbs (EuclideanDomain.gcd a b) = Int.gcd a b := by
  apply Nat.dvd_antisymm <;> 

Proof state:
case a
a b : ℤ
⊢ natAbs (EuclideanDomain.gcd a b) ∣ gcd a b

Next tactic:
rw [← Int.coe_nat_dvd]
theorem natAbs_euclideanDomain_gcd (a b : ℤ) :
    Int.natAbs (EuclideanDomain.gcd a b) = Int.gcd a b := by
  apply Nat.dvd_antisymm <;> 

Proof state:
case a
a b : ℤ
⊢ gcd a b ∣ natAbs (EuclideanDomain.gcd a b)

Next tactic:
rw [← Int.coe_nat_dvd]
theorem natAbs_euclideanDomain_gcd (a b : ℤ) :
    Int.natAbs (EuclideanDomain.gcd a b) = Int.gcd a b := by
  apply Nat.dvd_antisymm <;> rw [← Int.coe_nat_dvd]
  · 

Proof state:
case a
a b : ℤ
⊢ ↑(natAbs (EuclideanDomain.gcd a b)) ∣ ↑(gcd a b)

Next tactic:
rw [Int.natAbs_dvd]
theorem natAbs_euclideanDomain_gcd (a b : ℤ) :
    Int.natAbs (EuclideanDomain.gcd a b) = Int.gcd a b := by
  apply Nat.dvd_antisymm <;> rw [← Int.coe_nat_dvd]
  · rw [Int.natAbs_dvd]
    

Proof state:
case a
a b : ℤ
⊢ EuclideanDomain.gcd a b ∣ ↑(gcd a b)

Next tactic:
exact Int.dvd_gcd (EuclideanDomain.gcd_dvd_left _ _) (EuclideanDomain.gcd_dvd_right _ _)
theorem natAbs_euclideanDomain_gcd (a b : ℤ) :
    Int.natAbs (EuclideanDomain.gcd a b) = Int.gcd a b := by
  apply Nat.dvd_antisymm <;> rw [← Int.coe_nat_dvd]
  · rw [Int.natAbs_dvd]
    exact Int.dvd_gcd (EuclideanDomain.gcd_dvd_left _ _) (EuclideanDomain.gcd_dvd_right _ _)
  · 

Proof state:
case a
a b : ℤ
⊢ ↑(gcd a b) ∣ ↑(natAbs (EuclideanDomain.gcd a b))

Next tactic:
rw [Int.dvd_natAbs]
theorem natAbs_euclideanDomain_gcd (a b : ℤ) :
    Int.natAbs (EuclideanDomain.gcd a b) = Int.gcd a b := by
  apply Nat.dvd_antisymm <;> rw [← Int.coe_nat_dvd]
  · rw [Int.natAbs_dvd]
    exact Int.dvd_gcd (EuclideanDomain.gcd_dvd_left _ _) (EuclideanDomain.gcd_dvd_right _ _)
  · rw [Int.dvd_natAbs]
    

Proof state:
case a
a b : ℤ
⊢ ↑(gcd a b) ∣ EuclideanDomain.gcd a b

Next tactic:
exact EuclideanDomain.dvd_gcd (Int.gcd_dvd_left _ _) (Int.gcd_dvd_right _ _)
/-- Maps an associate class of integers consisting of `-n, n` to `n : ℕ` -/
def associatesIntEquivNat : Associates ℤ ≃ ℕ := by
  

Proof state:
⊢ Associates ℤ ≃ ℕ

Next tactic:
refine' ⟨fun z => z.out.natAbs, fun n => Associates.mk n, _, _⟩
/-- Maps an associate class of integers consisting of `-n, n` to `n : ℕ` -/
def associatesIntEquivNat : Associates ℤ ≃ ℕ := by
  refine' ⟨fun z => z.out.natAbs, fun n => Associates.mk n, _, _⟩
  · 

Proof state:
case refine'_1
⊢ Function.LeftInverse (fun n => Associates.mk ↑n) fun z => Int.natAbs (Associates.out z)

Next tactic:
refine' fun a =>
      Quotient.inductionOn a fun a =>
        Associates.mk_eq_mk_iff_associated.2 <| Associated.symm <| ⟨normUnit a, _⟩
/-- Maps an associate class of integers consisting of `-n, n` to `n : ℕ` -/
def associatesIntEquivNat : Associates ℤ ≃ ℕ := by
  refine' ⟨fun z => z.out.natAbs, fun n => Associates.mk n, _, _⟩
  · refine' fun a =>
      Quotient.inductionOn a fun a =>
        Associates.mk_eq_mk_iff_associated.2 <| Associated.symm <| ⟨normUnit a, _⟩
    

Proof state:
case refine'_1
a✝ : Associates ℤ
a : ℤ
⊢ a * ↑(normUnit a) = ↑((fun z => Int.natAbs (Associates.out z)) ⟦a⟧)

Next tactic:
simp [Int.abs_eq_normalize]
/-- Maps an associate class of integers consisting of `-n, n` to `n : ℕ` -/
def associatesIntEquivNat : Associates ℤ ≃ ℕ := by
  refine' ⟨fun z => z.out.natAbs, fun n => Associates.mk n, _, _⟩
  · refine' fun a =>
      Quotient.inductionOn a fun a =>
        Associates.mk_eq_mk_iff_associated.2 <| Associated.symm <| ⟨normUnit a, _⟩
    simp [Int.abs_eq_normalize]
  · 

Proof state:
case refine'_2
⊢ Function.RightInverse (fun n => Associates.mk ↑n) fun z => Int.natAbs (Associates.out z)

Next tactic:
intro n
/-- Maps an associate class of integers consisting of `-n, n` to `n : ℕ` -/
def associatesIntEquivNat : Associates ℤ ≃ ℕ := by
  refine' ⟨fun z => z.out.natAbs, fun n => Associates.mk n, _, _⟩
  · refine' fun a =>
      Quotient.inductionOn a fun a =>
        Associates.mk_eq_mk_iff_associated.2 <| Associated.symm <| ⟨normUnit a, _⟩
    simp [Int.abs_eq_normalize]
  · intro n
    

Proof state:
case refine'_2
n : ℕ
⊢ (fun z => Int.natAbs (Associates.out z)) ((fun n => Associates.mk ↑n) n) = n

Next tactic:
dsimp
/-- Maps an associate class of integers consisting of `-n, n` to `n : ℕ` -/
def associatesIntEquivNat : Associates ℤ ≃ ℕ := by
  refine' ⟨fun z => z.out.natAbs, fun n => Associates.mk n, _, _⟩
  · refine' fun a =>
      Quotient.inductionOn a fun a =>
        Associates.mk_eq_mk_iff_associated.2 <| Associated.symm <| ⟨normUnit a, _⟩
    simp [Int.abs_eq_normalize]
  · intro n
    dsimp
    

Proof state:
case refine'_2
n : ℕ
⊢ Int.natAbs (↑n * ↑(normUnit ↑n)) = n

Next tactic:
rw [← normalize_apply, ← Int.abs_eq_normalize, Int.natAbs_abs, Int.natAbs_ofNat]
theorem Int.Prime.dvd_mul {m n : ℤ} {p : ℕ} (hp : Nat.Prime p) (h : (p : ℤ) ∣ m * n) :
    p ∣ m.natAbs ∨ p ∣ n.natAbs := by
  

Proof state:
m n : ℤ
p : ℕ
hp : Nat.Prime p
h : ↑p ∣ m * n
⊢ p ∣ natAbs m ∨ p ∣ natAbs n

Next tactic:
rwa [← hp.dvd_mul, ← Int.natAbs_mul, ← Int.coe_nat_dvd_left]
theorem Int.Prime.dvd_mul' {m n : ℤ} {p : ℕ} (hp : Nat.Prime p) (h : (p : ℤ) ∣ m * n) :
    (p : ℤ) ∣ m ∨ (p : ℤ) ∣ n := by
  

Proof state:
m n : ℤ
p : ℕ
hp : Nat.Prime p
h : ↑p ∣ m * n
⊢ ↑p ∣ m ∨ ↑p ∣ n

Next tactic:
rw [Int.coe_nat_dvd_left, Int.coe_nat_dvd_left]
theorem Int.Prime.dvd_mul' {m n : ℤ} {p : ℕ} (hp : Nat.Prime p) (h : (p : ℤ) ∣ m * n) :
    (p : ℤ) ∣ m ∨ (p : ℤ) ∣ n := by
  rw [Int.coe_nat_dvd_left, Int.coe_nat_dvd_left]
  

Proof state:
m n : ℤ
p : ℕ
hp : Nat.Prime p
h : ↑p ∣ m * n
⊢ p ∣ natAbs m ∨ p ∣ natAbs n

Next tactic:
exact Int.Prime.dvd_mul hp h
theorem Int.Prime.dvd_pow {n : ℤ} {k p : ℕ} (hp : Nat.Prime p) (h : (p : ℤ) ∣ n ^ k) :
    p ∣ n.natAbs := by
  

Proof state:
n : ℤ
k p : ℕ
hp : Nat.Prime p
h : ↑p ∣ n ^ k
⊢ p ∣ natAbs n

Next tactic:
rw [Int.coe_nat_dvd_left, Int.natAbs_pow] at h
theorem Int.Prime.dvd_pow {n : ℤ} {k p : ℕ} (hp : Nat.Prime p) (h : (p : ℤ) ∣ n ^ k) :
    p ∣ n.natAbs := by
  rw [Int.coe_nat_dvd_left, Int.natAbs_pow] at h
  

Proof state:
n : ℤ
k p : ℕ
hp : Nat.Prime p
h : p ∣ natAbs n ^ k
⊢ p ∣ natAbs n

Next tactic:
exact hp.dvd_of_dvd_pow h
theorem Int.Prime.dvd_pow' {n : ℤ} {k p : ℕ} (hp : Nat.Prime p) (h : (p : ℤ) ∣ n ^ k) :
    (p : ℤ) ∣ n := by
  

Proof state:
n : ℤ
k p : ℕ
hp : Nat.Prime p
h : ↑p ∣ n ^ k
⊢ ↑p ∣ n

Next tactic:
rw [Int.coe_nat_dvd_left]
theorem Int.Prime.dvd_pow' {n : ℤ} {k p : ℕ} (hp : Nat.Prime p) (h : (p : ℤ) ∣ n ^ k) :
    (p : ℤ) ∣ n := by
  rw [Int.coe_nat_dvd_left]
  

Proof state:
n : ℤ
k p : ℕ
hp : Nat.Prime p
h : ↑p ∣ n ^ k
⊢ p ∣ natAbs n

Next tactic:
exact Int.Prime.dvd_pow hp h
theorem prime_two_or_dvd_of_dvd_two_mul_pow_self_two {m : ℤ} {p : ℕ} (hp : Nat.Prime p)
    (h : (p : ℤ) ∣ 2 * m ^ 2) : p = 2 ∨ p ∣ Int.natAbs m := by
  

Proof state:
m : ℤ
p : ℕ
hp : Nat.Prime p
h : ↑p ∣ 2 * m ^ 2
⊢ p = 2 ∨ p ∣ Int.natAbs m

Next tactic:
cases' Int.Prime.dvd_mul hp h with hp2 hpp
theorem prime_two_or_dvd_of_dvd_two_mul_pow_self_two {m : ℤ} {p : ℕ} (hp : Nat.Prime p)
    (h : (p : ℤ) ∣ 2 * m ^ 2) : p = 2 ∨ p ∣ Int.natAbs m := by
  cases' Int.Prime.dvd_mul hp h with hp2 hpp
  · 

Proof state:
case inl
m : ℤ
p : ℕ
hp : Nat.Prime p
h : ↑p ∣ 2 * m ^ 2
hp2 : p ∣ Int.natAbs 2
⊢ p = 2 ∨ p ∣ Int.natAbs m

Next tactic:
apply Or.intro_left
theorem prime_two_or_dvd_of_dvd_two_mul_pow_self_two {m : ℤ} {p : ℕ} (hp : Nat.Prime p)
    (h : (p : ℤ) ∣ 2 * m ^ 2) : p = 2 ∨ p ∣ Int.natAbs m := by
  cases' Int.Prime.dvd_mul hp h with hp2 hpp
  · apply Or.intro_left
    

Proof state:
case inl.h
m : ℤ
p : ℕ
hp : Nat.Prime p
h : ↑p ∣ 2 * m ^ 2
hp2 : p ∣ Int.natAbs 2
⊢ p = 2

Next tactic:
exact le_antisymm (Nat.le_of_dvd zero_lt_two hp2) (Nat.Prime.two_le hp)
theorem prime_two_or_dvd_of_dvd_two_mul_pow_self_two {m : ℤ} {p : ℕ} (hp : Nat.Prime p)
    (h : (p : ℤ) ∣ 2 * m ^ 2) : p = 2 ∨ p ∣ Int.natAbs m := by
  cases' Int.Prime.dvd_mul hp h with hp2 hpp
  · apply Or.intro_left
    exact le_antisymm (Nat.le_of_dvd zero_lt_two hp2) (Nat.Prime.two_le hp)
  · 

Proof state:
case inr
m : ℤ
p : ℕ
hp : Nat.Prime p
h : ↑p ∣ 2 * m ^ 2
hpp : p ∣ Int.natAbs (m ^ 2)
⊢ p = 2 ∨ p ∣ Int.natAbs m

Next tactic:
apply Or.intro_right
theorem prime_two_or_dvd_of_dvd_two_mul_pow_self_two {m : ℤ} {p : ℕ} (hp : Nat.Prime p)
    (h : (p : ℤ) ∣ 2 * m ^ 2) : p = 2 ∨ p ∣ Int.natAbs m := by
  cases' Int.Prime.dvd_mul hp h with hp2 hpp
  · apply Or.intro_left
    exact le_antisymm (Nat.le_of_dvd zero_lt_two hp2) (Nat.Prime.two_le hp)
  · apply Or.intro_right
    

Proof state:
case inr.h
m : ℤ
p : ℕ
hp : Nat.Prime p
h : ↑p ∣ 2 * m ^ 2
hpp : p ∣ Int.natAbs (m ^ 2)
⊢ p ∣ Int.natAbs m

Next tactic:
rw [sq, Int.natAbs_mul] at hpp
theorem prime_two_or_dvd_of_dvd_two_mul_pow_self_two {m : ℤ} {p : ℕ} (hp : Nat.Prime p)
    (h : (p : ℤ) ∣ 2 * m ^ 2) : p = 2 ∨ p ∣ Int.natAbs m := by
  cases' Int.Prime.dvd_mul hp h with hp2 hpp
  · apply Or.intro_left
    exact le_antisymm (Nat.le_of_dvd zero_lt_two hp2) (Nat.Prime.two_le hp)
  · apply Or.intro_right
    rw [sq, Int.natAbs_mul] at hpp
    

Proof state:
case inr.h
m : ℤ
p : ℕ
hp : Nat.Prime p
h : ↑p ∣ 2 * m ^ 2
hpp : p ∣ Int.natAbs m * Int.natAbs m
⊢ p ∣ Int.natAbs m

Next tactic:
exact or_self_iff.mp ((Nat.Prime.dvd_mul hp).mp hpp)
theorem Int.exists_prime_and_dvd {n : ℤ} (hn : n.natAbs ≠ 1) : ∃ p, Prime p ∧ p ∣ n := by
  

Proof state:
n : ℤ
hn : natAbs n ≠ 1
⊢ ∃ p, Prime p ∧ p ∣ n

Next tactic:
obtain ⟨p, pp, pd⟩ := Nat.exists_prime_and_dvd hn
theorem Int.exists_prime_and_dvd {n : ℤ} (hn : n.natAbs ≠ 1) : ∃ p, Prime p ∧ p ∣ n := by
  obtain ⟨p, pp, pd⟩ := Nat.exists_prime_and_dvd hn
  

Proof state:
case intro.intro
n : ℤ
hn : natAbs n ≠ 1
p : ℕ
pp : Nat.Prime p
pd : p ∣ natAbs n
⊢ ∃ p, Prime p ∧ p ∣ n

Next tactic:
exact ⟨p, Nat.prime_iff_prime_int.mp pp, Int.coe_nat_dvd_left.mpr pd⟩
theorem Nat.factors_eq {n : ℕ} : normalizedFactors n = n.factors := by
  

Proof state:
n : ℕ
⊢ normalizedFactors n = ↑(factors n)

Next tactic:
cases n
theorem Nat.factors_eq {n : ℕ} : normalizedFactors n = n.factors := by
  cases n
  

Proof state:
case zero
⊢ normalizedFactors zero = ↑(factors zero)
case succ n✝ : ℕ ⊢ normalizedFactors (succ n✝) = ↑(factors (succ n✝))

Next tactic:
case zero => simp
theorem Nat.factors_eq {n : ℕ} : normalizedFactors n = n.factors := by
  cases n
  

Proof state:
⊢ normalizedFactors zero = ↑(factors zero)

Next tactic:
case zero => simp
theorem Nat.factors_eq {n : ℕ} : normalizedFactors n = n.factors := by
  cases n
  case zero => 

Proof state:
⊢ normalizedFactors zero = ↑(factors zero)

Next tactic:
simp
theorem Nat.factors_eq {n : ℕ} : normalizedFactors n = n.factors := by
  cases n
  case zero => simp
  

Proof state:
case succ
n✝ : ℕ
⊢ normalizedFactors (succ n✝) = ↑(factors (succ n✝))

Next tactic:
case succ n =>
    rw [← Multiset.rel_eq, ← associated_eq_eq]
    apply UniqueFactorizationMonoid.factors_unique irreducible_of_normalized_factor _
    · rw [Multiset.coe_prod, Nat.prod_factors n.succ_ne_zero]
      apply normalizedFactors_prod (Nat.succ_ne_zero _)
    · intro x hx
      rw [Nat.irreducible_iff_prime, ← Nat.prime_iff]
      exact Nat.prime_of_mem_factors hx
theorem Nat.factors_eq {n : ℕ} : normalizedFactors n = n.factors := by
  cases n
  case zero => simp
  

Proof state:
n : ℕ
⊢ normalizedFactors (succ n) = ↑(factors (succ n))

Next tactic:
case succ n =>
    rw [← Multiset.rel_eq, ← associated_eq_eq]
    apply UniqueFactorizationMonoid.factors_unique irreducible_of_normalized_factor _
    · rw [Multiset.coe_prod, Nat.prod_factors n.succ_ne_zero]
      apply normalizedFactors_prod (Nat.succ_ne_zero _)
    · intro x hx
      rw [Nat.irreducible_iff_prime, ← Nat.prime_iff]
      exact Nat.prime_of_mem_factors hx
theorem Nat.factors_eq {n : ℕ} : normalizedFactors n = n.factors := by
  cases n
  case zero => simp
  case succ n =>
    

Proof state:
n : ℕ
⊢ normalizedFactors (succ n) = ↑(factors (succ n))

Next tactic:
rw [← Multiset.rel_eq, ← associated_eq_eq]
theorem Nat.factors_eq {n : ℕ} : normalizedFactors n = n.factors := by
  cases n
  case zero => simp
  case succ n =>
    rw [← Multiset.rel_eq, ← associated_eq_eq]
    

Proof state:
n : ℕ
⊢ Multiset.Rel (fun x x_1 => Associated x x_1) (normalizedFactors (succ n)) ↑(factors (succ n))

Next tactic:
apply UniqueFactorizationMonoid.factors_unique irreducible_of_normalized_factor _
theorem Nat.factors_eq {n : ℕ} : normalizedFactors n = n.factors := by
  cases n
  case zero => simp
  case succ n =>
    rw [← Multiset.rel_eq, ← associated_eq_eq]
    apply UniqueFactorizationMonoid.factors_unique irreducible_of_normalized_factor _
    · 

Proof state:
n : ℕ
⊢ Associated (Multiset.prod (normalizedFactors (succ n))) (Multiset.prod ↑(factors (succ n)))

Next tactic:
rw [Multiset.coe_prod, Nat.prod_factors n.succ_ne_zero]
theorem Nat.factors_eq {n : ℕ} : normalizedFactors n = n.factors := by
  cases n
  case zero => simp
  case succ n =>
    rw [← Multiset.rel_eq, ← associated_eq_eq]
    apply UniqueFactorizationMonoid.factors_unique irreducible_of_normalized_factor _
    · rw [Multiset.coe_prod, Nat.prod_factors n.succ_ne_zero]
      

Proof state:
n : ℕ
⊢ Associated (Multiset.prod (normalizedFactors (succ n))) (succ n)

Next tactic:
apply normalizedFactors_prod (Nat.succ_ne_zero _)
theorem Nat.factors_eq {n : ℕ} : normalizedFactors n = n.factors := by
  cases n
  case zero => simp
  case succ n =>
    rw [← Multiset.rel_eq, ← associated_eq_eq]
    apply UniqueFactorizationMonoid.factors_unique irreducible_of_normalized_factor _
    · rw [Multiset.coe_prod, Nat.prod_factors n.succ_ne_zero]
      apply normalizedFactors_prod (Nat.succ_ne_zero _)
    · 

Proof state:
n : ℕ
⊢ ∀ x ∈ ↑(factors (succ n)), Irreducible x

Next tactic:
intro x hx
theorem Nat.factors_eq {n : ℕ} : normalizedFactors n = n.factors := by
  cases n
  case zero => simp
  case succ n =>
    rw [← Multiset.rel_eq, ← associated_eq_eq]
    apply UniqueFactorizationMonoid.factors_unique irreducible_of_normalized_factor _
    · rw [Multiset.coe_prod, Nat.prod_factors n.succ_ne_zero]
      apply normalizedFactors_prod (Nat.succ_ne_zero _)
    · intro x hx
      

Proof state:
n x : ℕ
hx : x ∈ ↑(factors (succ n))
⊢ Irreducible x

Next tactic:
rw [Nat.irreducible_iff_prime, ← Nat.prime_iff]
theorem Nat.factors_eq {n : ℕ} : normalizedFactors n = n.factors := by
  cases n
  case zero => simp
  case succ n =>
    rw [← Multiset.rel_eq, ← associated_eq_eq]
    apply UniqueFactorizationMonoid.factors_unique irreducible_of_normalized_factor _
    · rw [Multiset.coe_prod, Nat.prod_factors n.succ_ne_zero]
      apply normalizedFactors_prod (Nat.succ_ne_zero _)
    · intro x hx
      rw [Nat.irreducible_iff_prime, ← Nat.prime_iff]
      

Proof state:
n x : ℕ
hx : x ∈ ↑(factors (succ n))
⊢ Prime x

Next tactic:
exact Nat.prime_of_mem_factors hx
theorem Nat.factors_multiset_prod_of_irreducible {s : Multiset ℕ}
    (h : ∀ x : ℕ, x ∈ s → Irreducible x) : normalizedFactors s.prod = s := by
  

Proof state:
s : Multiset ℕ
h : ∀ x ∈ s, Irreducible x
⊢ normalizedFactors (Multiset.prod s) = s

Next tactic:
rw [← Multiset.rel_eq, ← associated_eq_eq]
theorem Nat.factors_multiset_prod_of_irreducible {s : Multiset ℕ}
    (h : ∀ x : ℕ, x ∈ s → Irreducible x) : normalizedFactors s.prod = s := by
  rw [← Multiset.rel_eq, ← associated_eq_eq]
  

Proof state:
s : Multiset ℕ
h : ∀ x ∈ s, Irreducible x
⊢ Multiset.Rel (fun x x_1 => Associated x x_1) (normalizedFactors (Multiset.prod s)) s

Next tactic:
apply
    UniqueFactorizationMonoid.factors_unique irreducible_of_normalized_factor h
      (normalizedFactors_prod _)