l3lab/ntp-mathlib huggingface dataset:
protected theorem mul_left' (h : a ≡ b [ZMOD n]) : c * a ≡ c * b [ZMOD c * n] := by
  obtain hc | rfl | hc := lt_trichotomy c 0
  · rw [← neg_modEq_neg, ← modEq_neg, ← neg_mul, ← neg_mul, ← neg_mul]
    simp only [ModEq, mul_emod_mul_of_pos _ _ (neg_pos.2 hc), h.eq]
  · simp only [zero_mul, ModEq.rfl]
  · 

Proof state:
case inr.inr
m n a b c d : ℤ
h : a ≡ b [ZMOD n]
hc : 0 < c
⊢ c * a ≡ c * b [ZMOD c * n]

Next tactic:
simp only [ModEq, mul_emod_mul_of_pos _ _ hc, h.eq]
protected theorem mul_right' (h : a ≡ b [ZMOD n]) : a * c ≡ b * c [ZMOD n * c] := by
  

Proof state:
m n a b c d : ℤ
h : a ≡ b [ZMOD n]
⊢ a * c ≡ b * c [ZMOD n * c]

Next tactic:
rw [mul_comm a, mul_comm b, mul_comm n]
protected theorem mul_right' (h : a ≡ b [ZMOD n]) : a * c ≡ b * c [ZMOD n * c] := by
  rw [mul_comm a, mul_comm b, mul_comm n]; 

Proof state:
m n a b c d : ℤ
h : a ≡ b [ZMOD n]
⊢ c * a ≡ c * b [ZMOD c * n]

Next tactic:
exact h.mul_left'
@[gcongr]
protected theorem add (h₁ : a ≡ b [ZMOD n]) (h₂ : c ≡ d [ZMOD n]) : a + c ≡ b + d [ZMOD n] :=
  modEq_iff_dvd.2 <| by
    

Proof state:
m n a b c d : ℤ
h₁ : a ≡ b [ZMOD n]
h₂ : c ≡ d [ZMOD n]
⊢ n ∣ b + d - (a + c)

Next tactic:
convert dvd_add h₁.dvd h₂.dvd using 1
@[gcongr]
protected theorem add (h₁ : a ≡ b [ZMOD n]) (h₂ : c ≡ d [ZMOD n]) : a + c ≡ b + d [ZMOD n] :=
  modEq_iff_dvd.2 <| by
    convert dvd_add h₁.dvd h₂.dvd using 1
    

Proof state:
case h.e'_4
m n a b c d : ℤ
h₁ : a ≡ b [ZMOD n]
h₂ : c ≡ d [ZMOD n]
⊢ b + d - (a + c) = b - a + (d - c)

Next tactic:
ring
protected theorem add_left_cancel (h₁ : a ≡ b [ZMOD n]) (h₂ : a + c ≡ b + d [ZMOD n]) :
    c ≡ d [ZMOD n] :=
  have : d - c = b + d - (a + c) - (b - a) := by 

Proof state:
m n a b c d : ℤ
h₁ : a ≡ b [ZMOD n]
h₂ : a + c ≡ b + d [ZMOD n]
⊢ d - c = b + d - (a + c) - (b - a)

Next tactic:
ring
protected theorem add_left_cancel (h₁ : a ≡ b [ZMOD n]) (h₂ : a + c ≡ b + d [ZMOD n]) :
    c ≡ d [ZMOD n] :=
  have : d - c = b + d - (a + c) - (b - a) := by ring
  modEq_iff_dvd.2 <| by
    

Proof state:
m n a b c d : ℤ
h₁ : a ≡ b [ZMOD n]
h₂ : a + c ≡ b + d [ZMOD n]
this : d - c = b + d - (a + c) - (b - a)
⊢ n ∣ d - c

Next tactic:
rw [this]
protected theorem add_left_cancel (h₁ : a ≡ b [ZMOD n]) (h₂ : a + c ≡ b + d [ZMOD n]) :
    c ≡ d [ZMOD n] :=
  have : d - c = b + d - (a + c) - (b - a) := by ring
  modEq_iff_dvd.2 <| by
    rw [this]
    

Proof state:
m n a b c d : ℤ
h₁ : a ≡ b [ZMOD n]
h₂ : a + c ≡ b + d [ZMOD n]
this : d - c = b + d - (a + c) - (b - a)
⊢ n ∣ b + d - (a + c) - (b - a)

Next tactic:
exact dvd_sub h₂.dvd h₁.dvd
protected theorem add_right_cancel (h₁ : c ≡ d [ZMOD n]) (h₂ : a + c ≡ b + d [ZMOD n]) :
    a ≡ b [ZMOD n] := by
  

Proof state:
m n a b c d : ℤ
h₁ : c ≡ d [ZMOD n]
h₂ : a + c ≡ b + d [ZMOD n]
⊢ a ≡ b [ZMOD n]

Next tactic:
rw [add_comm a, add_comm b] at h₂
protected theorem add_right_cancel (h₁ : c ≡ d [ZMOD n]) (h₂ : a + c ≡ b + d [ZMOD n]) :
    a ≡ b [ZMOD n] := by
  rw [add_comm a, add_comm b] at h₂
  

Proof state:
m n a b c d : ℤ
h₁ : c ≡ d [ZMOD n]
h₂ : c + a ≡ d + b [ZMOD n]
⊢ a ≡ b [ZMOD n]

