l3lab/ntp-mathlib huggingface dataset:
theorem valMinAbs_natAbs_eq_min {n : ℕ} [hpos : NeZero n] (a : ZMod n) :
    a.valMinAbs.natAbs = min a.val (n - a.val) := by
  rw [valMinAbs_def_pos]
  split_ifs with h
  · rw [Int.natAbs_ofNat]
    symm
    apply
      min_eq_left (le_trans h (le_trans (Nat.half_le_of_sub_le_half _) (Nat.sub_le_sub_left h n)))
    rw [Nat.sub_sub_self (Nat.div_le_self _ _)]
  · rw [← Int.natAbs_neg, neg_sub, ← Nat.cast_sub a.val_le]
    

Proof state:
case neg
n✝ a✝ n : ℕ
hpos : NeZero n
a : ZMod n
h : ¬val a ≤ n / 2
⊢ Int.natAbs ↑(n - val a) = min (val a) (n - val a)

Next tactic:
symm
theorem valMinAbs_natAbs_eq_min {n : ℕ} [hpos : NeZero n] (a : ZMod n) :
    a.valMinAbs.natAbs = min a.val (n - a.val) := by
  rw [valMinAbs_def_pos]
  split_ifs with h
  · rw [Int.natAbs_ofNat]
    symm
    apply
      min_eq_left (le_trans h (le_trans (Nat.half_le_of_sub_le_half _) (Nat.sub_le_sub_left h n)))
    rw [Nat.sub_sub_self (Nat.div_le_self _ _)]
  · rw [← Int.natAbs_neg, neg_sub, ← Nat.cast_sub a.val_le]
    symm
    

Proof state:
case neg
n✝ a✝ n : ℕ
hpos : NeZero n
a : ZMod n
h : ¬val a ≤ n / 2
⊢ min (val a) (n - val a) = Int.natAbs ↑(n - val a)

Next tactic:
apply
      min_eq_right
        (le_trans (le_trans (Nat.sub_le_sub_left (lt_of_not_ge h) n) (Nat.le_half_of_half_lt_sub _))
          (le_of_not_ge h))
theorem valMinAbs_natAbs_eq_min {n : ℕ} [hpos : NeZero n] (a : ZMod n) :
    a.valMinAbs.natAbs = min a.val (n - a.val) := by
  rw [valMinAbs_def_pos]
  split_ifs with h
  · rw [Int.natAbs_ofNat]
    symm
    apply
      min_eq_left (le_trans h (le_trans (Nat.half_le_of_sub_le_half _) (Nat.sub_le_sub_left h n)))
    rw [Nat.sub_sub_self (Nat.div_le_self _ _)]
  · rw [← Int.natAbs_neg, neg_sub, ← Nat.cast_sub a.val_le]
    symm
    apply
      min_eq_right
        (le_trans (le_trans (Nat.sub_le_sub_left (lt_of_not_ge h) n) (Nat.le_half_of_half_lt_sub _))
          (le_of_not_ge h))
    

Proof state:
n✝ a✝ n : ℕ
hpos : NeZero n
a : ZMod n
h : ¬val a ≤ n / 2
⊢ n / 2 < n - (n - Nat.succ (n / 2))

