l3lab/ntp-mathlib huggingface dataset:
/-- The **Chinese remainder theorem**. For a pair of coprime natural numbers, `m` and `n`,
  the rings `ZMod (m * n)` and `ZMod m × ZMod n` are isomorphic.

See `Ideal.quotientInfRingEquivPiQuotient` for the Chinese remainder theorem for ideals in any
ring.
-/
def chineseRemainder {m n : ℕ} (h : m.Coprime n) : ZMod (m * n) ≃+* ZMod m × ZMod n :=
  let to_fun : ZMod (m * n) → ZMod m × ZMod n :=
    ZMod.castHom (show m.lcm n ∣ m * n by simp [Nat.lcm_dvd_iff]) (ZMod m × ZMod n)
  let inv_fun : ZMod m × ZMod n → ZMod (m * n) := fun x =>
    if m * n = 0 then if m = 1 then RingHom.snd _ (ZMod n) x else RingHom.fst (ZMod m) _ x
    else Nat.chineseRemainder h x.1.val x.2.val
  have inv : Function.LeftInverse inv_fun to_fun ∧ Function.RightInverse inv_fun to_fun :=
    if hmn0 : m * n = 0 then by
      rcases h.eq_of_mul_eq_zero hmn0 with (⟨rfl, rfl⟩ | ⟨rfl, rfl⟩)
      · constructor
        · intro x; rfl
        · rintro ⟨x, y⟩
          fin_cases y
          simp [castHom, Prod.ext_iff, eq_iff_true_of_subsingleton]
      · constructor
        · intro x; rfl
        · rintro ⟨x, y⟩
          fin_cases x
          simp [castHom, Prod.ext_iff, eq_iff_true_of_subsingleton]
    else by
      haveI : NeZero (m * n) := ⟨hmn0⟩
      haveI : NeZero m := ⟨left_ne_zero_of_mul hmn0⟩
      haveI : NeZero n := ⟨right_ne_zero_of_mul hmn0⟩
      have left_inv : Function.LeftInverse inv_fun to_fun := by
        intro x
        dsimp only [dvd_mul_left, dvd_mul_right, ZMod.castHom_apply]
        conv_rhs => rw [← ZMod.nat_cast_zmod_val x]
        rw [if_neg hmn0, ZMod.eq_iff_modEq_nat, ← Nat.modEq_and_modEq_iff_modEq_mul h,
          Prod.fst_zmod_cast, Prod.snd_zmod_cast]
        refine'
          ⟨(Nat.chineseRemainder h (x : ZMod m).val (x : ZMod n).val).2.left.trans _,
            (Nat.chineseRemainder h (x : ZMod m).val (x : ZMod n).val).2.right.trans _⟩
        · rw [← ZMod.eq_iff_modEq_nat, ZMod.nat_cast_zmod_val, ZMod.nat_cast_val]
        · rw [← ZMod.eq_iff_modEq_nat, ZMod.nat_cast_zmod_val, ZMod.nat_cast_val]
      

Proof state:
m n : ℕ
h : Nat.Coprime m n
to_fun : ZMod (m * n) → ZMod m × ZMod n := ⇑(castHom (_ : Nat.lcm m n ∣ m * n) (ZMod m × ZMod n))
inv_fun : ZMod m × ZMod n → ZMod (m * n) :=
  fun x =>
    if m * n = 0 then if m = 1 then ↑((RingHom.snd (ZMod m) (ZMod n)) x) else ↑((RingHom.fst (ZMod m) (ZMod n)) x)
    else ↑↑(Nat.chineseRemainder h (val x.1) (val x.2))
hmn0 : ¬m * n = 0
this✝¹ : NeZero (m * n)
this✝ : NeZero m
this : NeZero n
left_inv : LeftInverse inv_fun to_fun
⊢ LeftInverse inv_fun to_fun ∧ Function.RightInverse inv_fun to_fun

Next tactic:
exact ⟨left_inv, left_inv.rightInverse_of_card_le (by simp)⟩
/-- The **Chinese remainder theorem**. For a pair of coprime natural numbers, `m` and `n`,
  the rings `ZMod (m * n)` and `ZMod m × ZMod n` are isomorphic.

