l3lab/ntp-mathlib huggingface dataset:
/-- The identity between `ZMod m` and `ZMod n` when `m = n`, as a ring isomorphism. -/
def ringEquivCongr {m n : ℕ} (h : m = n) : ZMod m ≃+* ZMod n := by
  cases' m with m <;> cases' n with n
  · exact RingEquiv.refl _
  · exfalso
    exact n.succ_ne_zero h.symm
  · exfalso
    exact m.succ_ne_zero h
  · exact
      { Fin.castIso h with
        map_mul' := fun a b => by
          dsimp [ZMod]
          ext
          rw [Fin.coe_cast, Fin.coe_mul, Fin.coe_mul, Fin.coe_cast, Fin.coe_cast, ← h]
        map_add' := fun a b => by
          

Proof state:
n✝ : ℕ
R : Type u_1
inst✝¹ : Ring R
inst✝ : CharP R n✝
m n : ℕ
h : Nat.succ m = Nat.succ n
src✝ : Fin (Nat.succ m) ≃o Fin (Nat.succ n) := Fin.castIso h
a b : ZMod (Nat.succ m)
⊢ Equiv.toFun src✝.toEquiv (a + b) = Equiv.toFun src✝.toEquiv a + Equiv.toFun src✝.toEquiv b

Next tactic:
dsimp [ZMod]
/-- The identity between `ZMod m` and `ZMod n` when `m = n`, as a ring isomorphism. -/
def ringEquivCongr {m n : ℕ} (h : m = n) : ZMod m ≃+* ZMod n := by
  cases' m with m <;> cases' n with n
  · exact RingEquiv.refl _
  · exfalso
    exact n.succ_ne_zero h.symm
  · exfalso
    exact m.succ_ne_zero h
  · exact
      { Fin.castIso h with
        map_mul' := fun a b => by
          dsimp [ZMod]
          ext
          rw [Fin.coe_cast, Fin.coe_mul, Fin.coe_mul, Fin.coe_cast, Fin.coe_cast, ← h]
        map_add' := fun a b => by
          dsimp [ZMod]
          

Proof state:
n✝ : ℕ
R : Type u_1
inst✝¹ : Ring R
inst✝ : CharP R n✝
m n : ℕ
h : Nat.succ m = Nat.succ n
src✝ : Fin (Nat.succ m) ≃o Fin (Nat.succ n) := Fin.castIso h
a b : ZMod (Nat.succ m)
⊢ Fin.cast h (a + b) = Fin.cast h a + Fin.cast h b

Next tactic:
ext
/-- The identity between `ZMod m` and `ZMod n` when `m = n`, as a ring isomorphism. -/
def ringEquivCongr {m n : ℕ} (h : m = n) : ZMod m ≃+* ZMod n := by
  cases' m with m <;> cases' n with n
  · exact RingEquiv.refl _
  · exfalso
    exact n.succ_ne_zero h.symm
  · exfalso
    exact m.succ_ne_zero h
  · exact
      { Fin.castIso h with
        map_mul' := fun a b => by
          dsimp [ZMod]
          ext
          rw [Fin.coe_cast, Fin.coe_mul, Fin.coe_mul, Fin.coe_cast, Fin.coe_cast, ← h]
        map_add' := fun a b => by
          dsimp [ZMod]
          ext
          

Proof state:
case h
n✝ : ℕ
R : Type u_1
inst✝¹ : Ring R
inst✝ : CharP R n✝
m n : ℕ
h : Nat.succ m = Nat.succ n
src✝ : Fin (Nat.succ m) ≃o Fin (Nat.succ n) := Fin.castIso h
a b : ZMod (Nat.succ m)
⊢ ↑(Fin.cast h (a + b)) = ↑(Fin.cast h a + Fin.cast h b)

Next tactic:
rw [Fin.coe_cast, Fin.val_add, Fin.val_add, Fin.coe_cast, Fin.coe_cast, ← h]
theorem nat_cast_eq_nat_cast_iff (a b c : ℕ) : (a : ZMod c) = (b : ZMod c) ↔ a ≡ b [MOD c] := by
  

Proof state:
a b c : ℕ
⊢ ↑a = ↑b ↔ a ≡ b [MOD c]

Next tactic:
simpa [Int.coe_nat_modEq_iff] using ZMod.int_cast_eq_int_cast_iff a b c
theorem int_cast_zmod_eq_zero_iff_dvd (a : ℤ) (b : ℕ) : (a : ZMod b) = 0 ↔ (b : ℤ) ∣ a := by
  

Proof state:
a : ℤ
b : ℕ
⊢ ↑a = 0 ↔ ↑b ∣ a

Next tactic:
rw [← Int.cast_zero, ZMod.int_cast_eq_int_cast_iff, Int.modEq_zero_iff_dvd]
theorem int_cast_eq_int_cast_iff_dvd_sub (a b : ℤ) (c : ℕ) : (a : ZMod c) = ↑b ↔ ↑c ∣ b - a := by
  

Proof state:
a b : ℤ
c : ℕ
⊢ ↑a = ↑b ↔ ↑c ∣ b - a

Next tactic:
rw [ZMod.int_cast_eq_int_cast_iff, Int.modEq_iff_dvd]
theorem nat_cast_zmod_eq_zero_iff_dvd (a b : ℕ) : (a : ZMod b) = 0 ↔ b ∣ a := by
  

Proof state:
a b : ℕ
⊢ ↑a = 0 ↔ b ∣ a

Next tactic:
rw [← Nat.cast_zero, ZMod.nat_cast_eq_nat_cast_iff, Nat.modEq_zero_iff_dvd]
theorem val_int_cast {n : ℕ} (a : ℤ) [NeZero n] : ↑(a : ZMod n).val = a % n := by
  

Proof state:
n : ℕ
a : ℤ
inst✝ : NeZero n
⊢ ↑(val ↑a) = a % ↑n

Next tactic:
have hle : (0 : ℤ) ≤ ↑(a : ZMod n).val := Int.coe_nat_nonneg _
theorem val_int_cast {n : ℕ} (a : ℤ) [NeZero n] : ↑(a : ZMod n).val = a % n := by
  have hle : (0 : ℤ) ≤ ↑(a : ZMod n).val := Int.coe_nat_nonneg _
  

Proof state:
n : ℕ
a : ℤ
inst✝ : NeZero n
hle : 0 ≤ ↑(val ↑a)
⊢ ↑(val ↑a) = a % ↑n

Next tactic:
have hlt : ↑(a : ZMod n).val < (n : ℤ) := Int.ofNat_lt.mpr (ZMod.val_lt a)
theorem val_int_cast {n : ℕ} (a : ℤ) [NeZero n] : ↑(a : ZMod n).val = a % n := by
  have hle : (0 : ℤ) ≤ ↑(a : ZMod n).val := Int.coe_nat_nonneg _
  have hlt : ↑(a : ZMod n).val < (n : ℤ) := Int.ofNat_lt.mpr (ZMod.val_lt a)
  

Proof state:
n : ℕ
a : ℤ
inst✝ : NeZero n
hle : 0 ≤ ↑(val ↑a)
hlt : ↑(val ↑a) < ↑n
⊢ ↑(val ↑a) = a % ↑n

Next tactic:
refine' (Int.emod_eq_of_lt hle hlt).symm.trans _
theorem val_int_cast {n : ℕ} (a : ℤ) [NeZero n] : ↑(a : ZMod n).val = a % n := by
  have hle : (0 : ℤ) ≤ ↑(a : ZMod n).val := Int.coe_nat_nonneg _
  have hlt : ↑(a : ZMod n).val < (n : ℤ) := Int.ofNat_lt.mpr (ZMod.val_lt a)
  refine' (Int.emod_eq_of_lt hle hlt).symm.trans _
  

Proof state:
n : ℕ
a : ℤ
inst✝ : NeZero n
hle : 0 ≤ ↑(val ↑a)
hlt : ↑(val ↑a) < ↑n
⊢ ↑(val ↑a) % ↑n = a % ↑n

Next tactic:
rw [← ZMod.int_cast_eq_int_cast_iff', Int.cast_ofNat, ZMod.nat_cast_val, ZMod.cast_id]
theorem coe_int_cast {n : ℕ} (a : ℤ) : ↑(a : ZMod n) = a % n := by
  

Proof state:
n : ℕ
a : ℤ
⊢ ↑↑a = a % ↑n

Next tactic:
cases n
theorem coe_int_cast {n : ℕ} (a : ℤ) : ↑(a : ZMod n) = a % n := by
  cases n
  · 

Proof state:
case zero
a : ℤ
⊢ ↑↑a = a % ↑Nat.zero

Next tactic:
rw [Int.ofNat_zero, Int.emod_zero, Int.cast_id]
theorem coe_int_cast {n : ℕ} (a : ℤ) : ↑(a : ZMod n) = a % n := by
  cases n
  · rw [Int.ofNat_zero, Int.emod_zero, Int.cast_id]; 

Proof state:
case zero
a : ℤ
⊢ ↑a = a

Next tactic:
rfl
theorem coe_int_cast {n : ℕ} (a : ℤ) : ↑(a : ZMod n) = a % n := by
  cases n
  · rw [Int.ofNat_zero, Int.emod_zero, Int.cast_id]; rfl
  · 

Proof state:
case succ
a : ℤ
n✝ : ℕ
⊢ ↑↑a = a % ↑(Nat.succ n✝)

Next tactic:
rw [← val_int_cast, val]
theorem coe_int_cast {n : ℕ} (a : ℤ) : ↑(a : ZMod n) = a % n := by
  cases n
  · rw [Int.ofNat_zero, Int.emod_zero, Int.cast_id]; rfl
  · rw [← val_int_cast, val]; 

Proof state:
case succ
a : ℤ
n✝ : ℕ
⊢ ↑↑a =
    ↑((match (motive := (x : ℕ) → ZMod x → ℕ) Nat.succ n✝ with
        | 0 => Int.natAbs
        | Nat.succ n => Fin.val)
        ↑a)

Next tactic:
rfl
@[simp]
theorem val_neg_one (n : ℕ) : (-1 : ZMod n.succ).val = n := by
  

Proof state:
n : ℕ
⊢ val (-1) = n

Next tactic:
dsimp [val, Fin.coe_neg]
@[simp]
theorem val_neg_one (n : ℕ) : (-1 : ZMod n.succ).val = n := by
  dsimp [val, Fin.coe_neg]
  

Proof state:
n : ℕ
⊢ ↑(-1) = n

Next tactic:
cases n
@[simp]
theorem val_neg_one (n : ℕ) : (-1 : ZMod n.succ).val = n := by
  dsimp [val, Fin.coe_neg]
  cases n
  · 

Proof state:
case zero
⊢ ↑(-1) = Nat.zero

Next tactic:
simp [Nat.mod_one]
@[simp]
theorem val_neg_one (n : ℕ) : (-1 : ZMod n.succ).val = n := by
  dsimp [val, Fin.coe_neg]
  cases n
  · simp [Nat.mod_one]
  · 

Proof state:
case succ
n✝ : ℕ
⊢ ↑(-1) = Nat.succ n✝

Next tactic:
dsimp [ZMod, ZMod.cast]
@[simp]
theorem val_neg_one (n : ℕ) : (-1 : ZMod n.succ).val = n := by
  dsimp [val, Fin.coe_neg]
  cases n
  · simp [Nat.mod_one]
  · dsimp [ZMod, ZMod.cast]
    

Proof state:
case succ
n✝ : ℕ
⊢ ↑(-1) = Nat.succ n✝

Next tactic:
rw [Fin.coe_neg_one]
/-- `-1 : ZMod n` lifts to `n - 1 : R`. This avoids the characteristic assumption in `cast_neg`. -/
theorem cast_neg_one {R : Type*} [Ring R] (n : ℕ) : ↑(-1 : ZMod n) = (n - 1 : R) := by
  

Proof state:
R : Type u_1
inst✝ : Ring R
n : ℕ
⊢ ↑(-1) = ↑n - 1

Next tactic:
cases' n with n
/-- `-1 : ZMod n` lifts to `n - 1 : R`. This avoids the characteristic assumption in `cast_neg`. -/
theorem cast_neg_one {R : Type*} [Ring R] (n : ℕ) : ↑(-1 : ZMod n) = (n - 1 : R) := by
  cases' n with n
  · 

Proof state:
case zero
R : Type u_1
inst✝ : Ring R
⊢ ↑(-1) = ↑Nat.zero - 1

Next tactic:
dsimp [ZMod, ZMod.cast]
/-- `-1 : ZMod n` lifts to `n - 1 : R`. This avoids the characteristic assumption in `cast_neg`. -/
theorem cast_neg_one {R : Type*} [Ring R] (n : ℕ) : ↑(-1 : ZMod n) = (n - 1 : R) := by
  cases' n with n
  · dsimp [ZMod, ZMod.cast]; 

Proof state:
case zero
R : Type u_1
inst✝ : Ring R
⊢ ↑(-1) = ↑0 - 1

Next tactic:
simp
/-- `-1 : ZMod n` lifts to `n - 1 : R`. This avoids the characteristic assumption in `cast_neg`. -/
theorem cast_neg_one {R : Type*} [Ring R] (n : ℕ) : ↑(-1 : ZMod n) = (n - 1 : R) := by
  cases' n with n
  · dsimp [ZMod, ZMod.cast]; simp
  · 

Proof state:
case succ
R : Type u_1
inst✝ : Ring R
n : ℕ
⊢ ↑(-1) = ↑(Nat.succ n) - 1

Next tactic:
rw [← nat_cast_val, val_neg_one, Nat.cast_succ, add_sub_cancel]
theorem cast_sub_one {R : Type*} [Ring R] {n : ℕ} (k : ZMod n) :
    ((k - 1 : ZMod n) : R) = (if k = 0 then (n : R) else k) - 1 := by
  

Proof state:
R : Type u_1
inst✝ : Ring R
n : ℕ
k : ZMod n
⊢ ↑(k - 1) = (if k = 0 then ↑n else ↑k) - 1

Next tactic:
split_ifs with hk
theorem cast_sub_one {R : Type*} [Ring R] {n : ℕ} (k : ZMod n) :
    ((k - 1 : ZMod n) : R) = (if k = 0 then (n : R) else k) - 1 := by
  split_ifs with hk
  · 

Proof state:
case pos
R : Type u_1
inst✝ : Ring R
n : ℕ
k : ZMod n
hk : k = 0
⊢ ↑(k - 1) = ↑n - 1

Next tactic:
rw [hk, zero_sub, ZMod.cast_neg_one]
theorem cast_sub_one {R : Type*} [Ring R] {n : ℕ} (k : ZMod n) :
    ((k - 1 : ZMod n) : R) = (if k = 0 then (n : R) else k) - 1 := by
  split_ifs with hk
  · rw [hk, zero_sub, ZMod.cast_neg_one]
  · 

Proof state:
case neg
R : Type u_1
inst✝ : Ring R
n : ℕ
k : ZMod n
hk : ¬k = 0
⊢ ↑(k - 1) = ↑k - 1

Next tactic:
cases n
theorem cast_sub_one {R : Type*} [Ring R] {n : ℕ} (k : ZMod n) :
    ((k - 1 : ZMod n) : R) = (if k = 0 then (n : R) else k) - 1 := by
  split_ifs with hk
  · rw [hk, zero_sub, ZMod.cast_neg_one]
  · cases n
    · 

Proof state:
case neg.zero
R : Type u_1
inst✝ : Ring R
k : ZMod Nat.zero
hk : ¬k = 0
⊢ ↑(k - 1) = ↑k - 1

Next tactic:
dsimp [ZMod, ZMod.cast]
theorem cast_sub_one {R : Type*} [Ring R] {n : ℕ} (k : ZMod n) :
    ((k - 1 : ZMod n) : R) = (if k = 0 then (n : R) else k) - 1 := by
  split_ifs with hk
  · rw [hk, zero_sub, ZMod.cast_neg_one]
  · cases n
    · dsimp [ZMod, ZMod.cast]
      

Proof state:
case neg.zero
R : Type u_1
inst✝ : Ring R
k : ZMod Nat.zero
hk : ¬k = 0
⊢ ↑(k - 1) = ↑k - 1

Next tactic:
rw [Int.cast_sub, Int.cast_one]
theorem cast_sub_one {R : Type*} [Ring R] {n : ℕ} (k : ZMod n) :
    ((k - 1 : ZMod n) : R) = (if k = 0 then (n : R) else k) - 1 := by
  split_ifs with hk
  · rw [hk, zero_sub, ZMod.cast_neg_one]
  · cases n
    · dsimp [ZMod, ZMod.cast]
      rw [Int.cast_sub, Int.cast_one]
    · 

Proof state:
case neg.succ
R : Type u_1
inst✝ : Ring R
n✝ : ℕ
k : ZMod (Nat.succ n✝)
hk : ¬k = 0
⊢ ↑(k - 1) = ↑k - 1

Next tactic:
dsimp [ZMod, ZMod.cast, ZMod.val]
theorem cast_sub_one {R : Type*} [Ring R] {n : ℕ} (k : ZMod n) :
    ((k - 1 : ZMod n) : R) = (if k = 0 then (n : R) else k) - 1 := by
  split_ifs with hk
  · rw [hk, zero_sub, ZMod.cast_neg_one]
  · cases n
    · dsimp [ZMod, ZMod.cast]
      rw [Int.cast_sub, Int.cast_one]
    · dsimp [ZMod, ZMod.cast, ZMod.val]
      

Proof state:
case neg.succ
R : Type u_1
inst✝ : Ring R
n✝ : ℕ
k : ZMod (Nat.succ n✝)
hk : ¬k = 0
⊢ ↑↑(k - 1) = ↑↑k - 1

Next tactic:
rw [Fin.coe_sub_one, if_neg]
theorem cast_sub_one {R : Type*} [Ring R] {n : ℕ} (k : ZMod n) :
    ((k - 1 : ZMod n) : R) = (if k = 0 then (n : R) else k) - 1 := by
  split_ifs with hk
  · rw [hk, zero_sub, ZMod.cast_neg_one]
  · cases n
    · dsimp [ZMod, ZMod.cast]
      rw [Int.cast_sub, Int.cast_one]
    · dsimp [ZMod, ZMod.cast, ZMod.val]
      rw [Fin.coe_sub_one, if_neg]
      · 

Proof state:
case neg.succ
R : Type u_1
inst✝ : Ring R
n✝ : ℕ
k : ZMod (Nat.succ n✝)
hk : ¬k = 0
⊢ ↑(↑k - 1) = ↑↑k - 1

Next tactic:
rw [Nat.cast_sub, Nat.cast_one]
theorem cast_sub_one {R : Type*} [Ring R] {n : ℕ} (k : ZMod n) :
    ((k - 1 : ZMod n) : R) = (if k = 0 then (n : R) else k) - 1 := by
  split_ifs with hk
  · rw [hk, zero_sub, ZMod.cast_neg_one]
  · cases n
    · dsimp [ZMod, ZMod.cast]
      rw [Int.cast_sub, Int.cast_one]
    · dsimp [ZMod, ZMod.cast, ZMod.val]
      rw [Fin.coe_sub_one, if_neg]
      · rw [Nat.cast_sub, Nat.cast_one]
        

Proof state:
case neg.succ
R : Type u_1
inst✝ : Ring R
n✝ : ℕ
k : ZMod (Nat.succ n✝)
hk : ¬k = 0
⊢ 1 ≤ ↑k

Next tactic:
rwa [Fin.ext_iff, Fin.val_zero, ← Ne, ← Nat.one_le_iff_ne_zero] at hk
theorem cast_sub_one {R : Type*} [Ring R] {n : ℕ} (k : ZMod n) :
    ((k - 1 : ZMod n) : R) = (if k = 0 then (n : R) else k) - 1 := by
  split_ifs with hk
  · rw [hk, zero_sub, ZMod.cast_neg_one]
  · cases n
    · dsimp [ZMod, ZMod.cast]
      rw [Int.cast_sub, Int.cast_one]
    · dsimp [ZMod, ZMod.cast, ZMod.val]
      rw [Fin.coe_sub_one, if_neg]
      · rw [Nat.cast_sub, Nat.cast_one]
        rwa [Fin.ext_iff, Fin.val_zero, ← Ne, ← Nat.one_le_iff_ne_zero] at hk
      · 

Proof state:
case neg.succ.hnc
R : Type u_1
inst✝ : Ring R
n✝ : ℕ
k : ZMod (Nat.succ n✝)
hk : ¬k = 0
⊢ ¬k = 0

Next tactic:
exact hk
theorem nat_coe_zmod_eq_iff (p : ℕ) (n : ℕ) (z : ZMod p) [NeZero p] :
    ↑n = z ↔ ∃ k, n = z.val + p * k := by
  

Proof state:
p n : ℕ
z : ZMod p
inst✝ : NeZero p
⊢ ↑n = z ↔ ∃ k, n = val z + p * k

Next tactic:
constructor
theorem nat_coe_zmod_eq_iff (p : ℕ) (n : ℕ) (z : ZMod p) [NeZero p] :
    ↑n = z ↔ ∃ k, n = z.val + p * k := by
  constructor
  · 

Proof state:
case mp
p n : ℕ
z : ZMod p
inst✝ : NeZero p
⊢ ↑n = z → ∃ k, n = val z + p * k

Next tactic:
rintro rfl
theorem nat_coe_zmod_eq_iff (p : ℕ) (n : ℕ) (z : ZMod p) [NeZero p] :
    ↑n = z ↔ ∃ k, n = z.val + p * k := by
  constructor
  · rintro rfl
    

Proof state:
case mp
p n : ℕ
inst✝ : NeZero p
⊢ ∃ k, n = val ↑n + p * k

Next tactic:
refine' ⟨n / p, _⟩
theorem nat_coe_zmod_eq_iff (p : ℕ) (n : ℕ) (z : ZMod p) [NeZero p] :
    ↑n = z ↔ ∃ k, n = z.val + p * k := by
  constructor
  · rintro rfl
    refine' ⟨n / p, _⟩
    

Proof state:
case mp
p n : ℕ
inst✝ : NeZero p
⊢ n = val ↑n + p * (n / p)

Next tactic:
rw [val_nat_cast, Nat.mod_add_div]
theorem nat_coe_zmod_eq_iff (p : ℕ) (n : ℕ) (z : ZMod p) [NeZero p] :
    ↑n = z ↔ ∃ k, n = z.val + p * k := by
  constructor
  · rintro rfl
    refine' ⟨n / p, _⟩
    rw [val_nat_cast, Nat.mod_add_div]
  · 

Proof state:
case mpr
p n : ℕ
z : ZMod p
inst✝ : NeZero p
⊢ (∃ k, n = val z + p * k) → ↑n = z

Next tactic:
rintro ⟨k, rfl⟩
theorem nat_coe_zmod_eq_iff (p : ℕ) (n : ℕ) (z : ZMod p) [NeZero p] :
    ↑n = z ↔ ∃ k, n = z.val + p * k := by
  constructor
  · rintro rfl
    refine' ⟨n / p, _⟩
    rw [val_nat_cast, Nat.mod_add_div]
  · rintro ⟨k, rfl⟩
    

Proof state:
case mpr.intro
p : ℕ
z : ZMod p
inst✝ : NeZero p
k : ℕ
⊢ ↑(val z + p * k) = z

Next tactic:
rw [Nat.cast_add, nat_cast_zmod_val, Nat.cast_mul, nat_cast_self, zero_mul,
      add_zero]
theorem int_coe_zmod_eq_iff (p : ℕ) (n : ℤ) (z : ZMod p) [NeZero p] :
    ↑n = z ↔ ∃ k, n = z.val + p * k := by
  

Proof state:
p : ℕ
n : ℤ
z : ZMod p
inst✝ : NeZero p
⊢ ↑n = z ↔ ∃ k, n = ↑(val z) + ↑p * k

Next tactic:
constructor
theorem int_coe_zmod_eq_iff (p : ℕ) (n : ℤ) (z : ZMod p) [NeZero p] :
    ↑n = z ↔ ∃ k, n = z.val + p * k := by
  constructor
  · 

Proof state:
case mp
p : ℕ
n : ℤ
z : ZMod p
inst✝ : NeZero p
⊢ ↑n = z → ∃ k, n = ↑(val z) + ↑p * k

Next tactic:
rintro rfl
theorem int_coe_zmod_eq_iff (p : ℕ) (n : ℤ) (z : ZMod p) [NeZero p] :
    ↑n = z ↔ ∃ k, n = z.val + p * k := by
  constructor
  · rintro rfl
    

Proof state:
case mp
p : ℕ
n : ℤ
inst✝ : NeZero p
⊢ ∃ k, n = ↑(val ↑n) + ↑p * k

Next tactic:
refine' ⟨n / p, _⟩
theorem int_coe_zmod_eq_iff (p : ℕ) (n : ℤ) (z : ZMod p) [NeZero p] :
    ↑n = z ↔ ∃ k, n = z.val + p * k := by
  constructor
  · rintro rfl
    refine' ⟨n / p, _⟩
    

Proof state:
case mp
p : ℕ
n : ℤ
inst✝ : NeZero p
⊢ n = ↑(val ↑n) + ↑p * (n / ↑p)

Next tactic:
rw [val_int_cast, Int.emod_add_ediv]
theorem int_coe_zmod_eq_iff (p : ℕ) (n : ℤ) (z : ZMod p) [NeZero p] :
    ↑n = z ↔ ∃ k, n = z.val + p * k := by
  constructor
  · rintro rfl
    refine' ⟨n / p, _⟩
    rw [val_int_cast, Int.emod_add_ediv]
  · 

Proof state:
case mpr
p : ℕ
n : ℤ
z : ZMod p
inst✝ : NeZero p
⊢ (∃ k, n = ↑(val z) + ↑p * k) → ↑n = z

Next tactic:
rintro ⟨k, rfl⟩
theorem int_coe_zmod_eq_iff (p : ℕ) (n : ℤ) (z : ZMod p) [NeZero p] :
    ↑n = z ↔ ∃ k, n = z.val + p * k := by
  constructor
  · rintro rfl
    refine' ⟨n / p, _⟩
    rw [val_int_cast, Int.emod_add_ediv]
  · rintro ⟨k, rfl⟩
    

Proof state:
case mpr.intro
p : ℕ
z : ZMod p
inst✝ : NeZero p
k : ℤ
⊢ ↑(↑(val z) + ↑p * k) = z

Next tactic:
rw [Int.cast_add, Int.cast_mul, Int.cast_ofNat, Int.cast_ofNat, nat_cast_val,
      ZMod.nat_cast_self, zero_mul, add_zero, cast_id]
@[push_cast, simp]
theorem int_cast_mod (a : ℤ) (b : ℕ) : ((a % b : ℤ) : ZMod b) = (a : ZMod b) := by
  

Proof state:
a : ℤ
b : ℕ
⊢ ↑(a % ↑b) = ↑a

Next tactic:
rw [ZMod.int_cast_eq_int_cast_iff]
@[push_cast, simp]
theorem int_cast_mod (a : ℤ) (b : ℕ) : ((a % b : ℤ) : ZMod b) = (a : ZMod b) := by
  rw [ZMod.int_cast_eq_int_cast_iff]
  

Proof state:
a : ℤ
b : ℕ
⊢ a % ↑b ≡ a [ZMOD ↑b]

Next tactic:
apply Int.mod_modEq
theorem ker_int_castAddHom (n : ℕ) :
    (Int.castAddHom (ZMod n)).ker = AddSubgroup.zmultiples (n : ℤ) := by
  

Proof state:
n : ℕ
⊢ AddMonoidHom.ker (Int.castAddHom (ZMod n)) = AddSubgroup.zmultiples ↑n

Next tactic:
ext
theorem ker_int_castAddHom (n : ℕ) :
    (Int.castAddHom (ZMod n)).ker = AddSubgroup.zmultiples (n : ℤ) := by
  ext
  

Proof state:
case h
n : ℕ
x✝ : ℤ
⊢ x✝ ∈ AddMonoidHom.ker (Int.castAddHom (ZMod n)) ↔ x✝ ∈ AddSubgroup.zmultiples ↑n

Next tactic:
rw [Int.mem_zmultiples_iff, AddMonoidHom.mem_ker, Int.coe_castAddHom,
    int_cast_zmod_eq_zero_iff_dvd]
theorem ker_int_castRingHom (n : ℕ) :
    RingHom.ker (Int.castRingHom (ZMod n)) = Ideal.span ({(n : ℤ)} : Set ℤ) := by
  

Proof state:
n : ℕ
⊢ RingHom.ker (Int.castRingHom (ZMod n)) = Ideal.span {↑n}

Next tactic:
ext
theorem ker_int_castRingHom (n : ℕ) :
    RingHom.ker (Int.castRingHom (ZMod n)) = Ideal.span ({(n : ℤ)} : Set ℤ) := by
  ext
  

Proof state:
case h
n : ℕ
x✝ : ℤ
⊢ x✝ ∈ RingHom.ker (Int.castRingHom (ZMod n)) ↔ x✝ ∈ Ideal.span {↑n}

Next tactic:
rw [Ideal.mem_span_singleton, RingHom.mem_ker, Int.coe_castRingHom, int_cast_zmod_eq_zero_iff_dvd]
theorem cast_injective_of_lt {m n : ℕ} [nzm : NeZero m] (h : m < n) :
    Function.Injective (@cast (ZMod n) _ m) := by
  

Proof state:
m n : ℕ
nzm : NeZero m
h : m < n
⊢ Injective cast

Next tactic:
cases m with
  | zero => cases nzm; simp_all
  | succ m =>
    rintro ⟨x, hx⟩ ⟨y, hy⟩ f
    simp only [cast, val, nat_cast_eq_nat_cast_iff',
      Nat.mod_eq_of_lt (lt_trans hx h), Nat.mod_eq_of_lt (lt_trans hy h)] at f
    apply Fin.ext
    exact f
theorem cast_injective_of_lt {m n : ℕ} [nzm : NeZero m] (h : m < n) :
    Function.Injective (@cast (ZMod n) _ m) := by
  cases m with
  

Proof state:
case zero
n : ℕ
nzm : NeZero Nat.zero
h : Nat.zero < n
⊢ Injective cast

Next tactic:
| zero => cases nzm; simp_all
theorem cast_injective_of_lt {m n : ℕ} [nzm : NeZero m] (h : m < n) :
    Function.Injective (@cast (ZMod n) _ m) := by
  cases m with
  | zero => 

Proof state:
case zero
n : ℕ
nzm : NeZero Nat.zero
h : Nat.zero < n
⊢ Injective cast

Next tactic:
cases nzm
theorem cast_injective_of_lt {m n : ℕ} [nzm : NeZero m] (h : m < n) :
    Function.Injective (@cast (ZMod n) _ m) := by
  cases m with
  | zero => cases nzm; 

Proof state:
case zero.mk
n : ℕ
h : Nat.zero < n
out✝ : Nat.zero ≠ 0
⊢ Injective cast

Next tactic:
simp_all
theorem cast_injective_of_lt {m n : ℕ} [nzm : NeZero m] (h : m < n) :
    Function.Injective (@cast (ZMod n) _ m) := by
  cases m with
  | zero => cases nzm; simp_all
  

Proof state:
case succ
n m : ℕ
nzm : NeZero (Nat.succ m)
h : Nat.succ m < n
⊢ Injective cast

Next tactic:
| succ m =>
    rintro ⟨x, hx⟩ ⟨y, hy⟩ f
    simp only [cast, val, nat_cast_eq_nat_cast_iff',
      Nat.mod_eq_of_lt (lt_trans hx h), Nat.mod_eq_of_lt (lt_trans hy h)] at f
    apply Fin.ext
    exact f
theorem cast_injective_of_lt {m n : ℕ} [nzm : NeZero m] (h : m < n) :
    Function.Injective (@cast (ZMod n) _ m) := by
  cases m with
  | zero => cases nzm; simp_all
  | succ m =>
    

Proof state:
case succ
n m : ℕ
nzm : NeZero (Nat.succ m)
h : Nat.succ m < n
⊢ Injective cast

Next tactic:
rintro ⟨x, hx⟩ ⟨y, hy⟩ f
theorem cast_injective_of_lt {m n : ℕ} [nzm : NeZero m] (h : m < n) :
    Function.Injective (@cast (ZMod n) _ m) := by
  cases m with
  | zero => cases nzm; simp_all
  | succ m =>
    rintro ⟨x, hx⟩ ⟨y, hy⟩ f
    

Proof state:
case succ.mk.mk
n m : ℕ
nzm : NeZero (Nat.succ m)
h : Nat.succ m < n
x : ℕ
hx : x < m + 1
y : ℕ
hy : y < m + 1
f : ↑{ val := x, isLt := hx } = ↑{ val := y, isLt := hy }
⊢ { val := x, isLt := hx } = { val := y, isLt := hy }

Next tactic:
simp only [cast, val, nat_cast_eq_nat_cast_iff',
      Nat.mod_eq_of_lt (lt_trans hx h), Nat.mod_eq_of_lt (lt_trans hy h)] at f
theorem cast_injective_of_lt {m n : ℕ} [nzm : NeZero m] (h : m < n) :
    Function.Injective (@cast (ZMod n) _ m) := by
  cases m with
  | zero => cases nzm; simp_all
  | succ m =>
    rintro ⟨x, hx⟩ ⟨y, hy⟩ f
    simp only [cast, val, nat_cast_eq_nat_cast_iff',
      Nat.mod_eq_of_lt (lt_trans hx h), Nat.mod_eq_of_lt (lt_trans hy h)] at f
    

Proof state:
case succ.mk.mk
n m : ℕ
nzm : NeZero (Nat.succ m)
h : Nat.succ m < n
x : ℕ
hx : x < m + 1
y : ℕ
hy : y < m + 1
f : x = y
⊢ { val := x, isLt := hx } = { val := y, isLt := hy }

Next tactic:
apply Fin.ext
theorem cast_injective_of_lt {m n : ℕ} [nzm : NeZero m] (h : m < n) :
    Function.Injective (@cast (ZMod n) _ m) := by
  cases m with
  | zero => cases nzm; simp_all
  | succ m =>
    rintro ⟨x, hx⟩ ⟨y, hy⟩ f
    simp only [cast, val, nat_cast_eq_nat_cast_iff',
      Nat.mod_eq_of_lt (lt_trans hx h), Nat.mod_eq_of_lt (lt_trans hy h)] at f
    apply Fin.ext
    

Proof state:
case succ.mk.mk.h
n m : ℕ
nzm : NeZero (Nat.succ m)
h : Nat.succ m < n
x : ℕ
hx : x < m + 1
y : ℕ
hy : y < m + 1
f : x = y
⊢ ↑{ val := x, isLt := hx } = ↑{ val := y, isLt := hy }

Next tactic:
exact f
theorem cast_zmod_eq_zero_iff_of_lt {m n : ℕ} [NeZero m] (h : m < n) (a : ZMod m) :
    (a : ZMod n) = 0 ↔ a = 0 := by
  

Proof state:
m n : ℕ
inst✝ : NeZero m
h : m < n
a : ZMod m
⊢ ↑a = 0 ↔ a = 0

Next tactic:
rw [← ZMod.cast_zero (n := m)]
theorem cast_zmod_eq_zero_iff_of_lt {m n : ℕ} [NeZero m] (h : m < n) (a : ZMod m) :
    (a : ZMod n) = 0 ↔ a = 0 := by
  rw [← ZMod.cast_zero (n := m)]
  

Proof state:
m n : ℕ
inst✝ : NeZero m
h : m < n
a : ZMod m
⊢ ↑a = ↑0 ↔ a = 0

Next tactic:
exact Injective.eq_iff' (cast_injective_of_lt h) rfl
@[simp]
theorem nat_cast_toNat (p : ℕ) : ∀ {z : ℤ} (_h : 0 ≤ z), (z.toNat : ZMod p) = z
  | (n : ℕ), _h => by 

Proof state:
p n : ℕ
_h : 0 ≤ ↑n
⊢ ↑(Int.toNat ↑n) = ↑↑n

Next tactic:
simp only [Int.cast_ofNat, Int.toNat_coe_nat]
@[simp]
theorem nat_cast_toNat (p : ℕ) : ∀ {z : ℤ} (_h : 0 ≤ z), (z.toNat : ZMod p) = z
  | (n : ℕ), _h => by simp only [Int.cast_ofNat, Int.toNat_coe_nat]
  | Int.negSucc n, h => by 

Proof state:
p n : ℕ
h : 0 ≤ Int.negSucc n
⊢ ↑(Int.toNat (Int.negSucc n)) = ↑(Int.negSucc n)

Next tactic:
simp at h
theorem val_injective (n : ℕ) [NeZero n] : Function.Injective (val : ZMod n → ℕ) := by
  

Proof state:
n : ℕ
inst✝ : NeZero n
⊢ Injective val

Next tactic:
cases n
theorem val_injective (n : ℕ) [NeZero n] : Function.Injective (val : ZMod n → ℕ) := by
  cases n
  · 

Proof state:
case zero
inst✝ : NeZero Nat.zero
⊢ Injective val

Next tactic:
cases NeZero.ne 0 rfl
theorem val_injective (n : ℕ) [NeZero n] : Function.Injective (val : ZMod n → ℕ) := by
  cases n
  · cases NeZero.ne 0 rfl
  

Proof state:
case succ
n✝ : ℕ
inst✝ : NeZero (Nat.succ n✝)
⊢ Injective val

Next tactic:
intro a b h
theorem val_injective (n : ℕ) [NeZero n] : Function.Injective (val : ZMod n → ℕ) := by
  cases n
  · cases NeZero.ne 0 rfl
  intro a b h
  

Proof state:
case succ
n✝ : ℕ
inst✝ : NeZero (Nat.succ n✝)
a b : ZMod (Nat.succ n✝)
h : val a = val b
⊢ a = b

Next tactic:
dsimp [ZMod]
theorem val_injective (n : ℕ) [NeZero n] : Function.Injective (val : ZMod n → ℕ) := by
  cases n
  · cases NeZero.ne 0 rfl
  intro a b h
  dsimp [ZMod]
  

Proof state:
case succ
n✝ : ℕ
inst✝ : NeZero (Nat.succ n✝)
a b : ZMod (Nat.succ n✝)
h : val a = val b
⊢ a = b

Next tactic:
ext
theorem val_injective (n : ℕ) [NeZero n] : Function.Injective (val : ZMod n → ℕ) := by
  cases n
  · cases NeZero.ne 0 rfl
  intro a b h
  dsimp [ZMod]
  ext
  

Proof state:
case succ.h
n✝ : ℕ
inst✝ : NeZero (Nat.succ n✝)
a b : ZMod (Nat.succ n✝)
h : val a = val b
⊢ ↑a = ↑b

Next tactic:
exact h
theorem val_one_eq_one_mod (n : ℕ) : (1 : ZMod n).val = 1 % n := by
  

Proof state:
n : ℕ
⊢ val 1 = 1 % n

Next tactic:
rw [← Nat.cast_one, val_nat_cast]