Next tactic:
rw [Nat.sub_sub_self (Nat.div_lt_self (lt_of_le_of_ne' (Nat.zero_le _) hpos.1) one_lt_two)]
theorem valMinAbs_natAbs_eq_min {n : ℕ} [hpos : NeZero n] (a : ZMod n) :
    a.valMinAbs.natAbs = min a.val (n - a.val) := by
  rw [valMinAbs_def_pos]
  split_ifs with h
  · rw [Int.natAbs_ofNat]
    symm
    apply
      min_eq_left (le_trans h (le_trans (Nat.half_le_of_sub_le_half _) (Nat.sub_le_sub_left h n)))
    rw [Nat.sub_sub_self (Nat.div_le_self _ _)]
  · rw [← Int.natAbs_neg, neg_sub, ← Nat.cast_sub a.val_le]
    symm
    apply
      min_eq_right
        (le_trans (le_trans (Nat.sub_le_sub_left (lt_of_not_ge h) n) (Nat.le_half_of_half_lt_sub _))
          (le_of_not_ge h))
    rw [Nat.sub_sub_self (Nat.div_lt_self (lt_of_le_of_ne' (Nat.zero_le _) hpos.1) one_lt_two)]
    

Proof state:
n✝ a✝ n : ℕ
hpos : NeZero n
a : ZMod n
h : ¬val a ≤ n / 2
⊢ n / 2 < Nat.succ (n / 2)

Next tactic:
apply Nat.lt_succ_self
theorem valMinAbs_natCast_of_le_half (ha : a ≤ n / 2) : (a : ZMod n).valMinAbs = a := by
  

Proof state:
n a : ℕ
ha : a ≤ n / 2
⊢ valMinAbs ↑a = ↑a

Next tactic:
cases n
theorem valMinAbs_natCast_of_le_half (ha : a ≤ n / 2) : (a : ZMod n).valMinAbs = a := by
  cases n
  · 

Proof state:
case zero
a : ℕ
ha : a ≤ Nat.zero / 2
⊢ valMinAbs ↑a = ↑a

Next tactic:
simp
theorem valMinAbs_natCast_of_le_half (ha : a ≤ n / 2) : (a : ZMod n).valMinAbs = a := by
  cases n
  · simp
  · 

Proof state:
case succ
a n✝ : ℕ
ha : a ≤ Nat.succ n✝ / 2
⊢ valMinAbs ↑a = ↑a

Next tactic:
simp [valMinAbs_def_pos, val_nat_cast, Nat.mod_eq_of_lt (ha.trans_lt <| Nat.div_lt_self' _ 0),
      ha]
theorem valMinAbs_natCast_of_half_lt (ha : n / 2 < a) (ha' : a < n) :
    (a : ZMod n).valMinAbs = a - n := by
  

Proof state:
n a : ℕ
ha : n / 2 < a
ha' : a < n
⊢ valMinAbs ↑a = ↑a - ↑n

Next tactic:
cases n
theorem valMinAbs_natCast_of_half_lt (ha : n / 2 < a) (ha' : a < n) :
    (a : ZMod n).valMinAbs = a - n := by
  cases n
  · 

Proof state:
case zero
a : ℕ
ha : Nat.zero / 2 < a
ha' : a < Nat.zero
⊢ valMinAbs ↑a = ↑a - ↑Nat.zero

Next tactic:
cases not_lt_bot ha'
theorem valMinAbs_natCast_of_half_lt (ha : n / 2 < a) (ha' : a < n) :
    (a : ZMod n).valMinAbs = a - n := by
  cases n
  · cases not_lt_bot ha'
  · 

Proof state:
case succ
a n✝ : ℕ
ha : Nat.succ n✝ / 2 < a
ha' : a < Nat.succ n✝
⊢ valMinAbs ↑a = ↑a - ↑(Nat.succ n✝)

Next tactic:
simp [valMinAbs_def_pos, val_nat_cast, Nat.mod_eq_of_lt ha', ha.not_le]
@[simp]
theorem valMinAbs_natCast_eq_self [NeZero n] : (a : ZMod n).valMinAbs = a ↔ a ≤ n / 2 := by
  

Proof state:
n a : ℕ
inst✝ : NeZero n
⊢ valMinAbs ↑a = ↑a ↔ a ≤ n / 2

Next tactic:
refine' ⟨fun ha => _, valMinAbs_natCast_of_le_half⟩
@[simp]
theorem valMinAbs_natCast_eq_self [NeZero n] : (a : ZMod n).valMinAbs = a ↔ a ≤ n / 2 := by
  refine' ⟨fun ha => _, valMinAbs_natCast_of_le_half⟩
  

Proof state:
n a : ℕ
inst✝ : NeZero n
ha : valMinAbs ↑a = ↑a
⊢ a ≤ n / 2

Next tactic:
rw [← Int.natAbs_ofNat a, ← ha]
@[simp]
theorem valMinAbs_natCast_eq_self [NeZero n] : (a : ZMod n).valMinAbs = a ↔ a ≤ n / 2 := by
  refine' ⟨fun ha => _, valMinAbs_natCast_of_le_half⟩
  rw [← Int.natAbs_ofNat a, ← ha]
  

Proof state:
n a : ℕ
inst✝ : NeZero n
ha : valMinAbs ↑a = ↑a
⊢ Int.natAbs (valMinAbs ↑a) ≤ n / 2

Next tactic:
exact natAbs_valMinAbs_le a
theorem natAbs_min_of_le_div_two (n : ℕ) (x y : ℤ) (he : (x : ZMod n) = y) (hl : x.natAbs ≤ n / 2) :
    x.natAbs ≤ y.natAbs := by
  

Proof state:
n✝ a n : ℕ
x y : ℤ
he : ↑x = ↑y
hl : Int.natAbs x ≤ n / 2
⊢ Int.natAbs x ≤ Int.natAbs y

Next tactic:
rw [int_cast_eq_int_cast_iff_dvd_sub] at he
theorem natAbs_min_of_le_div_two (n : ℕ) (x y : ℤ) (he : (x : ZMod n) = y) (hl : x.natAbs ≤ n / 2) :
    x.natAbs ≤ y.natAbs := by
  rw [int_cast_eq_int_cast_iff_dvd_sub] at he
  

Proof state:
n✝ a n : ℕ
x y : ℤ
he : ↑n ∣ y - x
hl : Int.natAbs x ≤ n / 2
⊢ Int.natAbs x ≤ Int.natAbs y

Next tactic:
obtain ⟨m, he⟩ := he
theorem natAbs_min_of_le_div_two (n : ℕ) (x y : ℤ) (he : (x : ZMod n) = y) (hl : x.natAbs ≤ n / 2) :
    x.natAbs ≤ y.natAbs := by
  rw [int_cast_eq_int_cast_iff_dvd_sub] at he
  obtain ⟨m, he⟩ := he
  

Proof state:
case intro
n✝ a n : ℕ
x y : ℤ
hl : Int.natAbs x ≤ n / 2
m : ℤ
he : y - x = ↑n * m
⊢ Int.natAbs x ≤ Int.natAbs y

Next tactic:
rw [sub_eq_iff_eq_add] at he
theorem natAbs_min_of_le_div_two (n : ℕ) (x y : ℤ) (he : (x : ZMod n) = y) (hl : x.natAbs ≤ n / 2) :
    x.natAbs ≤ y.natAbs := by
  rw [int_cast_eq_int_cast_iff_dvd_sub] at he
  obtain ⟨m, he⟩ := he
  rw [sub_eq_iff_eq_add] at he
  

Proof state:
case intro
n✝ a n : ℕ
x y : ℤ
hl : Int.natAbs x ≤ n / 2
m : ℤ
he : y = ↑n * m + x
⊢ Int.natAbs x ≤ Int.natAbs y

Next tactic:
subst he
theorem natAbs_min_of_le_div_two (n : ℕ) (x y : ℤ) (he : (x : ZMod n) = y) (hl : x.natAbs ≤ n / 2) :
    x.natAbs ≤ y.natAbs := by
  rw [int_cast_eq_int_cast_iff_dvd_sub] at he
  obtain ⟨m, he⟩ := he
  rw [sub_eq_iff_eq_add] at he
  subst he
  

Proof state:
case intro
n✝ a n : ℕ
x : ℤ
hl : Int.natAbs x ≤ n / 2
m : ℤ
⊢ Int.natAbs x ≤ Int.natAbs (↑n * m + x)

Next tactic:
obtain rfl | hm := eq_or_ne m 0
theorem natAbs_min_of_le_div_two (n : ℕ) (x y : ℤ) (he : (x : ZMod n) = y) (hl : x.natAbs ≤ n / 2) :
    x.natAbs ≤ y.natAbs := by
  rw [int_cast_eq_int_cast_iff_dvd_sub] at he
  obtain ⟨m, he⟩ := he
  rw [sub_eq_iff_eq_add] at he
  subst he
  obtain rfl | hm := eq_or_ne m 0
  · 

Proof state:
case intro.inl
n✝ a n : ℕ
x : ℤ
hl : Int.natAbs x ≤ n / 2
⊢ Int.natAbs x ≤ Int.natAbs (↑n * 0 + x)

Next tactic:
rw [mul_zero, zero_add]
theorem natAbs_min_of_le_div_two (n : ℕ) (x y : ℤ) (he : (x : ZMod n) = y) (hl : x.natAbs ≤ n / 2) :
    x.natAbs ≤ y.natAbs := by
  rw [int_cast_eq_int_cast_iff_dvd_sub] at he
  obtain ⟨m, he⟩ := he
  rw [sub_eq_iff_eq_add] at he
  subst he
  obtain rfl | hm := eq_or_ne m 0
  · rw [mul_zero, zero_add]
  

Proof state:
case intro.inr
n✝ a n : ℕ
x : ℤ
hl : Int.natAbs x ≤ n / 2
m : ℤ
hm : m ≠ 0
⊢ Int.natAbs x ≤ Int.natAbs (↑n * m + x)

Next tactic:
apply hl.trans
theorem natAbs_min_of_le_div_two (n : ℕ) (x y : ℤ) (he : (x : ZMod n) = y) (hl : x.natAbs ≤ n / 2) :
    x.natAbs ≤ y.natAbs := by
  rw [int_cast_eq_int_cast_iff_dvd_sub] at he
  obtain ⟨m, he⟩ := he
  rw [sub_eq_iff_eq_add] at he
  subst he
  obtain rfl | hm := eq_or_ne m 0
  · rw [mul_zero, zero_add]
  apply hl.trans
  

Proof state:
case intro.inr
n✝ a n : ℕ
x : ℤ
hl : Int.natAbs x ≤ n / 2
m : ℤ
hm : m ≠ 0
⊢ n / 2 ≤ Int.natAbs (↑n * m + x)

Next tactic:
rw [← add_le_add_iff_right x.natAbs]
theorem natAbs_min_of_le_div_two (n : ℕ) (x y : ℤ) (he : (x : ZMod n) = y) (hl : x.natAbs ≤ n / 2) :
    x.natAbs ≤ y.natAbs := by
  rw [int_cast_eq_int_cast_iff_dvd_sub] at he
  obtain ⟨m, he⟩ := he
  rw [sub_eq_iff_eq_add] at he
  subst he
  obtain rfl | hm := eq_or_ne m 0
  · rw [mul_zero, zero_add]
  apply hl.trans
  rw [← add_le_add_iff_right x.natAbs]
  

Proof state:
case intro.inr
n✝ a n : ℕ
x : ℤ
hl : Int.natAbs x ≤ n / 2
m : ℤ
hm : m ≠ 0
⊢ n / 2 + Int.natAbs x ≤ Int.natAbs (↑n * m + x) + Int.natAbs x

Next tactic:
refine' le_trans (le_trans ((add_le_add_iff_left _).2 hl) _) (Int.natAbs_sub_le _ _)
theorem natAbs_min_of_le_div_two (n : ℕ) (x y : ℤ) (he : (x : ZMod n) = y) (hl : x.natAbs ≤ n / 2) :
    x.natAbs ≤ y.natAbs := by
  rw [int_cast_eq_int_cast_iff_dvd_sub] at he
  obtain ⟨m, he⟩ := he
  rw [sub_eq_iff_eq_add] at he
  subst he
  obtain rfl | hm := eq_or_ne m 0
  · rw [mul_zero, zero_add]
  apply hl.trans
  rw [← add_le_add_iff_right x.natAbs]
  refine' le_trans (le_trans ((add_le_add_iff_left _).2 hl) _) (Int.natAbs_sub_le _ _)
  

Proof state:
case intro.inr
n✝ a n : ℕ
x : ℤ
hl : Int.natAbs x ≤ n / 2
m : ℤ
hm : m ≠ 0
⊢ n / 2 + n / 2 ≤ Int.natAbs (↑n * m + x - x)

Next tactic:
rw [add_sub_cancel, Int.natAbs_mul, Int.natAbs_ofNat]
theorem natAbs_min_of_le_div_two (n : ℕ) (x y : ℤ) (he : (x : ZMod n) = y) (hl : x.natAbs ≤ n / 2) :
    x.natAbs ≤ y.natAbs := by
  rw [int_cast_eq_int_cast_iff_dvd_sub] at he
  obtain ⟨m, he⟩ := he
  rw [sub_eq_iff_eq_add] at he
  subst he
  obtain rfl | hm := eq_or_ne m 0
  · rw [mul_zero, zero_add]
  apply hl.trans
  rw [← add_le_add_iff_right x.natAbs]
  refine' le_trans (le_trans ((add_le_add_iff_left _).2 hl) _) (Int.natAbs_sub_le _ _)
  rw [add_sub_cancel, Int.natAbs_mul, Int.natAbs_ofNat]
  

Proof state:
case intro.inr
n✝ a n : ℕ
x : ℤ
hl : Int.natAbs x ≤ n / 2
m : ℤ
hm : m ≠ 0
⊢ n / 2 + n / 2 ≤ n * Int.natAbs m

Next tactic:
refine' le_trans _ (Nat.le_mul_of_pos_right <| Int.natAbs_pos.2 hm)
theorem natAbs_min_of_le_div_two (n : ℕ) (x y : ℤ) (he : (x : ZMod n) = y) (hl : x.natAbs ≤ n / 2) :
    x.natAbs ≤ y.natAbs := by
  rw [int_cast_eq_int_cast_iff_dvd_sub] at he
  obtain ⟨m, he⟩ := he
  rw [sub_eq_iff_eq_add] at he
  subst he
  obtain rfl | hm := eq_or_ne m 0
  · rw [mul_zero, zero_add]
  apply hl.trans
  rw [← add_le_add_iff_right x.natAbs]
  refine' le_trans (le_trans ((add_le_add_iff_left _).2 hl) _) (Int.natAbs_sub_le _ _)
  rw [add_sub_cancel, Int.natAbs_mul, Int.natAbs_ofNat]
  refine' le_trans _ (Nat.le_mul_of_pos_right <| Int.natAbs_pos.2 hm)
  

Proof state:
case intro.inr
n✝ a n : ℕ
x : ℤ
hl : Int.natAbs x ≤ n / 2
m : ℤ
hm : m ≠ 0
⊢ n / 2 + n / 2 ≤ n

Next tactic:
rw [← mul_two]
theorem natAbs_min_of_le_div_two (n : ℕ) (x y : ℤ) (he : (x : ZMod n) = y) (hl : x.natAbs ≤ n / 2) :
    x.natAbs ≤ y.natAbs := by
  rw [int_cast_eq_int_cast_iff_dvd_sub] at he
  obtain ⟨m, he⟩ := he
  rw [sub_eq_iff_eq_add] at he
  subst he
  obtain rfl | hm := eq_or_ne m 0
  · rw [mul_zero, zero_add]
  apply hl.trans
  rw [← add_le_add_iff_right x.natAbs]
  refine' le_trans (le_trans ((add_le_add_iff_left _).2 hl) _) (Int.natAbs_sub_le _ _)
  rw [add_sub_cancel, Int.natAbs_mul, Int.natAbs_ofNat]
  refine' le_trans _ (Nat.le_mul_of_pos_right <| Int.natAbs_pos.2 hm)
  rw [← mul_two]; 

Proof state:
case intro.inr
n✝ a n : ℕ
x : ℤ
hl : Int.natAbs x ≤ n / 2
m : ℤ
hm : m ≠ 0
⊢ n / 2 * 2 ≤ n

Next tactic:
apply Nat.div_mul_le_self
theorem natAbs_valMinAbs_add_le {n : ℕ} (a b : ZMod n) :
    (a + b).valMinAbs.natAbs ≤ (a.valMinAbs + b.valMinAbs).natAbs := by
  

Proof state:
n✝ a✝ n : ℕ
a b : ZMod n
⊢ Int.natAbs (valMinAbs (a + b)) ≤ Int.natAbs (valMinAbs a + valMinAbs b)

Next tactic:
cases' n with n
theorem natAbs_valMinAbs_add_le {n : ℕ} (a b : ZMod n) :
    (a + b).valMinAbs.natAbs ≤ (a.valMinAbs + b.valMinAbs).natAbs := by
  cases' n with n
  · 

Proof state:
case zero
n a✝ : ℕ
a b : ZMod Nat.zero
⊢ Int.natAbs (valMinAbs (a + b)) ≤ Int.natAbs (valMinAbs a + valMinAbs b)

Next tactic:
rfl
theorem natAbs_valMinAbs_add_le {n : ℕ} (a b : ZMod n) :
    (a + b).valMinAbs.natAbs ≤ (a.valMinAbs + b.valMinAbs).natAbs := by
  cases' n with n
  · rfl
  

Proof state:
case succ
n✝ a✝ n : ℕ
a b : ZMod (Nat.succ n)
⊢ Int.natAbs (valMinAbs (a + b)) ≤ Int.natAbs (valMinAbs a + valMinAbs b)

Next tactic:
apply natAbs_min_of_le_div_two n.succ
theorem natAbs_valMinAbs_add_le {n : ℕ} (a b : ZMod n) :
    (a + b).valMinAbs.natAbs ≤ (a.valMinAbs + b.valMinAbs).natAbs := by
  cases' n with n
  · rfl
  apply natAbs_min_of_le_div_two n.succ
  · 

Proof state:
case succ.he
n✝ a✝ n : ℕ
a b : ZMod (Nat.succ n)
⊢ ↑(valMinAbs (a + b)) = ↑(valMinAbs a + valMinAbs b)

Next tactic:
simp_rw [Int.cast_add, coe_valMinAbs]
theorem natAbs_valMinAbs_add_le {n : ℕ} (a b : ZMod n) :
    (a + b).valMinAbs.natAbs ≤ (a.valMinAbs + b.valMinAbs).natAbs := by
  cases' n with n
  · rfl
  apply natAbs_min_of_le_div_two n.succ
  · simp_rw [Int.cast_add, coe_valMinAbs]
  · 

Proof state:
case succ.hl
n✝ a✝ n : ℕ
a b : ZMod (Nat.succ n)
⊢ Int.natAbs (valMinAbs (a + b)) ≤ Nat.succ n / 2

Next tactic:
apply natAbs_valMinAbs_le
private theorem mul_inv_cancel_aux (a : ZMod p) (h : a ≠ 0) : a * a⁻¹ = 1 := by
  

Proof state:
n a✝ p : ℕ
inst✝ : Fact (Nat.Prime p)
a : ZMod p
h : a ≠ 0
⊢ a * a⁻¹ = 1

Next tactic:
obtain ⟨k, rfl⟩ := nat_cast_zmod_surjective a
private theorem mul_inv_cancel_aux (a : ZMod p) (h : a ≠ 0) : a * a⁻¹ = 1 := by
  obtain ⟨k, rfl⟩ := nat_cast_zmod_surjective a
  

Proof state:
case intro
n a p : ℕ
inst✝ : Fact (Nat.Prime p)
k : ℕ
h : ↑k ≠ 0
⊢ ↑k * (↑k)⁻¹ = 1

Next tactic:
apply coe_mul_inv_eq_one
private theorem mul_inv_cancel_aux (a : ZMod p) (h : a ≠ 0) : a * a⁻¹ = 1 := by
  obtain ⟨k, rfl⟩ := nat_cast_zmod_surjective a
  apply coe_mul_inv_eq_one
  

Proof state:
case intro.h
n a p : ℕ
inst✝ : Fact (Nat.Prime p)
k : ℕ
h : ↑k ≠ 0
⊢ Nat.Coprime k p

Next tactic:
apply Nat.Coprime.symm
private theorem mul_inv_cancel_aux (a : ZMod p) (h : a ≠ 0) : a * a⁻¹ = 1 := by
  obtain ⟨k, rfl⟩ := nat_cast_zmod_surjective a
  apply coe_mul_inv_eq_one
  apply Nat.Coprime.symm
  

Proof state:
case intro.h.a
n a p : ℕ
inst✝ : Fact (Nat.Prime p)
k : ℕ
h : ↑k ≠ 0
⊢ Nat.Coprime p k

Next tactic:
rwa [Nat.Prime.coprime_iff_not_dvd Fact.out, ← CharP.cast_eq_zero_iff (ZMod p)]
/-- `ZMod p` is an integral domain when `p` is prime. -/
instance (p : ℕ) [hp : Fact p.Prime] : IsDomain (ZMod p) := by
  -- We need `cases p` here in order to resolve which `CommRing` instance is being used.
  

Proof state:
n a p✝ : ℕ
inst✝ : Fact (Nat.Prime p✝)
p : ℕ
hp : Fact (Nat.Prime p)
⊢ IsDomain (ZMod p)

Next tactic:
cases p
/-- `ZMod p` is an integral domain when `p` is prime. -/
instance (p : ℕ) [hp : Fact p.Prime] : IsDomain (ZMod p) := by
  -- We need `cases p` here in order to resolve which `CommRing` instance is being used.
  cases p
  · 

Proof state:
case zero
n a p : ℕ
inst✝ : Fact (Nat.Prime p)
hp : Fact (Nat.Prime Nat.zero)
⊢ IsDomain (ZMod Nat.zero)

Next tactic:
exact (Nat.not_prime_zero hp.out).elim
/-- `ZMod p` is an integral domain when `p` is prime. -/
instance (p : ℕ) [hp : Fact p.Prime] : IsDomain (ZMod p) := by
  -- We need `cases p` here in order to resolve which `CommRing` instance is being used.
  cases p
  · exact (Nat.not_prime_zero hp.out).elim
  

Proof state:
case succ
n a p : ℕ
inst✝ : Fact (Nat.Prime p)
n✝ : ℕ
hp : Fact (Nat.Prime (Nat.succ n✝))
⊢ IsDomain (ZMod (Nat.succ n✝))

Next tactic:
exact @Field.isDomain (ZMod _) (inferInstanceAs (Field (ZMod _)))
theorem RingHom.ext_zmod {n : ℕ} {R : Type*} [Semiring R] (f g : ZMod n →+* R) : f = g := by
  

Proof state:
n : ℕ
R : Type u_1
inst✝ : Semiring R
f g : ZMod n →+* R
⊢ f = g

Next tactic:
ext a
theorem RingHom.ext_zmod {n : ℕ} {R : Type*} [Semiring R] (f g : ZMod n →+* R) : f = g := by
  ext a
  

Proof state:
case a
n : ℕ
R : Type u_1
inst✝ : Semiring R
f g : ZMod n →+* R
a : ZMod n
⊢ f a = g a

Next tactic:
obtain ⟨k, rfl⟩ := ZMod.int_cast_surjective a
theorem RingHom.ext_zmod {n : ℕ} {R : Type*} [Semiring R] (f g : ZMod n →+* R) : f = g := by
  ext a
  obtain ⟨k, rfl⟩ := ZMod.int_cast_surjective a
  

Proof state:
case a.intro
n : ℕ
R : Type u_1
inst✝ : Semiring R
f g : ZMod n →+* R
k : ℤ
⊢ f ↑k = g ↑k

Next tactic:
let φ : ℤ →+* R := f.comp (Int.castRingHom (ZMod n))
theorem RingHom.ext_zmod {n : ℕ} {R : Type*} [Semiring R] (f g : ZMod n →+* R) : f = g := by
  ext a
  obtain ⟨k, rfl⟩ := ZMod.int_cast_surjective a
  let φ : ℤ →+* R := f.comp (Int.castRingHom (ZMod n))
  

Proof state:
case a.intro
n : ℕ
R : Type u_1
inst✝ : Semiring R
f g : ZMod n →+* R
k : ℤ
φ : ℤ →+* R := comp f (Int.castRingHom (ZMod n))
⊢ f ↑k = g ↑k

Next tactic:
let ψ : ℤ →+* R := g.comp (Int.castRingHom (ZMod n))
theorem RingHom.ext_zmod {n : ℕ} {R : Type*} [Semiring R] (f g : ZMod n →+* R) : f = g := by
  ext a
  obtain ⟨k, rfl⟩ := ZMod.int_cast_surjective a
  let φ : ℤ →+* R := f.comp (Int.castRingHom (ZMod n))
  let ψ : ℤ →+* R := g.comp (Int.castRingHom (ZMod n))
  

Proof state:
case a.intro
n : ℕ
R : Type u_1
inst✝ : Semiring R
f g : ZMod n →+* R
k : ℤ
φ : ℤ →+* R := comp f (Int.castRingHom (ZMod n))
ψ : ℤ →+* R := comp g (Int.castRingHom (ZMod n))
⊢ f ↑k = g ↑k

Next tactic:
show φ k = ψ k
theorem RingHom.ext_zmod {n : ℕ} {R : Type*} [Semiring R] (f g : ZMod n →+* R) : f = g := by
  ext a
  obtain ⟨k, rfl⟩ := ZMod.int_cast_surjective a
  let φ : ℤ →+* R := f.comp (Int.castRingHom (ZMod n))
  let ψ : ℤ →+* R := g.comp (Int.castRingHom (ZMod n))
  show φ k = ψ k
  

Proof state:
case a.intro
n : ℕ
R : Type u_1
inst✝ : Semiring R
f g : ZMod n →+* R
k : ℤ
φ : ℤ →+* R := comp f (Int.castRingHom (ZMod n))
ψ : ℤ →+* R := comp g (Int.castRingHom (ZMod n))
⊢ φ k = ψ k

Next tactic:
rw [φ.ext_int ψ]
instance subsingleton_ringEquiv [Semiring R] : Subsingleton (ZMod n ≃+* R) :=
  ⟨fun f g => by
    

Proof state:
n : ℕ
R : Type u_1
inst✝ : Semiring R
f g : ZMod n ≃+* R
⊢ f = g

Next tactic:
rw [RingEquiv.coe_ringHom_inj_iff]
instance subsingleton_ringEquiv [Semiring R] : Subsingleton (ZMod n ≃+* R) :=
  ⟨fun f g => by
    rw [RingEquiv.coe_ringHom_inj_iff]
    

Proof state:
n : ℕ
R : Type u_1
inst✝ : Semiring R
f g : ZMod n ≃+* R
⊢ ↑f = ↑g

Next tactic:
apply RingHom.ext_zmod _ _
@[simp]
theorem ringHom_map_cast [Ring R] (f : R →+* ZMod n) (k : ZMod n) : f k = k := by
  

Proof state:
n : ℕ
R : Type u_1
inst✝ : Ring R
f : R →+* ZMod n
k : ZMod n
⊢ f ↑k = k

Next tactic:
cases n
@[simp]
theorem ringHom_map_cast [Ring R] (f : R →+* ZMod n) (k : ZMod n) : f k = k := by
  cases n
  · 

Proof state:
case zero
R : Type u_1
inst✝ : Ring R
f : R →+* ZMod Nat.zero
k : ZMod Nat.zero
⊢ f ↑k = k

Next tactic:
dsimp [ZMod, ZMod.cast] at f k ⊢
@[simp]
theorem ringHom_map_cast [Ring R] (f : R →+* ZMod n) (k : ZMod n) : f k = k := by
  cases n
  · dsimp [ZMod, ZMod.cast] at f k ⊢; 

Proof state:
case zero
R : Type u_1
inst✝ : Ring R
f : R →+* ℤ
k : ℤ
⊢ f ↑k = k

Next tactic:
simp
@[simp]
theorem ringHom_map_cast [Ring R] (f : R →+* ZMod n) (k : ZMod n) : f k = k := by
  cases n
  · dsimp [ZMod, ZMod.cast] at f k ⊢; simp
  · 

Proof state:
case succ
R : Type u_1
inst✝ : Ring R
n✝ : ℕ
f : R →+* ZMod (Nat.succ n✝)
k : ZMod (Nat.succ n✝)
⊢ f ↑k = k

Next tactic:
dsimp [ZMod, ZMod.cast] at f k ⊢
@[simp]
theorem ringHom_map_cast [Ring R] (f : R →+* ZMod n) (k : ZMod n) : f k = k := by
  cases n
  · dsimp [ZMod, ZMod.cast] at f k ⊢; simp
  · dsimp [ZMod, ZMod.cast] at f k ⊢
    

Proof state:
case succ
R : Type u_1
inst✝ : Ring R
n✝ : ℕ
f : R →+* Fin (n✝ + 1)
k : Fin (n✝ + 1)
⊢ f ↑(val k) = k

Next tactic:
erw [map_natCast, Fin.cast_val_eq_self]
theorem ringHom_eq_of_ker_eq [CommRing R] (f g : R →+* ZMod n)
    (h : RingHom.ker f = RingHom.ker g) : f = g := by
  

Proof state:
n : ℕ
R : Type u_1
inst✝ : CommRing R
f g : R →+* ZMod n
h : RingHom.ker f = RingHom.ker g
⊢ f = g

Next tactic:
have := f.liftOfRightInverse_comp _ (ZMod.ringHom_rightInverse f) ⟨g, le_of_eq h⟩
theorem ringHom_eq_of_ker_eq [CommRing R] (f g : R →+* ZMod n)
    (h : RingHom.ker f = RingHom.ker g) : f = g := by
  have := f.liftOfRightInverse_comp _ (ZMod.ringHom_rightInverse f) ⟨g, le_of_eq h⟩
  

Proof state:
n : ℕ
R : Type u_1
inst✝ : CommRing R
f g : R →+* ZMod n
h : RingHom.ker f = RingHom.ker g
this :
  RingHom.comp
      ((RingHom.liftOfRightInverse f cast (_ : Function.RightInverse cast ⇑f))
        { val := g, property := (_ : RingHom.ker f ≤ RingHom.ker g) })
      f =
    ↑{ val := g, property := (_ : RingHom.ker f ≤ RingHom.ker g) }
⊢ f = g

Next tactic:
rw [Subtype.coe_mk] at this
theorem ringHom_eq_of_ker_eq [CommRing R] (f g : R →+* ZMod n)
    (h : RingHom.ker f = RingHom.ker g) : f = g := by
  have := f.liftOfRightInverse_comp _ (ZMod.ringHom_rightInverse f) ⟨g, le_of_eq h⟩
  rw [Subtype.coe_mk] at this
  

Proof state:
n : ℕ
R : Type u_1
inst✝ : CommRing R
f g : R →+* ZMod n
h : RingHom.ker f = RingHom.ker g
this :
  RingHom.comp
      ((RingHom.liftOfRightInverse f cast (_ : Function.RightInverse cast ⇑f))
        { val := g, property := (_ : RingHom.ker f ≤ RingHom.ker g) })
      f =
    g
⊢ f = g

Next tactic:
rw [← this, RingHom.ext_zmod (f.liftOfRightInverse _ _ ⟨g, _⟩) _, RingHom.id_comp]
/-- The map from `ZMod n` induced by `f : ℤ →+ A` that maps `n` to `0`. -/
--@[simps] --Porting note: removed, simplified LHS of `lift_coe` to something worse.
def lift : { f : ℤ →+ A // f n = 0 } ≃ (ZMod n →+ A) :=
  (Equiv.subtypeEquivRight <| by
        

Proof state:
n : ℕ
R : Type u_1
A : Type u_2
inst✝ : AddGroup A
⊢ ∀ (x : ℤ →+ A), x ↑n = 0 ↔ AddMonoidHom.ker (Int.castAddHom (ZMod n)) ≤ AddMonoidHom.ker x

Next tactic:
intro f
/-- The map from `ZMod n` induced by `f : ℤ →+ A` that maps `n` to `0`. -/
--@[simps] --Porting note: removed, simplified LHS of `lift_coe` to something worse.
def lift : { f : ℤ →+ A // f n = 0 } ≃ (ZMod n →+ A) :=
  (Equiv.subtypeEquivRight <| by
        intro f
        

Proof state:
n : ℕ
R : Type u_1
A : Type u_2
inst✝ : AddGroup A
f : ℤ →+ A
⊢ f ↑n = 0 ↔ AddMonoidHom.ker (Int.castAddHom (ZMod n)) ≤ AddMonoidHom.ker f

Next tactic:
rw [ker_int_castAddHom]
/-- The map from `ZMod n` induced by `f : ℤ →+ A` that maps `n` to `0`. -/
--@[simps] --Porting note: removed, simplified LHS of `lift_coe` to something worse.
def lift : { f : ℤ →+ A // f n = 0 } ≃ (ZMod n →+ A) :=
  (Equiv.subtypeEquivRight <| by
        intro f
        rw [ker_int_castAddHom]
        

Proof state:
n : ℕ
R : Type u_1
A : Type u_2
inst✝ : AddGroup A
f : ℤ →+ A
⊢ f ↑n = 0 ↔ AddSubgroup.zmultiples ↑n ≤ AddMonoidHom.ker f

Next tactic:
constructor
/-- The map from `ZMod n` induced by `f : ℤ →+ A` that maps `n` to `0`. -/
--@[simps] --Porting note: removed, simplified LHS of `lift_coe` to something worse.
def lift : { f : ℤ →+ A // f n = 0 } ≃ (ZMod n →+ A) :=
  (Equiv.subtypeEquivRight <| by
        intro f
        rw [ker_int_castAddHom]
        constructor
        · 

Proof state:
case mp
n : ℕ
R : Type u_1
A : Type u_2
inst✝ : AddGroup A
f : ℤ →+ A
⊢ f ↑n = 0 → AddSubgroup.zmultiples ↑n ≤ AddMonoidHom.ker f

Next tactic:
rintro hf _ ⟨x, rfl⟩
/-- The map from `ZMod n` induced by `f : ℤ →+ A` that maps `n` to `0`. -/
--@[simps] --Porting note: removed, simplified LHS of `lift_coe` to something worse.
def lift : { f : ℤ →+ A // f n = 0 } ≃ (ZMod n →+ A) :=
  (Equiv.subtypeEquivRight <| by
        intro f
        rw [ker_int_castAddHom]
        constructor
        · rintro hf _ ⟨x, rfl⟩
          

Proof state:
case mp.intro
n : ℕ
R : Type u_1
A : Type u_2
inst✝ : AddGroup A
f : ℤ →+ A
hf : f ↑n = 0
x : ℤ
⊢ (fun x => x • ↑n) x ∈ AddMonoidHom.ker f

Next tactic:
simp only [f.map_zsmul, zsmul_zero, f.mem_ker, hf]