See `Ideal.quotientInfRingEquivPiQuotient` for the Chinese remainder theorem for ideals in any
ring.
-/
def chineseRemainder {m n : ℕ} (h : m.Coprime n) : ZMod (m * n) ≃+* ZMod m × ZMod n :=
  let to_fun : ZMod (m * n) → ZMod m × ZMod n :=
    ZMod.castHom (show m.lcm n ∣ m * n by simp [Nat.lcm_dvd_iff]) (ZMod m × ZMod n)
  let inv_fun : ZMod m × ZMod n → ZMod (m * n) := fun x =>
    if m * n = 0 then if m = 1 then RingHom.snd _ (ZMod n) x else RingHom.fst (ZMod m) _ x
    else Nat.chineseRemainder h x.1.val x.2.val
  have inv : Function.LeftInverse inv_fun to_fun ∧ Function.RightInverse inv_fun to_fun :=
    if hmn0 : m * n = 0 then by
      rcases h.eq_of_mul_eq_zero hmn0 with (⟨rfl, rfl⟩ | ⟨rfl, rfl⟩)
      · constructor
        · intro x; rfl
        · rintro ⟨x, y⟩
          fin_cases y
          simp [castHom, Prod.ext_iff, eq_iff_true_of_subsingleton]
      · constructor
        · intro x; rfl
        · rintro ⟨x, y⟩
          fin_cases x
          simp [castHom, Prod.ext_iff, eq_iff_true_of_subsingleton]
    else by
      haveI : NeZero (m * n) := ⟨hmn0⟩
      haveI : NeZero m := ⟨left_ne_zero_of_mul hmn0⟩
      haveI : NeZero n := ⟨right_ne_zero_of_mul hmn0⟩
      have left_inv : Function.LeftInverse inv_fun to_fun := by
        intro x
        dsimp only [dvd_mul_left, dvd_mul_right, ZMod.castHom_apply]
        conv_rhs => rw [← ZMod.nat_cast_zmod_val x]
        rw [if_neg hmn0, ZMod.eq_iff_modEq_nat, ← Nat.modEq_and_modEq_iff_modEq_mul h,
          Prod.fst_zmod_cast, Prod.snd_zmod_cast]
        refine'
          ⟨(Nat.chineseRemainder h (x : ZMod m).val (x : ZMod n).val).2.left.trans _,
            (Nat.chineseRemainder h (x : ZMod m).val (x : ZMod n).val).2.right.trans _⟩
        · rw [← ZMod.eq_iff_modEq_nat, ZMod.nat_cast_zmod_val, ZMod.nat_cast_val]
        · rw [← ZMod.eq_iff_modEq_nat, ZMod.nat_cast_zmod_val, ZMod.nat_cast_val]
      exact ⟨left_inv, left_inv.rightInverse_of_card_le (by 

Proof state:
m n : ℕ
h : Nat.Coprime m n
to_fun : ZMod (m * n) → ZMod m × ZMod n := ⇑(castHom (_ : Nat.lcm m n ∣ m * n) (ZMod m × ZMod n))
inv_fun : ZMod m × ZMod n → ZMod (m * n) :=
  fun x =>
    if m * n = 0 then if m = 1 then ↑((RingHom.snd (ZMod m) (ZMod n)) x) else ↑((RingHom.fst (ZMod m) (ZMod n)) x)
    else ↑↑(Nat.chineseRemainder h (val x.1) (val x.2))
hmn0 : ¬m * n = 0
this✝¹ : NeZero (m * n)
this✝ : NeZero m
this : NeZero n
left_inv : LeftInverse inv_fun to_fun
⊢ Fintype.card (ZMod m × ZMod n) ≤ Fintype.card (ZMod (m * n))

Next tactic:
simp
instance subsingleton_units : Subsingleton (ZMod 2)ˣ :=
  ⟨by 

Proof state:
⊢ ∀ (a b : (ZMod 2)ˣ), a = b

Next tactic:
decide
@[simp]
theorem add_self_eq_zero_iff_eq_zero {n : ℕ} (hn : Odd n) {a : ZMod n} :
    a + a = 0 ↔ a = 0 := by
  

Proof state:
n : ℕ
hn : Odd n
a : ZMod n
⊢ a + a = 0 ↔ a = 0

Next tactic:
rw [Nat.odd_iff, ← Nat.two_dvd_ne_zero, ← Nat.prime_two.coprime_iff_not_dvd] at hn
@[simp]
theorem add_self_eq_zero_iff_eq_zero {n : ℕ} (hn : Odd n) {a : ZMod n} :
    a + a = 0 ↔ a = 0 := by
  rw [Nat.odd_iff, ← Nat.two_dvd_ne_zero, ← Nat.prime_two.coprime_iff_not_dvd] at hn
  

Proof state:
n : ℕ
hn : Nat.Coprime 2 n
a : ZMod n
⊢ a + a = 0 ↔ a = 0

Next tactic:
rw [← mul_two, ← @Nat.cast_two (ZMod n), ← ZMod.coe_unitOfCoprime 2 hn, Units.mul_left_eq_zero]
theorem ne_neg_self {n : ℕ} (hn : Odd n) {a : ZMod n} (ha : a ≠ 0) : a ≠ -a := by
  

Proof state:
n : ℕ
hn : Odd n
a : ZMod n
ha : a ≠ 0
⊢ a ≠ -a

Next tactic:
rwa [Ne, eq_neg_iff_add_eq_zero, add_self_eq_zero_iff_eq_zero hn]
theorem neg_eq_self_mod_two (a : ZMod 2) : -a = a := by
  

Proof state:
a : ZMod 2
⊢ -a = a

Next tactic:
fin_cases a
theorem neg_eq_self_mod_two (a : ZMod 2) : -a = a := by
  fin_cases a <;> 

Proof state:
case head
⊢ -{ val := 0, isLt := (_ : 0 < 1 + 1) } = { val := 0, isLt := (_ : 0 < 1 + 1) }

Next tactic:
apply Fin.ext
theorem neg_eq_self_mod_two (a : ZMod 2) : -a = a := by
  fin_cases a <;> 

Proof state:
case tail.head
⊢ -{ val := 1, isLt := (_ : (fun a => a < 1 + 1) 1) } = { val := 1, isLt := (_ : (fun a => a < 1 + 1) 1) }

Next tactic:
apply Fin.ext
theorem neg_eq_self_mod_two (a : ZMod 2) : -a = a := by
  fin_cases a <;> apply Fin.ext <;> 

Proof state:
case head.h
⊢ ↑(-{ val := 0, isLt := (_ : 0 < 1 + 1) }) = ↑{ val := 0, isLt := (_ : 0 < 1 + 1) }

Next tactic:
simp [Fin.coe_neg, Int.natMod]
theorem neg_eq_self_mod_two (a : ZMod 2) : -a = a := by
  fin_cases a <;> apply Fin.ext <;> 

Proof state:
case tail.head.h
⊢ ↑(-{ val := 1, isLt := (_ : (fun a => a < 1 + 1) 1) }) = ↑{ val := 1, isLt := (_ : (fun a => a < 1 + 1) 1) }

Next tactic:
simp [Fin.coe_neg, Int.natMod]
theorem neg_eq_self_mod_two (a : ZMod 2) : -a = a := by
  fin_cases a <;> apply Fin.ext <;> simp [Fin.coe_neg, Int.natMod]; 

Proof state:
case tail.head.h
⊢ ↑(-1) = 1

Next tactic:
rfl
@[simp]
theorem natAbs_mod_two (a : ℤ) : (a.natAbs : ZMod 2) = a := by
  

Proof state:
a : ℤ
⊢ ↑(Int.natAbs a) = ↑a

Next tactic:
cases a
@[simp]
theorem natAbs_mod_two (a : ℤ) : (a.natAbs : ZMod 2) = a := by
  cases a
  · 

Proof state:
case ofNat
a✝ : ℕ
⊢ ↑(Int.natAbs (Int.ofNat a✝)) = ↑(Int.ofNat a✝)

Next tactic:
simp only [Int.natAbs_ofNat, Int.cast_ofNat, Int.ofNat_eq_coe]
@[simp]
theorem natAbs_mod_two (a : ℤ) : (a.natAbs : ZMod 2) = a := by
  cases a
  · simp only [Int.natAbs_ofNat, Int.cast_ofNat, Int.ofNat_eq_coe]
  · 

Proof state:
case negSucc
a✝ : ℕ
⊢ ↑(Int.natAbs (Int.negSucc a✝)) = ↑(Int.negSucc a✝)

Next tactic:
simp only [neg_eq_self_mod_two, Nat.cast_succ, Int.natAbs, Int.cast_negSucc]
@[simp]
theorem val_eq_zero : ∀ {n : ℕ} (a : ZMod n), a.val = 0 ↔ a = 0
  | 0, a => Int.natAbs_eq_zero
  | n + 1, a => by
    

Proof state:
n : ℕ
a : ZMod (n + 1)
⊢ val a = 0 ↔ a = 0

Next tactic:
rw [Fin.ext_iff]
@[simp]
theorem val_eq_zero : ∀ {n : ℕ} (a : ZMod n), a.val = 0 ↔ a = 0
  | 0, a => Int.natAbs_eq_zero
  | n + 1, a => by
    rw [Fin.ext_iff]
    

Proof state:
n : ℕ
a : ZMod (n + 1)
⊢ val a = 0 ↔ ↑a = ↑0

Next tactic:
exact Iff.rfl
theorem neg_eq_self_iff {n : ℕ} (a : ZMod n) : -a = a ↔ a = 0 ∨ 2 * a.val = n := by
  

Proof state:
n : ℕ
a : ZMod n
⊢ -a = a ↔ a = 0 ∨ 2 * val a = n

Next tactic:
rw [neg_eq_iff_add_eq_zero, ← two_mul]
theorem neg_eq_self_iff {n : ℕ} (a : ZMod n) : -a = a ↔ a = 0 ∨ 2 * a.val = n := by
  rw [neg_eq_iff_add_eq_zero, ← two_mul]
  

Proof state:
n : ℕ
a : ZMod n
⊢ 2 * a = 0 ↔ a = 0 ∨ 2 * val a = n

Next tactic:
cases n
theorem neg_eq_self_iff {n : ℕ} (a : ZMod n) : -a = a ↔ a = 0 ∨ 2 * a.val = n := by
  rw [neg_eq_iff_add_eq_zero, ← two_mul]
  cases n
  · 

Proof state:
case zero
a : ZMod Nat.zero
⊢ 2 * a = 0 ↔ a = 0 ∨ 2 * val a = Nat.zero

Next tactic:
erw [@mul_eq_zero ℤ, @mul_eq_zero ℕ, val_eq_zero]
theorem neg_eq_self_iff {n : ℕ} (a : ZMod n) : -a = a ↔ a = 0 ∨ 2 * a.val = n := by
  rw [neg_eq_iff_add_eq_zero, ← two_mul]
  cases n
  · erw [@mul_eq_zero ℤ, @mul_eq_zero ℕ, val_eq_zero]
    

Proof state:
case zero
a : ZMod Nat.zero
⊢ 2 = 0 ∨ a = 0 ↔ a = 0 ∨ 2 = 0 ∨ a = 0

Next tactic:
exact
      ⟨fun h => h.elim (by simp) Or.inl, fun h =>
        Or.inr (h.elim id fun h => h.elim (by simp) id)⟩
theorem neg_eq_self_iff {n : ℕ} (a : ZMod n) : -a = a ↔ a = 0 ∨ 2 * a.val = n := by
  rw [neg_eq_iff_add_eq_zero, ← two_mul]
  cases n
  · erw [@mul_eq_zero ℤ, @mul_eq_zero ℕ, val_eq_zero]
    exact
      ⟨fun h => h.elim (by 

Proof state:
a : ZMod Nat.zero
h : 2 = 0 ∨ a = 0
⊢ 2 = 0 → a = 0 ∨ 2 = 0 ∨ a = 0

Next tactic:
simp
theorem neg_eq_self_iff {n : ℕ} (a : ZMod n) : -a = a ↔ a = 0 ∨ 2 * a.val = n := by
  rw [neg_eq_iff_add_eq_zero, ← two_mul]
  cases n
  · erw [@mul_eq_zero ℤ, @mul_eq_zero ℕ, val_eq_zero]
    exact
      ⟨fun h => h.elim (by simp) Or.inl, fun h =>
        Or.inr (h.elim id fun h => h.elim (by 

Proof state:
a : ZMod Nat.zero
h✝ : a = 0 ∨ 2 = 0 ∨ a = 0
h : 2 = 0 ∨ a = 0
⊢ 2 = 0 → a = 0

Next tactic:
simp
theorem neg_eq_self_iff {n : ℕ} (a : ZMod n) : -a = a ↔ a = 0 ∨ 2 * a.val = n := by
  rw [neg_eq_iff_add_eq_zero, ← two_mul]
  cases n
  · erw [@mul_eq_zero ℤ, @mul_eq_zero ℕ, val_eq_zero]
    exact
      ⟨fun h => h.elim (by simp) Or.inl, fun h =>
        Or.inr (h.elim id fun h => h.elim (by simp) id)⟩
  

Proof state:
case succ
n✝ : ℕ
a : ZMod (Nat.succ n✝)
⊢ 2 * a = 0 ↔ a = 0 ∨ 2 * val a = Nat.succ n✝

Next tactic:
conv_lhs =>
    rw [← a.nat_cast_zmod_val, ← Nat.cast_two, ← Nat.cast_mul, nat_cast_zmod_eq_zero_iff_dvd]
theorem neg_eq_self_iff {n : ℕ} (a : ZMod n) : -a = a ↔ a = 0 ∨ 2 * a.val = n := by
  rw [neg_eq_iff_add_eq_zero, ← two_mul]
  cases n
  · erw [@mul_eq_zero ℤ, @mul_eq_zero ℕ, val_eq_zero]
    exact
      ⟨fun h => h.elim (by simp) Or.inl, fun h =>
        Or.inr (h.elim id fun h => h.elim (by simp) id)⟩
  conv_lhs =>
    

Proof state:
n✝ : ℕ
a : ZMod (Nat.succ n✝)
| 2 * a = 0

Next tactic:
rw [← a.nat_cast_zmod_val, ← Nat.cast_two, ← Nat.cast_mul, nat_cast_zmod_eq_zero_iff_dvd]
theorem neg_eq_self_iff {n : ℕ} (a : ZMod n) : -a = a ↔ a = 0 ∨ 2 * a.val = n := by
  rw [neg_eq_iff_add_eq_zero, ← two_mul]
  cases n
  · erw [@mul_eq_zero ℤ, @mul_eq_zero ℕ, val_eq_zero]
    exact
      ⟨fun h => h.elim (by simp) Or.inl, fun h =>
        Or.inr (h.elim id fun h => h.elim (by simp) id)⟩
  conv_lhs =>
    rw [← a.nat_cast_zmod_val, ← Nat.cast_two, ← Nat.cast_mul, nat_cast_zmod_eq_zero_iff_dvd]
  

Proof state:
case succ
n✝ : ℕ
a : ZMod (Nat.succ n✝)
⊢ Nat.succ n✝ ∣ 2 * val a ↔ a = 0 ∨ 2 * val a = Nat.succ n✝

Next tactic:
constructor
theorem neg_eq_self_iff {n : ℕ} (a : ZMod n) : -a = a ↔ a = 0 ∨ 2 * a.val = n := by
  rw [neg_eq_iff_add_eq_zero, ← two_mul]
  cases n
  · erw [@mul_eq_zero ℤ, @mul_eq_zero ℕ, val_eq_zero]
    exact
      ⟨fun h => h.elim (by simp) Or.inl, fun h =>
        Or.inr (h.elim id fun h => h.elim (by simp) id)⟩
  conv_lhs =>
    rw [← a.nat_cast_zmod_val, ← Nat.cast_two, ← Nat.cast_mul, nat_cast_zmod_eq_zero_iff_dvd]
  constructor
  · 

Proof state:
case succ.mp
n✝ : ℕ
a : ZMod (Nat.succ n✝)
⊢ Nat.succ n✝ ∣ 2 * val a → a = 0 ∨ 2 * val a = Nat.succ n✝

Next tactic:
rintro ⟨m, he⟩
theorem neg_eq_self_iff {n : ℕ} (a : ZMod n) : -a = a ↔ a = 0 ∨ 2 * a.val = n := by
  rw [neg_eq_iff_add_eq_zero, ← two_mul]
  cases n
  · erw [@mul_eq_zero ℤ, @mul_eq_zero ℕ, val_eq_zero]
    exact
      ⟨fun h => h.elim (by simp) Or.inl, fun h =>
        Or.inr (h.elim id fun h => h.elim (by simp) id)⟩
  conv_lhs =>
    rw [← a.nat_cast_zmod_val, ← Nat.cast_two, ← Nat.cast_mul, nat_cast_zmod_eq_zero_iff_dvd]
  constructor
  · rintro ⟨m, he⟩
    

Proof state:
case succ.mp.intro
n✝ : ℕ
a : ZMod (Nat.succ n✝)
m : ℕ
he : 2 * val a = Nat.succ n✝ * m
⊢ a = 0 ∨ 2 * val a = Nat.succ n✝

Next tactic:
cases' m with m
theorem neg_eq_self_iff {n : ℕ} (a : ZMod n) : -a = a ↔ a = 0 ∨ 2 * a.val = n := by
  rw [neg_eq_iff_add_eq_zero, ← two_mul]
  cases n
  · erw [@mul_eq_zero ℤ, @mul_eq_zero ℕ, val_eq_zero]
    exact
      ⟨fun h => h.elim (by simp) Or.inl, fun h =>
        Or.inr (h.elim id fun h => h.elim (by simp) id)⟩
  conv_lhs =>
    rw [← a.nat_cast_zmod_val, ← Nat.cast_two, ← Nat.cast_mul, nat_cast_zmod_eq_zero_iff_dvd]
  constructor
  · rintro ⟨m, he⟩
    cases' m with m
    · 

Proof state:
case succ.mp.intro.zero
n✝ : ℕ
a : ZMod (Nat.succ n✝)
he : 2 * val a = Nat.succ n✝ * Nat.zero
⊢ a = 0 ∨ 2 * val a = Nat.succ n✝

Next tactic:
erw [mul_zero, mul_eq_zero] at he
theorem neg_eq_self_iff {n : ℕ} (a : ZMod n) : -a = a ↔ a = 0 ∨ 2 * a.val = n := by
  rw [neg_eq_iff_add_eq_zero, ← two_mul]
  cases n
  · erw [@mul_eq_zero ℤ, @mul_eq_zero ℕ, val_eq_zero]
    exact
      ⟨fun h => h.elim (by simp) Or.inl, fun h =>
        Or.inr (h.elim id fun h => h.elim (by simp) id)⟩
  conv_lhs =>
    rw [← a.nat_cast_zmod_val, ← Nat.cast_two, ← Nat.cast_mul, nat_cast_zmod_eq_zero_iff_dvd]
  constructor
  · rintro ⟨m, he⟩
    cases' m with m
    · erw [mul_zero, mul_eq_zero] at he
      

Proof state:
case succ.mp.intro.zero
n✝ : ℕ
a : ZMod (Nat.succ n✝)
he : 2 = 0 ∨ val a = 0
⊢ a = 0 ∨ 2 * val a = Nat.succ n✝

Next tactic:
rcases he with (⟨⟨⟩⟩ | he)
theorem neg_eq_self_iff {n : ℕ} (a : ZMod n) : -a = a ↔ a = 0 ∨ 2 * a.val = n := by
  rw [neg_eq_iff_add_eq_zero, ← two_mul]
  cases n
  · erw [@mul_eq_zero ℤ, @mul_eq_zero ℕ, val_eq_zero]
    exact
      ⟨fun h => h.elim (by simp) Or.inl, fun h =>
        Or.inr (h.elim id fun h => h.elim (by simp) id)⟩
  conv_lhs =>
    rw [← a.nat_cast_zmod_val, ← Nat.cast_two, ← Nat.cast_mul, nat_cast_zmod_eq_zero_iff_dvd]
  constructor
  · rintro ⟨m, he⟩
    cases' m with m
    · erw [mul_zero, mul_eq_zero] at he
      rcases he with (⟨⟨⟩⟩ | he)
      

Proof state:
case succ.mp.intro.zero.inr
n✝ : ℕ
a : ZMod (Nat.succ n✝)
he : val a = 0
⊢ a = 0 ∨ 2 * val a = Nat.succ n✝

Next tactic:
exact Or.inl (a.val_eq_zero.1 he)
theorem neg_eq_self_iff {n : ℕ} (a : ZMod n) : -a = a ↔ a = 0 ∨ 2 * a.val = n := by
  rw [neg_eq_iff_add_eq_zero, ← two_mul]
  cases n
  · erw [@mul_eq_zero ℤ, @mul_eq_zero ℕ, val_eq_zero]
    exact
      ⟨fun h => h.elim (by simp) Or.inl, fun h =>
        Or.inr (h.elim id fun h => h.elim (by simp) id)⟩
  conv_lhs =>
    rw [← a.nat_cast_zmod_val, ← Nat.cast_two, ← Nat.cast_mul, nat_cast_zmod_eq_zero_iff_dvd]
  constructor
  · rintro ⟨m, he⟩
    cases' m with m
    · erw [mul_zero, mul_eq_zero] at he
      rcases he with (⟨⟨⟩⟩ | he)
      exact Or.inl (a.val_eq_zero.1 he)
    

Proof state:
case succ.mp.intro.succ
n✝ : ℕ
a : ZMod (Nat.succ n✝)
m : ℕ
he : 2 * val a = Nat.succ n✝ * Nat.succ m
⊢ a = 0 ∨ 2 * val a = Nat.succ n✝

Next tactic:
cases m
theorem neg_eq_self_iff {n : ℕ} (a : ZMod n) : -a = a ↔ a = 0 ∨ 2 * a.val = n := by
  rw [neg_eq_iff_add_eq_zero, ← two_mul]
  cases n
  · erw [@mul_eq_zero ℤ, @mul_eq_zero ℕ, val_eq_zero]
    exact
      ⟨fun h => h.elim (by simp) Or.inl, fun h =>
        Or.inr (h.elim id fun h => h.elim (by simp) id)⟩
  conv_lhs =>
    rw [← a.nat_cast_zmod_val, ← Nat.cast_two, ← Nat.cast_mul, nat_cast_zmod_eq_zero_iff_dvd]
  constructor
  · rintro ⟨m, he⟩
    cases' m with m
    · erw [mul_zero, mul_eq_zero] at he
      rcases he with (⟨⟨⟩⟩ | he)
      exact Or.inl (a.val_eq_zero.1 he)
    cases m
    · 

Proof state:
case succ.mp.intro.succ.zero
n✝ : ℕ
a : ZMod (Nat.succ n✝)
he : 2 * val a = Nat.succ n✝ * Nat.succ Nat.zero
⊢ a = 0 ∨ 2 * val a = Nat.succ n✝

Next tactic:
right
theorem neg_eq_self_iff {n : ℕ} (a : ZMod n) : -a = a ↔ a = 0 ∨ 2 * a.val = n := by
  rw [neg_eq_iff_add_eq_zero, ← two_mul]
  cases n
  · erw [@mul_eq_zero ℤ, @mul_eq_zero ℕ, val_eq_zero]
    exact
      ⟨fun h => h.elim (by simp) Or.inl, fun h =>
        Or.inr (h.elim id fun h => h.elim (by simp) id)⟩
  conv_lhs =>
    rw [← a.nat_cast_zmod_val, ← Nat.cast_two, ← Nat.cast_mul, nat_cast_zmod_eq_zero_iff_dvd]
  constructor
  · rintro ⟨m, he⟩
    cases' m with m
    · erw [mul_zero, mul_eq_zero] at he
      rcases he with (⟨⟨⟩⟩ | he)
      exact Or.inl (a.val_eq_zero.1 he)
    cases m
    · right
      

Proof state:
case succ.mp.intro.succ.zero.h
n✝ : ℕ
a : ZMod (Nat.succ n✝)
he : 2 * val a = Nat.succ n✝ * Nat.succ Nat.zero
⊢ 2 * val a = Nat.succ n✝

Next tactic:
rwa [show Nat.succ Nat.zero = 1 from rfl, mul_one] at he
theorem neg_eq_self_iff {n : ℕ} (a : ZMod n) : -a = a ↔ a = 0 ∨ 2 * a.val = n := by
  rw [neg_eq_iff_add_eq_zero, ← two_mul]
  cases n
  · erw [@mul_eq_zero ℤ, @mul_eq_zero ℕ, val_eq_zero]
    exact
      ⟨fun h => h.elim (by simp) Or.inl, fun h =>
        Or.inr (h.elim id fun h => h.elim (by simp) id)⟩
  conv_lhs =>
    rw [← a.nat_cast_zmod_val, ← Nat.cast_two, ← Nat.cast_mul, nat_cast_zmod_eq_zero_iff_dvd]
  constructor
  · rintro ⟨m, he⟩
    cases' m with m
    · erw [mul_zero, mul_eq_zero] at he
      rcases he with (⟨⟨⟩⟩ | he)
      exact Or.inl (a.val_eq_zero.1 he)
    cases m
    · right
      rwa [show Nat.succ Nat.zero = 1 from rfl, mul_one] at he
    

Proof state:
case succ.mp.intro.succ.succ
n✝¹ : ℕ
a : ZMod (Nat.succ n✝¹)
n✝ : ℕ
he : 2 * val a = Nat.succ n✝¹ * Nat.succ (Nat.succ n✝)
⊢ a = 0 ∨ 2 * val a = Nat.succ n✝¹

Next tactic:
refine' (a.val_lt.not_le <| Nat.le_of_mul_le_mul_left _ zero_lt_two).elim
theorem neg_eq_self_iff {n : ℕ} (a : ZMod n) : -a = a ↔ a = 0 ∨ 2 * a.val = n := by
  rw [neg_eq_iff_add_eq_zero, ← two_mul]
  cases n
  · erw [@mul_eq_zero ℤ, @mul_eq_zero ℕ, val_eq_zero]
    exact
      ⟨fun h => h.elim (by simp) Or.inl, fun h =>
        Or.inr (h.elim id fun h => h.elim (by simp) id)⟩
  conv_lhs =>
    rw [← a.nat_cast_zmod_val, ← Nat.cast_two, ← Nat.cast_mul, nat_cast_zmod_eq_zero_iff_dvd]
  constructor
  · rintro ⟨m, he⟩
    cases' m with m
    · erw [mul_zero, mul_eq_zero] at he
      rcases he with (⟨⟨⟩⟩ | he)
      exact Or.inl (a.val_eq_zero.1 he)
    cases m
    · right
      rwa [show Nat.succ Nat.zero = 1 from rfl, mul_one] at he
    refine' (a.val_lt.not_le <| Nat.le_of_mul_le_mul_left _ zero_lt_two).elim
    

Proof state:
case succ.mp.intro.succ.succ
n✝¹ : ℕ
a : ZMod (Nat.succ n✝¹)
n✝ : ℕ
he : 2 * val a = Nat.succ n✝¹ * Nat.succ (Nat.succ n✝)
⊢ 2 * Nat.succ n✝¹ ≤ 2 * val a

Next tactic:
rw [he, mul_comm]
theorem neg_eq_self_iff {n : ℕ} (a : ZMod n) : -a = a ↔ a = 0 ∨ 2 * a.val = n := by
  rw [neg_eq_iff_add_eq_zero, ← two_mul]
  cases n
  · erw [@mul_eq_zero ℤ, @mul_eq_zero ℕ, val_eq_zero]
    exact
      ⟨fun h => h.elim (by simp) Or.inl, fun h =>
        Or.inr (h.elim id fun h => h.elim (by simp) id)⟩
  conv_lhs =>
    rw [← a.nat_cast_zmod_val, ← Nat.cast_two, ← Nat.cast_mul, nat_cast_zmod_eq_zero_iff_dvd]
  constructor
  · rintro ⟨m, he⟩
    cases' m with m
    · erw [mul_zero, mul_eq_zero] at he
      rcases he with (⟨⟨⟩⟩ | he)
      exact Or.inl (a.val_eq_zero.1 he)
    cases m
    · right
      rwa [show Nat.succ Nat.zero = 1 from rfl, mul_one] at he
    refine' (a.val_lt.not_le <| Nat.le_of_mul_le_mul_left _ zero_lt_two).elim
    rw [he, mul_comm]
    

Proof state:
case succ.mp.intro.succ.succ
n✝¹ : ℕ
a : ZMod (Nat.succ n✝¹)
n✝ : ℕ
he : 2 * val a = Nat.succ n✝¹ * Nat.succ (Nat.succ n✝)
⊢ Nat.succ n✝¹ * 2 ≤ Nat.succ n✝¹ * Nat.succ (Nat.succ n✝)

Next tactic:
apply Nat.mul_le_mul_left
theorem neg_eq_self_iff {n : ℕ} (a : ZMod n) : -a = a ↔ a = 0 ∨ 2 * a.val = n := by
  rw [neg_eq_iff_add_eq_zero, ← two_mul]
  cases n
  · erw [@mul_eq_zero ℤ, @mul_eq_zero ℕ, val_eq_zero]
    exact
      ⟨fun h => h.elim (by simp) Or.inl, fun h =>
        Or.inr (h.elim id fun h => h.elim (by simp) id)⟩
  conv_lhs =>
    rw [← a.nat_cast_zmod_val, ← Nat.cast_two, ← Nat.cast_mul, nat_cast_zmod_eq_zero_iff_dvd]
  constructor
  · rintro ⟨m, he⟩
    cases' m with m
    · erw [mul_zero, mul_eq_zero] at he
      rcases he with (⟨⟨⟩⟩ | he)
      exact Or.inl (a.val_eq_zero.1 he)
    cases m
    · right
      rwa [show Nat.succ Nat.zero = 1 from rfl, mul_one] at he
    refine' (a.val_lt.not_le <| Nat.le_of_mul_le_mul_left _ zero_lt_two).elim
    rw [he, mul_comm]
    apply Nat.mul_le_mul_left
    

Proof state:
case succ.mp.intro.succ.succ.h
n✝¹ : ℕ
a : ZMod (Nat.succ n✝¹)
n✝ : ℕ
he : 2 * val a = Nat.succ n✝¹ * Nat.succ (Nat.succ n✝)
⊢ 2 ≤ Nat.succ (Nat.succ n✝)

Next tactic:
erw [Nat.succ_le_succ_iff, Nat.succ_le_succ_iff]
theorem neg_eq_self_iff {n : ℕ} (a : ZMod n) : -a = a ↔ a = 0 ∨ 2 * a.val = n := by
  rw [neg_eq_iff_add_eq_zero, ← two_mul]
  cases n
  · erw [@mul_eq_zero ℤ, @mul_eq_zero ℕ, val_eq_zero]
    exact
      ⟨fun h => h.elim (by simp) Or.inl, fun h =>
        Or.inr (h.elim id fun h => h.elim (by simp) id)⟩
  conv_lhs =>
    rw [← a.nat_cast_zmod_val, ← Nat.cast_two, ← Nat.cast_mul, nat_cast_zmod_eq_zero_iff_dvd]
  constructor
  · rintro ⟨m, he⟩
    cases' m with m
    · erw [mul_zero, mul_eq_zero] at he
      rcases he with (⟨⟨⟩⟩ | he)
      exact Or.inl (a.val_eq_zero.1 he)
    cases m
    · right
      rwa [show Nat.succ Nat.zero = 1 from rfl, mul_one] at he
    refine' (a.val_lt.not_le <| Nat.le_of_mul_le_mul_left _ zero_lt_two).elim
    rw [he, mul_comm]
    apply Nat.mul_le_mul_left
    erw [Nat.succ_le_succ_iff, Nat.succ_le_succ_iff]; 

Proof state:
case succ.mp.intro.succ.succ.h
n✝¹ : ℕ
a : ZMod (Nat.succ n✝¹)
n✝ : ℕ
he : 2 * val a = Nat.succ n✝¹ * Nat.succ (Nat.succ n✝)
⊢ 0 ≤ n✝

Next tactic:
simp
theorem neg_eq_self_iff {n : ℕ} (a : ZMod n) : -a = a ↔ a = 0 ∨ 2 * a.val = n := by
  rw [neg_eq_iff_add_eq_zero, ← two_mul]
  cases n
  · erw [@mul_eq_zero ℤ, @mul_eq_zero ℕ, val_eq_zero]
    exact
      ⟨fun h => h.elim (by simp) Or.inl, fun h =>
        Or.inr (h.elim id fun h => h.elim (by simp) id)⟩
  conv_lhs =>
    rw [← a.nat_cast_zmod_val, ← Nat.cast_two, ← Nat.cast_mul, nat_cast_zmod_eq_zero_iff_dvd]
  constructor
  · rintro ⟨m, he⟩
    cases' m with m
    · erw [mul_zero, mul_eq_zero] at he
      rcases he with (⟨⟨⟩⟩ | he)
      exact Or.inl (a.val_eq_zero.1 he)
    cases m
    · right
      rwa [show Nat.succ Nat.zero = 1 from rfl, mul_one] at he
    refine' (a.val_lt.not_le <| Nat.le_of_mul_le_mul_left _ zero_lt_two).elim
    rw [he, mul_comm]
    apply Nat.mul_le_mul_left
    erw [Nat.succ_le_succ_iff, Nat.succ_le_succ_iff]; simp
  · 

Proof state:
case succ.mpr
n✝ : ℕ
a : ZMod (Nat.succ n✝)
⊢ a = 0 ∨ 2 * val a = Nat.succ n✝ → Nat.succ n✝ ∣ 2 * val a

Next tactic:
rintro (rfl | h)