Next tactic:
exact h₁.add_left_cancel h₂
@[gcongr] protected theorem neg (h : a ≡ b [ZMOD n]) : -a ≡ -b [ZMOD n] :=
  h.add_left_cancel (by 

Proof state:
m n a b c d : ℤ
h : a ≡ b [ZMOD n]
⊢ a + -a ≡ b + -b [ZMOD n]

Next tactic:
simp_rw [← sub_eq_add_neg, sub_self]
@[gcongr] protected theorem neg (h : a ≡ b [ZMOD n]) : -a ≡ -b [ZMOD n] :=
  h.add_left_cancel (by simp_rw [← sub_eq_add_neg, sub_self]; 

Proof state:
m n a b c d : ℤ
h : a ≡ b [ZMOD n]
⊢ 0 ≡ 0 [ZMOD n]

Next tactic:
rfl
@[gcongr]
protected theorem sub (h₁ : a ≡ b [ZMOD n]) (h₂ : c ≡ d [ZMOD n]) : a - c ≡ b - d [ZMOD n] := by
  

Proof state:
m n a b c d : ℤ
h₁ : a ≡ b [ZMOD n]
h₂ : c ≡ d [ZMOD n]
⊢ a - c ≡ b - d [ZMOD n]

Next tactic:
rw [sub_eq_add_neg, sub_eq_add_neg]
@[gcongr]
protected theorem sub (h₁ : a ≡ b [ZMOD n]) (h₂ : c ≡ d [ZMOD n]) : a - c ≡ b - d [ZMOD n] := by
  rw [sub_eq_add_neg, sub_eq_add_neg]
  

Proof state:
m n a b c d : ℤ
h₁ : a ≡ b [ZMOD n]
h₂ : c ≡ d [ZMOD n]
⊢ a + -c ≡ b + -d [ZMOD n]

Next tactic:
exact h₁.add h₂.neg
@[gcongr] protected theorem pow (m : ℕ) (h : a ≡ b [ZMOD n]) : a ^ m ≡ b ^ m [ZMOD n] := by
  

Proof state:
m✝ n a b c d : ℤ
m : ℕ
h : a ≡ b [ZMOD n]
⊢ a ^ m ≡ b ^ m [ZMOD n]

Next tactic:
induction' m with d hd
@[gcongr] protected theorem pow (m : ℕ) (h : a ≡ b [ZMOD n]) : a ^ m ≡ b ^ m [ZMOD n] := by
  induction' m with d hd; · 

Proof state:
case zero
m n a b c d : ℤ
h : a ≡ b [ZMOD n]
⊢ a ^ Nat.zero ≡ b ^ Nat.zero [ZMOD n]

Next tactic:
rfl
@[gcongr] protected theorem pow (m : ℕ) (h : a ≡ b [ZMOD n]) : a ^ m ≡ b ^ m [ZMOD n] := by
  induction' m with d hd; · rfl
  

Proof state:
case succ
m n a b c d✝ : ℤ
h : a ≡ b [ZMOD n]
d : ℕ
hd : a ^ d ≡ b ^ d [ZMOD n]
⊢ a ^ Nat.succ d ≡ b ^ Nat.succ d [ZMOD n]

Next tactic:
rw [pow_succ, pow_succ]
@[gcongr] protected theorem pow (m : ℕ) (h : a ≡ b [ZMOD n]) : a ^ m ≡ b ^ m [ZMOD n] := by
  induction' m with d hd; · rfl
  rw [pow_succ, pow_succ]
  

Proof state:
case succ
m n a b c d✝ : ℤ
h : a ≡ b [ZMOD n]
d : ℕ
hd : a ^ d ≡ b ^ d [ZMOD n]
⊢ a * a ^ d ≡ b * b ^ d [ZMOD n]

Next tactic:
exact h.mul hd
lemma of_mul_left (m : ℤ) (h : a ≡ b [ZMOD m * n]) : a ≡ b [ZMOD n] := by
  

Proof state:
m✝ n a b c d m : ℤ
h : a ≡ b [ZMOD m * n]
⊢ a ≡ b [ZMOD n]

Next tactic:
rw [modEq_iff_dvd] at *
lemma of_mul_left (m : ℤ) (h : a ≡ b [ZMOD m * n]) : a ≡ b [ZMOD n] := by
  rw [modEq_iff_dvd] at *; 

Proof state:
m✝ n a b c d m : ℤ
h : m * n ∣ b - a
⊢ n ∣ b - a

Next tactic:
exact (dvd_mul_left n m).trans h
/-- To cancel a common factor `c` from a `ModEq` we must divide the modulus `m` by `gcd m c`. -/
theorem cancel_right_div_gcd (hm : 0 < m) (h : a * c ≡ b * c [ZMOD m]) :
    a ≡ b [ZMOD m / gcd m c] := by
  

Proof state:
m n a b c d : ℤ
hm : 0 < m
h : a * c ≡ b * c [ZMOD m]
⊢ a ≡ b [ZMOD m / ↑(gcd m c)]

Next tactic:
letI d := gcd m c
/-- To cancel a common factor `c` from a `ModEq` we must divide the modulus `m` by `gcd m c`. -/
theorem cancel_right_div_gcd (hm : 0 < m) (h : a * c ≡ b * c [ZMOD m]) :
    a ≡ b [ZMOD m / gcd m c] := by
  letI d := gcd m c
  

Proof state:
m n a b c d✝ : ℤ
hm : 0 < m
h : a * c ≡ b * c [ZMOD m]
d : ℕ := gcd m c
⊢ a ≡ b [ZMOD m / ↑(gcd m c)]

Next tactic:
have hmd := gcd_dvd_left m c
/-- To cancel a common factor `c` from a `ModEq` we must divide the modulus `m` by `gcd m c`. -/
theorem cancel_right_div_gcd (hm : 0 < m) (h : a * c ≡ b * c [ZMOD m]) :
    a ≡ b [ZMOD m / gcd m c] := by
  letI d := gcd m c
  have hmd := gcd_dvd_left m c
  

Proof state:
m n a b c d✝ : ℤ
hm : 0 < m
h : a * c ≡ b * c [ZMOD m]
d : ℕ := gcd m c
hmd : ↑(gcd m c) ∣ m
⊢ a ≡ b [ZMOD m / ↑(gcd m c)]

Next tactic:
have hcd := gcd_dvd_right m c
/-- To cancel a common factor `c` from a `ModEq` we must divide the modulus `m` by `gcd m c`. -/
theorem cancel_right_div_gcd (hm : 0 < m) (h : a * c ≡ b * c [ZMOD m]) :
    a ≡ b [ZMOD m / gcd m c] := by
  letI d := gcd m c
  have hmd := gcd_dvd_left m c
  have hcd := gcd_dvd_right m c
  

Proof state:
m n a b c d✝ : ℤ
hm : 0 < m
h : a * c ≡ b * c [ZMOD m]
d : ℕ := gcd m c
hmd : ↑(gcd m c) ∣ m
hcd : ↑(gcd m c) ∣ c
⊢ a ≡ b [ZMOD m / ↑(gcd m c)]

Next tactic:
rw [modEq_iff_dvd] at h ⊢
/-- To cancel a common factor `c` from a `ModEq` we must divide the modulus `m` by `gcd m c`. -/
theorem cancel_right_div_gcd (hm : 0 < m) (h : a * c ≡ b * c [ZMOD m]) :
    a ≡ b [ZMOD m / gcd m c] := by
  letI d := gcd m c
  have hmd := gcd_dvd_left m c
  have hcd := gcd_dvd_right m c
  rw [modEq_iff_dvd] at h ⊢
  -- porting note: removed `show` due to leanprover-community/mathlib4#3305
  

Proof state:
m n a b c d✝ : ℤ
hm : 0 < m
h : m ∣ b * c - a * c
d : ℕ := gcd m c
hmd : ↑(gcd m c) ∣ m
hcd : ↑(gcd m c) ∣ c
⊢ m / ↑(gcd m c) ∣ b - a

Next tactic:
refine Int.dvd_of_dvd_mul_right_of_gcd_one (?_ : m / d ∣ c / d * (b - a)) ?_
/-- To cancel a common factor `c` from a `ModEq` we must divide the modulus `m` by `gcd m c`. -/
theorem cancel_right_div_gcd (hm : 0 < m) (h : a * c ≡ b * c [ZMOD m]) :
    a ≡ b [ZMOD m / gcd m c] := by
  letI d := gcd m c
  have hmd := gcd_dvd_left m c
  have hcd := gcd_dvd_right m c
  rw [modEq_iff_dvd] at h ⊢
  -- porting note: removed `show` due to leanprover-community/mathlib4#3305
  refine Int.dvd_of_dvd_mul_right_of_gcd_one (?_ : m / d ∣ c / d * (b - a)) ?_
  · 

Proof state:
case refine_1
m n a b c d✝ : ℤ
hm : 0 < m
h : m ∣ b * c - a * c
d : ℕ := gcd m c
hmd : ↑(gcd m c) ∣ m
hcd : ↑(gcd m c) ∣ c
⊢ m / ↑d ∣ c / ↑d * (b - a)

Next tactic:
rw [mul_comm, ← Int.mul_ediv_assoc (b - a) hcd, sub_mul]
/-- To cancel a common factor `c` from a `ModEq` we must divide the modulus `m` by `gcd m c`. -/
theorem cancel_right_div_gcd (hm : 0 < m) (h : a * c ≡ b * c [ZMOD m]) :
    a ≡ b [ZMOD m / gcd m c] := by
  letI d := gcd m c
  have hmd := gcd_dvd_left m c
  have hcd := gcd_dvd_right m c
  rw [modEq_iff_dvd] at h ⊢
  -- porting note: removed `show` due to leanprover-community/mathlib4#3305
  refine Int.dvd_of_dvd_mul_right_of_gcd_one (?_ : m / d ∣ c / d * (b - a)) ?_
  · rw [mul_comm, ← Int.mul_ediv_assoc (b - a) hcd, sub_mul]
    

Proof state:
case refine_1
m n a b c d✝ : ℤ
hm : 0 < m
h : m ∣ b * c - a * c
d : ℕ := gcd m c
hmd : ↑(gcd m c) ∣ m
hcd : ↑(gcd m c) ∣ c
⊢ m / ↑d ∣ (b * c - a * c) / ↑(gcd m c)

Next tactic:
exact Int.ediv_dvd_ediv hmd h
/-- To cancel a common factor `c` from a `ModEq` we must divide the modulus `m` by `gcd m c`. -/
theorem cancel_right_div_gcd (hm : 0 < m) (h : a * c ≡ b * c [ZMOD m]) :
    a ≡ b [ZMOD m / gcd m c] := by
  letI d := gcd m c
  have hmd := gcd_dvd_left m c
  have hcd := gcd_dvd_right m c
  rw [modEq_iff_dvd] at h ⊢
  -- porting note: removed `show` due to leanprover-community/mathlib4#3305
  refine Int.dvd_of_dvd_mul_right_of_gcd_one (?_ : m / d ∣ c / d * (b - a)) ?_
  · rw [mul_comm, ← Int.mul_ediv_assoc (b - a) hcd, sub_mul]
    exact Int.ediv_dvd_ediv hmd h
  · 

Proof state:
case refine_2
m n a b c d✝ : ℤ
hm : 0 < m
h : m ∣ b * c - a * c
d : ℕ := gcd m c
hmd : ↑(gcd m c) ∣ m
hcd : ↑(gcd m c) ∣ c
⊢ gcd (m / ↑(gcd m c)) (c / ↑d) = 1

Next tactic:
rw [gcd_div hmd hcd, natAbs_ofNat, Nat.div_self (gcd_pos_of_ne_zero_left c hm.ne')]
/-- To cancel a common factor `c` from a `ModEq` we must divide the modulus `m` by `gcd m c`. -/
theorem cancel_left_div_gcd (hm : 0 < m) (h : c * a ≡ c * b [ZMOD m]) : a ≡ b [ZMOD m / gcd m c] :=
  cancel_right_div_gcd hm <| by 

Proof state:
m n a b c d : ℤ
hm : 0 < m
h : c * a ≡ c * b [ZMOD m]
⊢ a * c ≡ b * c [ZMOD m]

Next tactic:
simpa [mul_comm] using h
theorem of_div (h : a / c ≡ b / c [ZMOD m / c]) (ha : c ∣ a) (ha : c ∣ b) (ha : c ∣ m) :
    a ≡ b [ZMOD m] := by 

Proof state:
m n a b c d : ℤ
h : a / c ≡ b / c [ZMOD m / c]
ha✝¹ : c ∣ a
ha✝ : c ∣ b
ha : c ∣ m
⊢ a ≡ b [ZMOD m]

Next tactic:
convert h.mul_left'
theorem of_div (h : a / c ≡ b / c [ZMOD m / c]) (ha : c ∣ a) (ha : c ∣ b) (ha : c ∣ m) :
    a ≡ b [ZMOD m] := by convert h.mul_left' <;> 

Proof state:
case h.e'_1
m n a b c d : ℤ
h : a / c ≡ b / c [ZMOD m / c]
ha✝¹ : c ∣ a
ha✝ : c ∣ b
ha : c ∣ m
⊢ m = ?m.21762 * (m / c)

Next tactic:
rwa [Int.mul_ediv_cancel']
theorem of_div (h : a / c ≡ b / c [ZMOD m / c]) (ha : c ∣ a) (ha : c ∣ b) (ha : c ∣ m) :
    a ≡ b [ZMOD m] := by convert h.mul_left' <;> 

Proof state:
case h.e'_2
m n a b c d : ℤ
h : a / c ≡ b / c [ZMOD m / c]
ha✝¹ : c ∣ a
ha✝ : c ∣ b
ha : c ∣ m
⊢ a = c * (a / c)

Next tactic:
rwa [Int.mul_ediv_cancel']
theorem of_div (h : a / c ≡ b / c [ZMOD m / c]) (ha : c ∣ a) (ha : c ∣ b) (ha : c ∣ m) :
    a ≡ b [ZMOD m] := by convert h.mul_left' <;> 

Proof state:
case h.e'_3
m n a b c d : ℤ
h : a / c ≡ b / c [ZMOD m / c]
ha✝¹ : c ∣ a
ha✝ : c ∣ b
ha : c ∣ m
⊢ b = c * (b / c)

Next tactic:
rwa [Int.mul_ediv_cancel']
@[simp]
theorem modEq_zero_iff : a ≡ b [ZMOD 0] ↔ a = b := by 

Proof state:
m n a b c d : ℤ
⊢ a ≡ b [ZMOD 0] ↔ a = b

Next tactic:
rw [ModEq, emod_zero, emod_zero]
@[simp]
theorem add_modEq_left : n + a ≡ a [ZMOD n] := ModEq.symm <| modEq_iff_dvd.2 <| by 

Proof state:
m n a b c d : ℤ
⊢ n ∣ n + a - a

Next tactic:
simp
@[simp]
theorem add_modEq_right : a + n ≡ a [ZMOD n] := ModEq.symm <| modEq_iff_dvd.2 <| by 

Proof state:
m n a b c d : ℤ
⊢ n ∣ a + n - a

Next tactic:
simp
theorem modEq_and_modEq_iff_modEq_mul {a b m n : ℤ} (hmn : m.natAbs.Coprime n.natAbs) :
    a ≡ b [ZMOD m] ∧ a ≡ b [ZMOD n] ↔ a ≡ b [ZMOD m * n] :=
  ⟨fun h => by
    

Proof state:
m✝ n✝ a✝ b✝ c d a b m n : ℤ
hmn : Nat.Coprime (natAbs m) (natAbs n)
h : a ≡ b [ZMOD m] ∧ a ≡ b [ZMOD n]
⊢ a ≡ b [ZMOD m * n]

Next tactic:
rw [modEq_iff_dvd, modEq_iff_dvd] at h
theorem modEq_and_modEq_iff_modEq_mul {a b m n : ℤ} (hmn : m.natAbs.Coprime n.natAbs) :
    a ≡ b [ZMOD m] ∧ a ≡ b [ZMOD n] ↔ a ≡ b [ZMOD m * n] :=
  ⟨fun h => by
    rw [modEq_iff_dvd, modEq_iff_dvd] at h
    

Proof state:
m✝ n✝ a✝ b✝ c d a b m n : ℤ
hmn : Nat.Coprime (natAbs m) (natAbs n)
h : m ∣ b - a ∧ n ∣ b - a
⊢ a ≡ b [ZMOD m * n]

Next tactic:
rw [modEq_iff_dvd, ← natAbs_dvd, ← dvd_natAbs, coe_nat_dvd, natAbs_mul]
theorem modEq_and_modEq_iff_modEq_mul {a b m n : ℤ} (hmn : m.natAbs.Coprime n.natAbs) :
    a ≡ b [ZMOD m] ∧ a ≡ b [ZMOD n] ↔ a ≡ b [ZMOD m * n] :=
  ⟨fun h => by
    rw [modEq_iff_dvd, modEq_iff_dvd] at h
    rw [modEq_iff_dvd, ← natAbs_dvd, ← dvd_natAbs, coe_nat_dvd, natAbs_mul]
    

Proof state:
m✝ n✝ a✝ b✝ c d a b m n : ℤ
hmn : Nat.Coprime (natAbs m) (natAbs n)
h : m ∣ b - a ∧ n ∣ b - a
⊢ natAbs m * natAbs n ∣ natAbs (b - a)

Next tactic:
refine' hmn.mul_dvd_of_dvd_of_dvd _ _
theorem modEq_and_modEq_iff_modEq_mul {a b m n : ℤ} (hmn : m.natAbs.Coprime n.natAbs) :
    a ≡ b [ZMOD m] ∧ a ≡ b [ZMOD n] ↔ a ≡ b [ZMOD m * n] :=
  ⟨fun h => by
    rw [modEq_iff_dvd, modEq_iff_dvd] at h
    rw [modEq_iff_dvd, ← natAbs_dvd, ← dvd_natAbs, coe_nat_dvd, natAbs_mul]
    refine' hmn.mul_dvd_of_dvd_of_dvd _ _ <;> 

Proof state:
case refine'_1
m✝ n✝ a✝ b✝ c d a b m n : ℤ
hmn : Nat.Coprime (natAbs m) (natAbs n)
h : m ∣ b - a ∧ n ∣ b - a
⊢ natAbs m ∣ natAbs (b - a)

Next tactic:
rw [← coe_nat_dvd, natAbs_dvd, dvd_natAbs]
theorem modEq_and_modEq_iff_modEq_mul {a b m n : ℤ} (hmn : m.natAbs.Coprime n.natAbs) :
    a ≡ b [ZMOD m] ∧ a ≡ b [ZMOD n] ↔ a ≡ b [ZMOD m * n] :=
  ⟨fun h => by
    rw [modEq_iff_dvd, modEq_iff_dvd] at h
    rw [modEq_iff_dvd, ← natAbs_dvd, ← dvd_natAbs, coe_nat_dvd, natAbs_mul]
    refine' hmn.mul_dvd_of_dvd_of_dvd _ _ <;> 

Proof state:
case refine'_2
m✝ n✝ a✝ b✝ c d a b m n : ℤ
hmn : Nat.Coprime (natAbs m) (natAbs n)
h : m ∣ b - a ∧ n ∣ b - a
⊢ natAbs n ∣ natAbs (b - a)

Next tactic:
rw [← coe_nat_dvd, natAbs_dvd, dvd_natAbs]
theorem modEq_and_modEq_iff_modEq_mul {a b m n : ℤ} (hmn : m.natAbs.Coprime n.natAbs) :
    a ≡ b [ZMOD m] ∧ a ≡ b [ZMOD n] ↔ a ≡ b [ZMOD m * n] :=
  ⟨fun h => by
    rw [modEq_iff_dvd, modEq_iff_dvd] at h
    rw [modEq_iff_dvd, ← natAbs_dvd, ← dvd_natAbs, coe_nat_dvd, natAbs_mul]
    refine' hmn.mul_dvd_of_dvd_of_dvd _ _ <;> rw [← coe_nat_dvd, natAbs_dvd, dvd_natAbs] <;>
      

Proof state:
case refine'_1
m✝ n✝ a✝ b✝ c d a b m n : ℤ
hmn : Nat.Coprime (natAbs m) (natAbs n)
h : m ∣ b - a ∧ n ∣ b - a
⊢ m ∣ b - a

Next tactic:
tauto
theorem modEq_and_modEq_iff_modEq_mul {a b m n : ℤ} (hmn : m.natAbs.Coprime n.natAbs) :
    a ≡ b [ZMOD m] ∧ a ≡ b [ZMOD n] ↔ a ≡ b [ZMOD m * n] :=
  ⟨fun h => by
    rw [modEq_iff_dvd, modEq_iff_dvd] at h
    rw [modEq_iff_dvd, ← natAbs_dvd, ← dvd_natAbs, coe_nat_dvd, natAbs_mul]
    refine' hmn.mul_dvd_of_dvd_of_dvd _ _ <;> rw [← coe_nat_dvd, natAbs_dvd, dvd_natAbs] <;>
      

Proof state:
case refine'_2
m✝ n✝ a✝ b✝ c d a b m n : ℤ
hmn : Nat.Coprime (natAbs m) (natAbs n)
h : m ∣ b - a ∧ n ∣ b - a
⊢ n ∣ b - a

Next tactic:
tauto
theorem gcd_a_modEq (a b : ℕ) : (a : ℤ) * Nat.gcdA a b ≡ Nat.gcd a b [ZMOD b] := by
  

Proof state:
m n a✝ b✝ c d : ℤ
a b : ℕ
⊢ ↑a * Nat.gcdA a b ≡ ↑(Nat.gcd a b) [ZMOD ↑b]

Next tactic:
rw [← add_zero ((a : ℤ) * _), Nat.gcd_eq_gcd_ab]
theorem gcd_a_modEq (a b : ℕ) : (a : ℤ) * Nat.gcdA a b ≡ Nat.gcd a b [ZMOD b] := by
  rw [← add_zero ((a : ℤ) * _), Nat.gcd_eq_gcd_ab]
  

Proof state:
m n a✝ b✝ c d : ℤ
a b : ℕ
⊢ ↑a * Nat.gcdA a b + 0 ≡ ↑a * Nat.gcdA a b + ↑b * Nat.gcdB a b [ZMOD ↑b]

Next tactic:
exact (dvd_mul_right _ _).zero_modEq_int.add_left _
theorem modEq_add_fac {a b n : ℤ} (c : ℤ) (ha : a ≡ b [ZMOD n]) : a + n * c ≡ b [ZMOD n] :=
  calc
    a + n * c ≡ b + n * c [ZMOD n] := ha.add_right _
    _ ≡ b + 0 [ZMOD n] := (dvd_mul_right _ _).modEq_zero_int.add_left _
    _ ≡ b [ZMOD n] := by 

Proof state:
m n✝ a✝ b✝ c✝ d a b n c : ℤ
ha : a ≡ b [ZMOD n]
⊢ b + 0 ≡ b [ZMOD n]

Next tactic:
rw [add_zero]
theorem modEq_sub_fac {a b n : ℤ} (c : ℤ) (ha : a ≡ b [ZMOD n]) : a - n * c ≡ b [ZMOD n] := by
  

Proof state:
m n✝ a✝ b✝ c✝ d a b n c : ℤ
ha : a ≡ b [ZMOD n]
⊢ a - n * c ≡ b [ZMOD n]

Next tactic:
convert Int.modEq_add_fac (-c) ha using 1
theorem modEq_sub_fac {a b n : ℤ} (c : ℤ) (ha : a ≡ b [ZMOD n]) : a - n * c ≡ b [ZMOD n] := by
  convert Int.modEq_add_fac (-c) ha using 1
  

Proof state:
case h.e'_2
m n✝ a✝ b✝ c✝ d a b n c : ℤ
ha : a ≡ b [ZMOD n]
⊢ a - n * c = a + n * -c

Next tactic:
ring
theorem mod_coprime {a b : ℕ} (hab : Nat.Coprime a b) : ∃ y : ℤ, a * y ≡ 1 [ZMOD b] :=
  ⟨Nat.gcdA a b,
    have hgcd : Nat.gcd a b = 1 := Nat.Coprime.gcd_eq_one hab
    calc
      ↑a * Nat.gcdA a b ≡ ↑a * Nat.gcdA a b + ↑b * Nat.gcdB a b [ZMOD ↑b] :=
        ModEq.symm <| modEq_add_fac _ <| ModEq.refl _
      _ ≡ 1 [ZMOD ↑b] := by 

Proof state:
m n a✝ b✝ c d : ℤ
a b : ℕ
hab : Nat.Coprime a b
hgcd : Nat.gcd a b = 1
⊢ ↑a * Nat.gcdA a b + ↑b * Nat.gcdB a b ≡ 1 [ZMOD ↑b]

Next tactic:
rw [← Nat.gcd_eq_gcd_ab, hgcd]
theorem mod_coprime {a b : ℕ} (hab : Nat.Coprime a b) : ∃ y : ℤ, a * y ≡ 1 [ZMOD b] :=
  ⟨Nat.gcdA a b,
    have hgcd : Nat.gcd a b = 1 := Nat.Coprime.gcd_eq_one hab
    calc
      ↑a * Nat.gcdA a b ≡ ↑a * Nat.gcdA a b + ↑b * Nat.gcdB a b [ZMOD ↑b] :=
        ModEq.symm <| modEq_add_fac _ <| ModEq.refl _
      _ ≡ 1 [ZMOD ↑b] := by rw [← Nat.gcd_eq_gcd_ab, hgcd]; 

Proof state:
m n a✝ b✝ c d : ℤ
a b : ℕ
hab : Nat.Coprime a b
hgcd : Nat.gcd a b = 1
⊢ ↑1 ≡ 1 [ZMOD ↑b]

Next tactic:
rfl
theorem exists_unique_equiv (a : ℤ) {b : ℤ} (hb : 0 < b) :
    ∃ z : ℤ, 0 ≤ z ∧ z < b ∧ z ≡ a [ZMOD b] :=
  ⟨a % b, emod_nonneg _ (ne_of_gt hb),
    by
      

Proof state:
m n a✝ b✝ c d a b : ℤ
hb : 0 < b
⊢ a % b < b

Next tactic:
have : a % b < |b| := emod_lt _ (ne_of_gt hb)
theorem exists_unique_equiv (a : ℤ) {b : ℤ} (hb : 0 < b) :
    ∃ z : ℤ, 0 ≤ z ∧ z < b ∧ z ≡ a [ZMOD b] :=
  ⟨a % b, emod_nonneg _ (ne_of_gt hb),
    by
      have : a % b < |b| := emod_lt _ (ne_of_gt hb)
      

Proof state:
m n a✝ b✝ c d a b : ℤ
hb : 0 < b
this : a % b < |b|
⊢ a % b < b

Next tactic:
rwa [abs_of_pos hb] at this
theorem exists_unique_equiv (a : ℤ) {b : ℤ} (hb : 0 < b) :
    ∃ z : ℤ, 0 ≤ z ∧ z < b ∧ z ≡ a [ZMOD b] :=
  ⟨a % b, emod_nonneg _ (ne_of_gt hb),
    by
      have : a % b < |b| := emod_lt _ (ne_of_gt hb)
      rwa [abs_of_pos hb] at this, by 

Proof state:
m n a✝ b✝ c d a b : ℤ
hb : 0 < b
⊢ a % b ≡ a [ZMOD b]

Next tactic:
simp [ModEq]
theorem exists_unique_equiv_nat (a : ℤ) {b : ℤ} (hb : 0 < b) : ∃ z : ℕ, ↑z < b ∧ ↑z ≡ a [ZMOD b] :=
  let ⟨z, hz1, hz2, hz3⟩ := exists_unique_equiv a hb
  ⟨z.natAbs, by
    

Proof state:
m n a✝ b✝ c d a b : ℤ
hb : 0 < b
z : ℤ
hz1 : 0 ≤ z
hz2 : z < b
hz3 : z ≡ a [ZMOD b]
⊢ ↑(natAbs z) < b ∧ ↑(natAbs z) ≡ a [ZMOD b]

Next tactic:
constructor
theorem exists_unique_equiv_nat (a : ℤ) {b : ℤ} (hb : 0 < b) : ∃ z : ℕ, ↑z < b ∧ ↑z ≡ a [ZMOD b] :=
  let ⟨z, hz1, hz2, hz3⟩ := exists_unique_equiv a hb
  ⟨z.natAbs, by
    constructor <;> 

Proof state:
case left
m n a✝ b✝ c d a b : ℤ
hb : 0 < b
z : ℤ
hz1 : 0 ≤ z
hz2 : z < b
hz3 : z ≡ a [ZMOD b]
⊢ ↑(natAbs z) < b

Next tactic:
rw [natAbs_of_nonneg hz1]
theorem exists_unique_equiv_nat (a : ℤ) {b : ℤ} (hb : 0 < b) : ∃ z : ℕ, ↑z < b ∧ ↑z ≡ a [ZMOD b] :=
  let ⟨z, hz1, hz2, hz3⟩ := exists_unique_equiv a hb
  ⟨z.natAbs, by
    constructor <;> 

Proof state:
case right
m n a✝ b✝ c d a b : ℤ
hb : 0 < b
z : ℤ
hz1 : 0 ≤ z
hz2 : z < b
hz3 : z ≡ a [ZMOD b]
⊢ ↑(natAbs z) ≡ a [ZMOD b]

Next tactic:
rw [natAbs_of_nonneg hz1]
theorem exists_unique_equiv_nat (a : ℤ) {b : ℤ} (hb : 0 < b) : ∃ z : ℕ, ↑z < b ∧ ↑z ≡ a [ZMOD b] :=
  let ⟨z, hz1, hz2, hz3⟩ := exists_unique_equiv a hb
  ⟨z.natAbs, by
    constructor <;> rw [natAbs_of_nonneg hz1] <;> 

Proof state:
case left
m n a✝ b✝ c d a b : ℤ
hb : 0 < b
z : ℤ
hz1 : 0 ≤ z
hz2 : z < b
hz3 : z ≡ a [ZMOD b]
⊢ z < b

Next tactic:
assumption
theorem exists_unique_equiv_nat (a : ℤ) {b : ℤ} (hb : 0 < b) : ∃ z : ℕ, ↑z < b ∧ ↑z ≡ a [ZMOD b] :=
  let ⟨z, hz1, hz2, hz3⟩ := exists_unique_equiv a hb
  ⟨z.natAbs, by
    constructor <;> rw [natAbs_of_nonneg hz1] <;> 

Proof state:
case right
m n a✝ b✝ c d a b : ℤ
hb : 0 < b
z : ℤ
hz1 : 0 ≤ z
hz2 : z < b
hz3 : z ≡ a [ZMOD b]
⊢ z ≡ a [ZMOD b]

Next tactic:
assumption
@[elab_as_elim]
protected theorem induction_on {M : R[X] → Prop} (p : R[X]) (h_C : ∀ a, M (C a))
    (h_add : ∀ p q, M p → M q → M (p + q))
    (h_monomial : ∀ (n : ℕ) (a : R), M (C a * X ^ n) → M (C a * X ^ (n + 1))) : M p := by
  

Proof state:
R : Type u
S : Type v
T : Type w
ι : Type x
k : Type y
A : Type z
a b : R
m n : ℕ
inst✝ : Semiring R
p✝ q r : R[X]
M : R[X] → Prop
p : R[X]
h_C : ∀ (a : R), M (C a)
h_add : ∀ (p q : R[X]), M p → M q → M (p + q)
h_monomial : ∀ (n : ℕ) (a : R), M (C a * X ^ n) → M (C a * X ^ (n + 1))
⊢ M p

Next tactic:
have A : ∀ {n : ℕ} {a}, M (C a * X ^ n) := by
    intro n a
    induction' n with n ih
    · rw [pow_zero, mul_one]; exact h_C a
    · exact h_monomial _ _ ih
@[elab_as_elim]
protected theorem induction_on {M : R[X] → Prop} (p : R[X]) (h_C : ∀ a, M (C a))
    (h_add : ∀ p q, M p → M q → M (p + q))
    (h_monomial : ∀ (n : ℕ) (a : R), M (C a * X ^ n) → M (C a * X ^ (n + 1))) : M p := by
  have A : ∀ {n : ℕ} {a}, M (C a * X ^ n) := by
    

Proof state:
R : Type u
S : Type v
T : Type w
ι : Type x
k : Type y
A : Type z
a b : R
m n : ℕ
inst✝ : Semiring R
p✝ q r : R[X]
M : R[X] → Prop
p : R[X]
h_C : ∀ (a : R), M (C a)
h_add : ∀ (p q : R[X]), M p → M q → M (p + q)
h_monomial : ∀ (n : ℕ) (a : R), M (C a * X ^ n) → M (C a * X ^ (n + 1))
⊢ ∀ {n : ℕ} {a : R}, M (C a * X ^ n)

Next tactic:
intro n a
@[elab_as_elim]
protected theorem induction_on {M : R[X] → Prop} (p : R[X]) (h_C : ∀ a, M (C a))
    (h_add : ∀ p q, M p → M q → M (p + q))
    (h_monomial : ∀ (n : ℕ) (a : R), M (C a * X ^ n) → M (C a * X ^ (n + 1))) : M p := by
  have A : ∀ {n : ℕ} {a}, M (C a * X ^ n) := by
    intro n a
    

Proof state:
R : Type u
S : Type v
T : Type w
ι : Type x
k : Type y
A : Type z
a✝ b : R
m n✝ : ℕ
inst✝ : Semiring R
p✝ q r : R[X]
M : R[X] → Prop
p : R[X]
h_C : ∀ (a : R), M (C a)
h_add : ∀ (p q : R[X]), M p → M q → M (p + q)
h_monomial : ∀ (n : ℕ) (a : R), M (C a * X ^ n) → M (C a * X ^ (n + 1))
n : ℕ
a : R
⊢ M (C a * X ^ n)

Next tactic:
induction' n with n ih
@[elab_as_elim]
protected theorem induction_on {M : R[X] → Prop} (p : R[X]) (h_C : ∀ a, M (C a))
    (h_add : ∀ p q, M p → M q → M (p + q))
    (h_monomial : ∀ (n : ℕ) (a : R), M (C a * X ^ n) → M (C a * X ^ (n + 1))) : M p := by
  have A : ∀ {n : ℕ} {a}, M (C a * X ^ n) := by
    intro n a
    induction' n with n ih
    · 

Proof state:
case zero
R : Type u
S : Type v
T : Type w
ι : Type x
k : Type y
A : Type z
a✝ b : R
m n : ℕ
inst✝ : Semiring R
p✝ q r : R[X]
M : R[X] → Prop
p : R[X]
h_C : ∀ (a : R), M (C a)
h_add : ∀ (p q : R[X]), M p → M q → M (p + q)
h_monomial : ∀ (n : ℕ) (a : R), M (C a * X ^ n) → M (C a * X ^ (n + 1))
a : R
⊢ M (C a * X ^ Nat.zero)

Next tactic:
rw [pow_zero, mul_one]
@[elab_as_elim]
protected theorem induction_on {M : R[X] → Prop} (p : R[X]) (h_C : ∀ a, M (C a))
    (h_add : ∀ p q, M p → M q → M (p + q))
    (h_monomial : ∀ (n : ℕ) (a : R), M (C a * X ^ n) → M (C a * X ^ (n + 1))) : M p := by
  have A : ∀ {n : ℕ} {a}, M (C a * X ^ n) := by
    intro n a
    induction' n with n ih
    · rw [pow_zero, mul_one]; 

Proof state:
case zero
R : Type u
S : Type v
T : Type w
ι : Type x
k : Type y
A : Type z
a✝ b : R
m n : ℕ
inst✝ : Semiring R
p✝ q r : R[X]
M : R[X] → Prop
p : R[X]
h_C : ∀ (a : R), M (C a)
h_add : ∀ (p q : R[X]), M p → M q → M (p + q)
h_monomial : ∀ (n : ℕ) (a : R), M (C a * X ^ n) → M (C a * X ^ (n + 1))
a : R
⊢ M (C a)

Next tactic:
exact h_C a