[System] You are Leanstral, a Lean 4 proof assistant. Complete the task below using the provided Lean source context. The target mathlib commit is 5e932f97dd25535344f80f9dd8da3aab83df0fe6 (module Mathlib.Data.DFinsupp.Defs).

[User]
Prove the following theorem. The retrieved context below may help.

```lean
theorem coe_zsmul [∀ i, AddGroup (β i)] (b : ℤ) (v : Π₀ i, β i) : ⇑(b • v) = b • ⇑v
```

## Retrieved context
-- snippet 1
```lean
-- Mathlib.Data.DFinsupp.Defs.instDFunLike (L77-L82)
instance instDFunLike : DFunLike (Π₀ i, β i) ι β :=
⟨fun f => f.toFun, fun ⟨f₁, s₁⟩ ⟨f₂, s₁⟩ ↦ fun (h : f₁ = f₂) ↦ by
    subst h
    congr
    subsingleton ⟩
```

-- snippet 2
```lean
-- Mathlib.Data.DFinsupp.Defs.toFun_eq_coe (L84-L86)
theorem toFun_eq_coe (f : Π₀ i, β i) : f.toFun = f :=
rfl
```

-- snippet 3
```lean
-- Mathlib.Data.DFinsupp.Defs.ext (L88-L90)
theorem ext {f g : Π₀ i, β i} (h : ∀ i, f i = g i) : f = g :=
DFunLike.ext _ _ h
```

-- snippet 4
```lean
-- Mathlib.Data.DFinsupp.Defs.ne_iff (L91-L92)
lemma ne_iff {f g : Π₀ i, β i} : f ≠ g ↔ ∃ i, f i ≠ g i := DFunLike.ne_iff
```

-- snippet 5
```lean
-- Mathlib.Data.DFinsupp.Defs.zero_apply (L103-L116)
theorem zero_apply (i : ι) : (0 : Π₀ i, β i) i = 0 :=
rfl

/-- The composition of `f : β₁ → β₂` and `g : Π₀ i, β₁ i` is
  `mapRange f hf g : Π₀ i, β₂ i`, well defined when `f 0 = 0`.

This preserves the structure on `f`, and exists in various bundled forms for when `f` is itself
bundled:

* `DFinsupp.mapRange.addMonoidHom`
* `DFinsupp.mapRange.addEquiv`
* `dfinsupp.mapRange.linearMap`
* `dfinsupp.mapRange.linearEquiv`
-/
```

-- snippet 6
```lean
-- Mathlib.Data.DFinsupp.Defs.mapRange (L117-L121)
def mapRange (f : ∀ i, β₁ i → β₂ i) (hf : ∀ i, f i 0 = 0) (x : Π₀ i, β₁ i) : Π₀ i, β₂ i :=
⟨fun i => f i (x i),
    x.support'.map fun s => ⟨s.1, fun i => (s.2 i).imp_right fun h : x i = 0 => by
      rw [← hf i, ← h]⟩⟩
```

-- snippet 7
```lean
-- Mathlib.Data.DFinsupp.Defs.mapRange_apply (L123-L126)
theorem mapRange_apply (f : ∀ i, β₁ i → β₂ i) (hf : ∀ i, f i 0 = 0) (g : Π₀ i, β₁ i) (i : ι) :
    mapRange f hf g i = f i (g i) :=
rfl
```

-- snippet 8
```lean
-- Mathlib.Data.DFinsupp.Defs.mapRange_id (L128-L132)
theorem mapRange_id (h : ∀ i, id (0 : β₁ i) = 0 := fun _ => rfl) (g : Π₀ i : ι, β₁ i) :
mapRange (fun i => (id : β₁ i → β₁ i)) h g = g := by
  ext
  rfl
```

-- snippet 9
```lean
-- Mathlib.Data.DFinsupp.Defs.mapRange_comp (L133-L138)
theorem mapRange_comp (f : ∀ i, β₁ i → β₂ i) (f₂ : ∀ i, β i → β₁ i) (hf : ∀ i, f i 0 = 0)
    (hf₂ : ∀ i, f₂ i 0 = 0) (h : ∀ i, (f i ∘ f₂ i) 0 = 0) (g : Π₀ i : ι, β i) :
    mapRange (fun i => f i ∘ f₂ i) h g = mapRange f hf (mapRange f₂ hf₂ g) := by
ext
  simp only [mapRange_apply]; rfl
```

-- snippet 10
```lean
-- Mathlib.Data.DFinsupp.Defs.mapRange_zero (L140-L146)
theorem mapRange_zero (f : ∀ i, β₁ i → β₂ i) (hf : ∀ i, f i 0 = 0) :
    mapRange f hf (0 : Π₀ i, β₁ i) = 0 := by
ext
  simp only [mapRange_apply, coe_zero, Pi.zero_apply, hf]

/-- Let `f i` be a binary operation `β₁ i → β₂ i → β i` such that `f i 0 0 = 0`.
Then `zipWith f hf` is a binary operation `Π₀ i, β₁ i → Π₀ i, β₂ i → Π₀ i, β i`. -/
```

-- snippet 11
```lean
-- Mathlib.Data.DFinsupp.Defs.zipWith (L147-L158)
def zipWith (f : ∀ i, β₁ i → β₂ i → β i) (hf : ∀ i, f i 0 0 = 0) (x : Π₀ i, β₁ i) (y : Π₀ i, β₂ i) :
    Π₀ i, β i :=
⟨fun i => f i (x i) (y i), by
    refine x.support'.bind fun xs => ?_
    refine y.support'.map fun ys => ?_
    refine ⟨xs + ys, fun i => ?_⟩
    obtain h1 | (h1 : x i = 0) := xs.prop i
    · grind
    obtain h2 | (h2 : y i = 0) := ys.prop i
    · grind
    grind⟩
```

-- snippet 12
```lean
-- Mathlib.Data.DFinsupp.Defs.zipWith_apply (L160-L169)
theorem zipWith_apply (f : ∀ i, β₁ i → β₂ i → β i) (hf : ∀ i, f i 0 0 = 0) (g₁ : Π₀ i, β₁ i)
    (g₂ : Π₀ i, β₂ i) (i : ι) : zipWith f hf g₁ g₂ i = f i (g₁ i) (g₂ i) :=
rfl

section Piecewise

variable (x y : Π₀ i, β i) (s : Set ι) [∀ i, Decidable (i ∈ s)]

/-- `x.piecewise y s` is the finitely supported function equal to `x` on the set `s`,
  and to `y` on its complement. -/
```

-- snippet 13
```lean
-- Mathlib.Data.DFinsupp.Defs.piecewise (L170-L172)
def piecewise : Π₀ i, β i :=
zipWith (fun i x y => if i ∈ s then x else y) (fun _ => ite_self 0) x y
```

-- snippet 14
```lean
-- Mathlib.Data.DFinsupp.Defs.piecewise_apply (L173-L175)
theorem piecewise_apply (i : ι) : x.piecewise y s i = if i ∈ s then x i else y i :=
rfl
```

-- snippet 15
```lean
-- Mathlib.Data.DFinsupp.Defs.coe_piecewise (L177-L185)
theorem coe_piecewise : ⇑(x.piecewise y s) = s.piecewise x y :=
rfl

end Piecewise

end Basic

section Algebra
```

-- snippet 16
```lean
-- Mathlib.Data.DFinsupp.BigOperators.prod_comm (L127-L134)
theorem prod_comm {ι₁ ι₂ : Sort _} {β₁ : ι₁ → Type*} {β₂ : ι₂ → Type*} [DecidableEq ι₁]
    [DecidableEq ι₂] [∀ i, Zero (β₁ i)] [∀ i, Zero (β₂ i)] [∀ (i) (x : β₁ i), Decidable (x ≠ 0)]
    [∀ (i) (x : β₂ i), Decidable (x ≠ 0)] [CommMonoid γ] (f₁ : Π₀ i, β₁ i) (f₂ : Π₀ i, β₂ i)
    (h : ∀ i, β₁ i → ∀ i, β₂ i → γ) :
    (f₁.prod fun i₁ x₁ => f₂.prod fun i₂ x₂ => h i₁ x₁ i₂ x₂) =
      f₂.prod fun i₂ x₂ => f₁.prod fun i₁ x₁ => h i₁ x₁ i₂ x₂ :=
Finset.prod_comm
```

-- snippet 17
```lean
-- Mathlib.Data.DFinsupp.BigOperators.sum_apply (L136-L141)
theorem sum_apply {ι} {β : ι → Type v} {ι₁ : Type u₁} [DecidableEq ι₁] {β₁ : ι₁ → Type v₁}
    [∀ i₁, Zero (β₁ i₁)] [∀ (i) (x : β₁ i), Decidable (x ≠ 0)] [∀ i, AddCommMonoid (β i)]
    {f : Π₀ i₁, β₁ i₁} {g : ∀ i₁, β₁ i₁ → Π₀ i, β i} {i₂ : ι} :
    (f.sum g) i₂ = f.sum fun i₁ b => g i₁ b i₂ :=
map_sum (evalAddMonoidHom i₂) _ f.support
```

-- snippet 18
```lean
-- Mathlib.Data.DFinsupp.BigOperators.prod_one (L155-L158)
theorem prod_one [∀ i, AddCommMonoid (β i)] [∀ (i) (x : β i), Decidable (x ≠ 0)] [CommMonoid γ]
    {f : Π₀ i, β i} : (f.prod fun _ _ => (1 : γ)) = 1 :=
Finset.prod_const_one
```

-- snippet 19
```lean
-- Mathlib.Data.DFinsupp.BigOperators.coe_finset_sum (L61-L64)
theorem coe_finset_sum {α} [∀ i, AddCommMonoid (β i)] (s : Finset α) (g : α → Π₀ i, β i) :
    ⇑(∑ a ∈ s, g a) = ∑ a ∈ s, ⇑(g a) :=
map_sum coeFnAddMonoidHom g s
```

-- snippet 20
```lean
-- Mathlib.Data.DFinsupp.BigOperators.evalAddMonoidHom (L57-L59)
def evalAddMonoidHom [∀ i, AddZeroClass (β i)] (i : ι) : (Π₀ i, β i) →+ β i :=
(Pi.evalAddMonoidHom β i).comp coeFnAddMonoidHom
```

-- snippet 21
```lean
-- Mathlib.Data.DFinsupp.BigOperators.prod_mul (L160-L164)
theorem prod_mul [∀ i, AddCommMonoid (β i)] [∀ (i) (x : β i), Decidable (x ≠ 0)] [CommMonoid γ]
    {f : Π₀ i, β i} {h₁ h₂ : ∀ i, β i → γ} :
    (f.prod fun i b => h₁ i b * h₂ i b) = f.prod h₁ * f.prod h₂ :=
Finset.prod_mul_distrib
```

-- snippet 22
```lean
-- Mathlib.Data.DFinsupp.BigOperators.sumAddHom (L283-L306)
def sumAddHom [∀ i, AddZeroClass (β i)] [AddCommMonoid γ] (φ : ∀ i, β i →+ γ) :
    (Π₀ i, β i) →+ γ where
  __ := sumZeroHom fun i => φ i |>.toZeroHom
map_add' := by
    rintro ⟨f, sf, hf⟩ ⟨g, sg, hg⟩
    change (∑ i ∈ _, _) = (∑ i ∈ _, _) + ∑ i ∈ _, _
    simp only [AddMonoidHom.toZeroHom_coe, coe_add, coe_mk', Pi.add_apply, map_add,
      Finset.sum_add_distrib]
    congr 1
    · refine (Finset.sum_subset ?_ ?_).symm
      · intro i
        simp only [Multiset.mem_toFinset, Multiset.mem_add]
        exact Or.inl
      · intro i _ H2
        simp only [Multiset.mem_toFinset] at H2
        rw [(hf i).resolve_left H2, map_zero]
    · refine (Finset.sum_subset ?_ ?_).symm
      · intro i
        simp only [Multiset.mem_toFinset, Multiset.mem_add]
        exact Or.inr
      · intro i _ H2
        simp only [Multiset.mem_toFinset] at H2
        rw [(hg i).resolve_left H2, map_zero]
```

-- snippet 23
```lean
-- Mathlib.Data.DFinsupp.BigOperators.prod_eq_one (L172-L175)
theorem prod_eq_one [∀ i, Zero (β i)] [∀ (i) (x : β i), Decidable (x ≠ 0)] [CommMonoid γ]
    {f : Π₀ i, β i} {h : ∀ i, β i → γ} (hyp : ∀ i, h i (f i) = 1) : f.prod h = 1 :=
Finset.prod_eq_one fun i _ => hyp i
```

-- snippet 24
```lean
-- Mathlib.Data.DFinsupp.BigOperators.sumZeroHom (L223-L248)
def sumZeroHom [∀ i, Zero (β i)] [AddCommMonoid γ] (φ : ∀ i, ZeroHom (β i) γ) :
    ZeroHom (Π₀ i, β i) γ where
  toFun f :=
(f.support'.lift fun s => ∑ i ∈ Multiset.toFinset s.1, φ i (f i)) <| by
      rintro ⟨sx, hx⟩ ⟨sy, hy⟩
      dsimp only [Subtype.coe_mk, toFun_eq_coe] at *
      have H1 : sx.toFinset ∩ sy.toFinset ⊆ sx.toFinset := Finset.inter_subset_left
      have H2 : sx.toFinset ∩ sy.toFinset ⊆ sy.toFinset := Finset.inter_subset_right
      refine
        (Finset.sum_subset H1 ?_).symm.trans
          ((Finset.sum_congr rfl ?_).trans (Finset.sum_subset H2 ?_))
      · intro i H1 H2
        rw [Finset.mem_inter] at H2
        simp only [Multiset.mem_toFinset] at H1 H2
        convert map_zero (φ i)
        exact (hy i).resolve_left (mt (And.intro H1) H2)
      · intro i _
        rfl
      · intro i H1 H2
        rw [Finset.mem_inter] at H2
        simp only [Multiset.mem_toFinset] at H1 H2
        convert map_zero (φ i)
        exact (hx i).resolve_left (mt (fun H3 => And.intro H3 H1) H2)
  map_zero' := by
    simp only [toFun_eq_coe, coe_zero, Pi.zero_apply, map_zero, Finset.sum_const_zero]; rfl
```

-- snippet 25
```lean
-- Mathlib.Data.DFinsupp.BigOperators.finset_sum_apply (L66-L76)
theorem finset_sum_apply {α} [∀ i, AddCommMonoid (β i)] (s : Finset α) (g : α → Π₀ i, β i) (i : ι) :
    (∑ a ∈ s, g a) i = ∑ a ∈ s, g a i :=
map_sum (evalAddMonoidHom i) g s

end Algebra

section ProdAndSum

variable [DecidableEq ι]

/-- `DFinsupp.prod f g` is the product of `g i (f i)` over the support of `f`. -/
```

-- snippet 26
```lean
-- Mathlib.Data.DFinsupp.BigOperators.support_sum (L142-L153)
theorem support_sum {ι₁ : Type u₁} [DecidableEq ι₁] {β₁ : ι₁ → Type v₁} [∀ i₁, Zero (β₁ i₁)]
    [∀ (i) (x : β₁ i), Decidable (x ≠ 0)] [∀ i, AddCommMonoid (β i)]
    [∀ (i) (x : β i), Decidable (x ≠ 0)] {f : Π₀ i₁, β₁ i₁} {g : ∀ i₁, β₁ i₁ → Π₀ i, β i} :
    (f.sum g).support ⊆ f.support.biUnion fun i => (g i (f i)).support := by
have :
    ∀ i₁ : ι,
      (f.sum fun (i : ι₁) (b : β₁ i) => (g i b) i₁) ≠ 0 → ∃ i : ι₁, f i ≠ 0 ∧ ¬(g i (f i)) i₁ = 0 :=
    fun i₁ h =>
    let ⟨i, hi, Ne⟩ := Finset.exists_ne_zero_of_sum_ne_zero h
    ⟨i, mem_support_iff.1 hi, Ne⟩
  simpa [Finset.subset_iff, mem_support_iff, Finset.mem_biUnion, sum_apply] using this
```

-- snippet 27
```lean
-- Mathlib.Data.DFinsupp.BigOperators.sumZeroHom_single (L250-L254)
theorem sumZeroHom_single [∀ i, Zero (β i)] [AddCommMonoid γ] (φ : ∀ i, ZeroHom (β i) γ) (i)
    (x : β i) : sumZeroHom φ (single i x) = φ i x := by
dsimp [sumZeroHom, single, Trunc.lift_mk]
  rw [Multiset.toFinset_singleton, Finset.sum_singleton, Pi.single_eq_same]
```

-- snippet 28
```lean
-- Mathlib.Data.DFinsupp.BigOperators.prod_neg_index (L121-L125)
theorem prod_neg_index [∀ i, AddGroup (β i)] [∀ (i) (x : β i), Decidable (x ≠ 0)] [CommMonoid γ]
    {g : Π₀ i, β i} {h : ∀ i, β i → γ} (h0 : ∀ i, h i 0 = 1) :
    (-g).prod h = g.prod fun i b => h i (-b) :=
prod_mapRange_index h0
```

-- snippet 29
```lean
-- Mathlib.Data.DFinsupp.BigOperators.sumZeroHom_apply (L266-L281)
theorem sumZeroHom_apply [∀ i, AddZeroClass (β i)] [∀ (i) (x : β i), Decidable (x ≠ 0)]
    [AddCommMonoid γ] (φ : ∀ i, ZeroHom (β i) γ) (f : Π₀ i, β i) :
    sumZeroHom φ f = f.sum fun x => φ x := by
rcases f with ⟨f, s, hf⟩
  change (∑ i ∈ _, _) = ∑ i ∈ _ with _, _
  rw [Finset.sum_filter, Finset.sum_congr rfl]
  intro i _
  dsimp only [coe_mk', Subtype.coe_mk] at *
  split_ifs with h
  · rfl
  · rw [not_not.mp h, map_zero]

/--
When summing over an `AddMonoidHom`, the decidability assumption is not needed, and the result is
also an `AddMonoidHom`.
-/
```

-- snippet 30
```lean
-- Mathlib.Data.DFinsupp.BigOperators.prod_single_index (L112-L119)
theorem prod_single_index [∀ i, Zero (β i)] [∀ (i) (x : β i), Decidable (x ≠ 0)] [CommMonoid γ]
    {i : ι} {b : β i} {h : ∀ i, β i → γ} (h_zero : h i 0 = 1) : (single i b).prod h = h i b := by
by_cases h : b ≠ 0
  · simp [DFinsupp.prod, support_single_ne_zero h]
  · rw [not_not] at h
    simp [h, h_zero]
    rfl
```

-- snippet 31
```lean
-- Mathlib.Data.DFinsupp.BigOperators.prod_mapRange_index (L90-L105)
theorem prod_mapRange_index {β₁ : ι → Type v₁} {β₂ : ι → Type v₂} [∀ i, Zero (β₁ i)]
    [∀ i, Zero (β₂ i)] [∀ (i) (x : β₁ i), Decidable (x ≠ 0)] [∀ (i) (x : β₂ i), Decidable (x ≠ 0)]
    [CommMonoid γ] {f : ∀ i, β₁ i → β₂ i} {hf : ∀ i, f i 0 = 0} {g : Π₀ i, β₁ i} {h : ∀ i, β₂ i → γ}
    (h0 : ∀ i, h i 0 = 1) : (mapRange f hf g).prod h = g.prod fun i b => h i (f i b) := by
rw [mapRange_def]
  refine (Finset.prod_subset support_mk_subset ?_).trans ?_
  · intro i h1 h2
    simp only [mem_support_toFun, ne_eq] at h1
    simp only [Finset.coe_sort_coe, mem_support_toFun, mk_apply, ne_eq, h1, not_false_iff,
      dite_eq_ite, ite_true, not_not] at h2
    simp [h2, h0]
  · refine Finset.prod_congr rfl ?_
    intro i h1
    simp only [mem_support_toFun, ne_eq] at h1
    simp [h1]
```

-- snippet 32
```lean
-- Mathlib.Data.DFinsupp.BigOperators.prod_ne_zero_iff (L215-L222)
lemma prod_ne_zero_iff : f.prod g ≠ 0 ↔ ∀ i ∈ f.support, g i (f i) ≠ 0 := Finset.prod_ne_zero_iff
end CommMonoidWithZero

/--
When summing over an `ZeroHom`, the decidability assumption is not needed, and the result is
also an `ZeroHom`.
-/
```

-- snippet 33
```lean
-- Mathlib.Data.DFinsupp.BigOperators.prod_inv (L166-L170)
theorem prod_inv [∀ i, AddCommMonoid (β i)] [∀ (i) (x : β i), Decidable (x ≠ 0)]
    [DivisionCommMonoid γ] {f : Π₀ i, β i} {h : ∀ i, β i → γ} :
    (f.prod fun i b => (h i b)⁻¹) = (f.prod h)⁻¹ :=
(map_prod (invMonoidHom : γ →* γ) _ f.support).symm
```

-- snippet 34
```lean
-- Mathlib.Data.DFinsupp.BigOperators.smul_sum (L176-L180)
theorem smul_sum {α : Type*} [∀ i, Zero (β i)] [∀ (i) (x : β i), Decidable (x ≠ 0)]
    [AddCommMonoid γ] [DistribSMul α γ] {f : Π₀ i, β i} {h : ∀ i, β i → γ} {c : α} :
    c • f.sum h = f.sum fun a b => c • h a b :=
Finset.smul_sum
```

-- snippet 35
```lean
-- Mathlib.Data.DFinsupp.BigOperators.prod (L78-L81)
def prod [∀ i, Zero (β i)] [∀ (i) (x : β i), Decidable (x ≠ 0)] [CommMonoid γ] (f : Π₀ i, β i)
    (g : ∀ i, β i → γ) : γ :=
∏ i ∈ f.support, g i (f i)
```

-- snippet 36
```lean
-- Mathlib.Data.DFinsupp.BigOperators.prod_add_index (L182-L198)
theorem prod_add_index [∀ i, AddCommMonoid (β i)] [∀ (i) (x : β i), Decidable (x ≠ 0)]
    [CommMonoid γ] {f g : Π₀ i, β i} {h : ∀ i, β i → γ} (h_zero : ∀ i, h i 0 = 1)
    (h_add : ∀ i b₁ b₂, h i (b₁ + b₂) = h i b₁ * h i b₂) : (f + g).prod h = f.prod h * g.prod h :=
have f_eq : (∏ i ∈ f.support ∪ g.support, h i (f i)) = f.prod h :=
    (Finset.prod_subset Finset.subset_union_left <| by
        simp +contextual [h_zero]).symm
  have g_eq : (∏ i ∈ f.support ∪ g.support, h i (g i)) = g.prod h :=
    (Finset.prod_subset Finset.subset_union_right <| by
        simp +contextual [h_zero]).symm
  calc
    (∏ i ∈ (f + g).support, h i ((f + g) i)) = ∏ i ∈ f.support ∪ g.support, h i ((f + g) i) :=
      Finset.prod_subset support_add <| by
        simp +contextual [h_zero]
    _ = (∏ i ∈ f.support ∪ g.support, h i (f i)) * ∏ i ∈ f.support ∪ g.support, h i (g i) := by
      { simp [h_add, Finset.prod_mul_distrib] }
    _ = _ := by rw [f_eq, g_eq]
```

-- snippet 37
```lean
-- Mathlib.Data.DFinsupp.BigOperators.sumZeroHom_piSingle (L256-L265)
theorem sumZeroHom_piSingle [∀ i, Zero (β i)] [AddCommMonoid γ] (i) (φ : ZeroHom (β i) γ) :
    sumZeroHom (Pi.single i φ) = φ.comp { toFun := (· i), map_zero' := rfl } := by
ext ⟨f, sf, hf⟩
  simp only [sumZeroHom, Trunc.lift, toFun_eq_coe, ZeroHom.coe_mk, coe_mk', ZeroHom.coe_comp,
    Function.comp_apply]
  rw [Finset.sum_eq_single i (fun j _ hji => ?_) (fun hi => ?_), Pi.single_eq_same]
  · simp [hji]
  · simp [(hf i).resolve_left (by simpa using hi)]

/-- While we didn't need decidable instances to define it, we do to reduce it to a sum -/
```

-- snippet 38
```lean
-- Mathlib.Data.DFinsupp.BigOperators.prod_eq_zero_iff (L214-L214)
lemma prod_eq_zero_iff : f.prod g = 0 ↔ ∃ i ∈ f.support, g i (f i) = 0 := Finset.prod_eq_zero_iff
```

-- snippet 39
```lean
-- Mathlib.Data.DFinsupp.BigOperators.prod_zero_index (L107-L110)
theorem prod_zero_index [∀ i, AddCommMonoid (β i)] [∀ (i) (x : β i), Decidable (x ≠ 0)]
    [CommMonoid γ] {h : ∀ i, β i → γ} : (0 : Π₀ i, β i).prod h = 1 :=
rfl
```

-- snippet 40
```lean
-- Mathlib.Data.DFinsupp.BigOperators.prod_eq_prod_fintype (L200-L212)
theorem prod_eq_prod_fintype [Fintype ι] [∀ i, Zero (β i)] [∀ (i : ι) (x : β i), Decidable (x ≠ 0)]
    [CommMonoid γ] (v : Π₀ i, β i) {f : ∀ i, β i → γ} (hf : ∀ i, f i 0 = 1) :
    v.prod f = ∏ i, f i (DFinsupp.equivFunOnFintype v i) := by
suffices (∏ i ∈ v.support, f i (v i)) = ∏ i, f i (v i) by simp [DFinsupp.prod, this]
  apply Finset.prod_subset v.support.subset_univ
  intro i _ hi
  rw [mem_support_iff, not_not] at hi
  rw [hi, hf]

section CommMonoidWithZero
variable [Π i, Zero (β i)] [CommMonoidWithZero γ] [Nontrivial γ] [NoZeroDivisors γ]
  [Π i, DecidableEq (β i)] {f : Π₀ i, β i} {g : Π i, β i → γ}
```

<s>[SYSTEM_PROMPT]You are Leanstral, a Lean 4 proof assistant. Complete the task below using the provided Lean source context. The target mathlib commit is 5e932f97dd25535344f80f9dd8da3aab83df0fe6 (module Mathlib.Data.DFinsupp.Defs).[/SYSTEM_PROMPT][MODEL_SETTINGS]{"reasoning_effort": "none"}[/MODEL_SETTINGS][INST]Prove the following theorem. The retrieved context below may help.

```lean
theorem coe_zsmul [∀ i, AddGroup (β i)] (b : ℤ) (v : Π₀ i, β i) : ⇑(b • v) = b • ⇑v
```

## Retrieved context
-- snippet 1
```lean
-- Mathlib.Data.DFinsupp.Defs.instDFunLike (L77-L82)
instance instDFunLike : DFunLike (Π₀ i, β i) ι β :=
⟨fun f => f.toFun, fun ⟨f₁, s₁⟩ ⟨f₂, s₁⟩ ↦ fun (h : f₁ = f₂) ↦ by
    subst h
    congr
    subsingleton ⟩
```

-- snippet 2
```lean
-- Mathlib.Data.DFinsupp.Defs.toFun_eq_coe (L84-L86)
theorem toFun_eq_coe (f : Π₀ i, β i) : f.toFun = f :=
rfl
```

-- snippet 3
```lean
-- Mathlib.Data.DFinsupp.Defs.ext (L88-L90)
theorem ext {f g : Π₀ i, β i} (h : ∀ i, f i = g i) : f = g :=
DFunLike.ext _ _ h
```

-- snippet 4
```lean
-- Mathlib.Data.DFinsupp.Defs.ne_iff (L91-L92)
lemma ne_iff {f g : Π₀ i, β i} : f ≠ g ↔ ∃ i, f i ≠ g i := DFunLike.ne_iff
```

-- snippet 5
```lean
-- Mathlib.Data.DFinsupp.Defs.zero_apply (L103-L116)
theorem zero_apply (i : ι) : (0 : Π₀ i, β i) i = 0 :=
rfl

/-- The composition of `f : β₁ → β₂` and `g : Π₀ i, β₁ i` is
  `mapRange f hf g : Π₀ i, β₂ i`, well defined when `f 0 = 0`.

This preserves the structure on `f`, and exists in various bundled forms for when `f` is itself
bundled:

* `DFinsupp.mapRange.addMonoidHom`
* `DFinsupp.mapRange.addEquiv`
* `dfinsupp.mapRange.linearMap`
* `dfinsupp.mapRange.linearEquiv`
-/
```

-- snippet 6
```lean
-- Mathlib.Data.DFinsupp.Defs.mapRange (L117-L121)
def mapRange (f : ∀ i, β₁ i → β₂ i) (hf : ∀ i, f i 0 = 0) (x : Π₀ i, β₁ i) : Π₀ i, β₂ i :=
⟨fun i => f i (x i),
    x.support'.map fun s => ⟨s.1, fun i => (s.2 i).imp_right fun h : x i = 0 => by
      rw [← hf i, ← h]⟩⟩
```

-- snippet 7
```lean
-- Mathlib.Data.DFinsupp.Defs.mapRange_apply (L123-L126)
theorem mapRange_apply (f : ∀ i, β₁ i → β₂ i) (hf : ∀ i, f i 0 = 0) (g : Π₀ i, β₁ i) (i : ι) :
    mapRange f hf g i = f i (g i) :=
rfl
```

-- snippet 8
```lean
-- Mathlib.Data.DFinsupp.Defs.mapRange_id (L128-L132)
theorem mapRange_id (h : ∀ i, id (0 : β₁ i) = 0 := fun _ => rfl) (g : Π₀ i : ι, β₁ i) :
mapRange (fun i => (id : β₁ i → β₁ i)) h g = g := by
  ext
  rfl
```

-- snippet 9
```lean
-- Mathlib.Data.DFinsupp.Defs.mapRange_comp (L133-L138)
theorem mapRange_comp (f : ∀ i, β₁ i → β₂ i) (f₂ : ∀ i, β i → β₁ i) (hf : ∀ i, f i 0 = 0)
    (hf₂ : ∀ i, f₂ i 0 = 0) (h : ∀ i, (f i ∘ f₂ i) 0 = 0) (g : Π₀ i : ι, β i) :
    mapRange (fun i => f i ∘ f₂ i) h g = mapRange f hf (mapRange f₂ hf₂ g) := by
ext
  simp only [mapRange_apply]; rfl
```

-- snippet 10
```lean
-- Mathlib.Data.DFinsupp.Defs.mapRange_zero (L140-L146)
theorem mapRange_zero (f : ∀ i, β₁ i → β₂ i) (hf : ∀ i, f i 0 = 0) :
    mapRange f hf (0 : Π₀ i, β₁ i) = 0 := by
ext
  simp only [mapRange_apply, coe_zero, Pi.zero_apply, hf]

/-- Let `f i` be a binary operation `β₁ i → β₂ i → β i` such that `f i 0 0 = 0`.
Then `zipWith f hf` is a binary operation `Π₀ i, β₁ i → Π₀ i, β₂ i → Π₀ i, β i`. -/
```

-- snippet 11
```lean
-- Mathlib.Data.DFinsupp.Defs.zipWith (L147-L158)
def zipWith (f : ∀ i, β₁ i → β₂ i → β i) (hf : ∀ i, f i 0 0 = 0) (x : Π₀ i, β₁ i) (y : Π₀ i, β₂ i) :
    Π₀ i, β i :=
⟨fun i => f i (x i) (y i), by
    refine x.support'.bind fun xs => ?_
    refine y.support'.map fun ys => ?_
    refine ⟨xs + ys, fun i => ?_⟩
    obtain h1 | (h1 : x i = 0) := xs.prop i
    · grind
    obtain h2 | (h2 : y i = 0) := ys.prop i
    · grind
    grind⟩
```

-- snippet 12
```lean
-- Mathlib.Data.DFinsupp.Defs.zipWith_apply (L160-L169)
theorem zipWith_apply (f : ∀ i, β₁ i → β₂ i → β i) (hf : ∀ i, f i 0 0 = 0) (g₁ : Π₀ i, β₁ i)
    (g₂ : Π₀ i, β₂ i) (i : ι) : zipWith f hf g₁ g₂ i = f i (g₁ i) (g₂ i) :=
rfl

section Piecewise

variable (x y : Π₀ i, β i) (s : Set ι) [∀ i, Decidable (i ∈ s)]

/-- `x.piecewise y s` is the finitely supported function equal to `x` on the set `s`,
  and to `y` on its complement. -/
```

-- snippet 13
```lean
-- Mathlib.Data.DFinsupp.Defs.piecewise (L170-L172)
def piecewise : Π₀ i, β i :=
zipWith (fun i x y => if i ∈ s then x else y) (fun _ => ite_self 0) x y
```

-- snippet 14
```lean
-- Mathlib.Data.DFinsupp.Defs.piecewise_apply (L173-L175)
theorem piecewise_apply (i : ι) : x.piecewise y s i = if i ∈ s then x i else y i :=
rfl
```

-- snippet 15
```lean
-- Mathlib.Data.DFinsupp.Defs.coe_piecewise (L177-L185)
theorem coe_piecewise : ⇑(x.piecewise y s) = s.piecewise x y :=
rfl

end Piecewise

end Basic

section Algebra
```

-- snippet 16
```lean
-- Mathlib.Data.DFinsupp.BigOperators.prod_comm (L127-L134)
theorem prod_comm {ι₁ ι₂ : Sort _} {β₁ : ι₁ → Type*} {β₂ : ι₂ → Type*} [DecidableEq ι₁]
    [DecidableEq ι₂] [∀ i, Zero (β₁ i)] [∀ i, Zero (β₂ i)] [∀ (i) (x : β₁ i), Decidable (x ≠ 0)]
    [∀ (i) (x : β₂ i), Decidable (x ≠ 0)] [CommMonoid γ] (f₁ : Π₀ i, β₁ i) (f₂ : Π₀ i, β₂ i)
    (h : ∀ i, β₁ i → ∀ i, β₂ i → γ) :
    (f₁.prod fun i₁ x₁ => f₂.prod fun i₂ x₂ => h i₁ x₁ i₂ x₂) =
      f₂.prod fun i₂ x₂ => f₁.prod fun i₁ x₁ => h i₁ x₁ i₂ x₂ :=
Finset.prod_comm
```

-- snippet 17
```lean
-- Mathlib.Data.DFinsupp.BigOperators.sum_apply (L136-L141)
theorem sum_apply {ι} {β : ι → Type v} {ι₁ : Type u₁} [DecidableEq ι₁] {β₁ : ι₁ → Type v₁}
    [∀ i₁, Zero (β₁ i₁)] [∀ (i) (x : β₁ i), Decidable (x ≠ 0)] [∀ i, AddCommMonoid (β i)]
    {f : Π₀ i₁, β₁ i₁} {g : ∀ i₁, β₁ i₁ → Π₀ i, β i} {i₂ : ι} :
    (f.sum g) i₂ = f.sum fun i₁ b => g i₁ b i₂ :=
map_sum (evalAddMonoidHom i₂) _ f.support
```

-- snippet 18
```lean
-- Mathlib.Data.DFinsupp.BigOperators.prod_one (L155-L158)
theorem prod_one [∀ i, AddCommMonoid (β i)] [∀ (i) (x : β i), Decidable (x ≠ 0)] [CommMonoid γ]
    {f : Π₀ i, β i} : (f.prod fun _ _ => (1 : γ)) = 1 :=
Finset.prod_const_one
```

-- snippet 19
```lean
-- Mathlib.Data.DFinsupp.BigOperators.coe_finset_sum (L61-L64)
theorem coe_finset_sum {α} [∀ i, AddCommMonoid (β i)] (s : Finset α) (g : α → Π₀ i, β i) :
    ⇑(∑ a ∈ s, g a) = ∑ a ∈ s, ⇑(g a) :=
map_sum coeFnAddMonoidHom g s
```

-- snippet 20
```lean
-- Mathlib.Data.DFinsupp.BigOperators.evalAddMonoidHom (L57-L59)
def evalAddMonoidHom [∀ i, AddZeroClass (β i)] (i : ι) : (Π₀ i, β i) →+ β i :=
(Pi.evalAddMonoidHom β i).comp coeFnAddMonoidHom
```

-- snippet 21
```lean
-- Mathlib.Data.DFinsupp.BigOperators.prod_mul (L160-L164)
theorem prod_mul [∀ i, AddCommMonoid (β i)] [∀ (i) (x : β i), Decidable (x ≠ 0)] [CommMonoid γ]
    {f : Π₀ i, β i} {h₁ h₂ : ∀ i, β i → γ} :
    (f.prod fun i b => h₁ i b * h₂ i b) = f.prod h₁ * f.prod h₂ :=
Finset.prod_mul_distrib
```

-- snippet 22
```lean
-- Mathlib.Data.DFinsupp.BigOperators.sumAddHom (L283-L306)
def sumAddHom [∀ i, AddZeroClass (β i)] [AddCommMonoid γ] (φ : ∀ i, β i →+ γ) :
    (Π₀ i, β i) →+ γ where
  __ := sumZeroHom fun i => φ i |>.toZeroHom
map_add' := by
    rintro ⟨f, sf, hf⟩ ⟨g, sg, hg⟩
    change (∑ i ∈ _, _) = (∑ i ∈ _, _) + ∑ i ∈ _, _
    simp only [AddMonoidHom.toZeroHom_coe, coe_add, coe_mk', Pi.add_apply, map_add,
      Finset.sum_add_distrib]
    congr 1
    · refine (Finset.sum_subset ?_ ?_).symm
      · intro i
        simp only [Multiset.mem_toFinset, Multiset.mem_add]
        exact Or.inl
      · intro i _ H2
        simp only [Multiset.mem_toFinset] at H2
        rw [(hf i).resolve_left H2, map_zero]
    · refine (Finset.sum_subset ?_ ?_).symm
      · intro i
        simp only [Multiset.mem_toFinset, Multiset.mem_add]
        exact Or.inr
      · intro i _ H2
        simp only [Multiset.mem_toFinset] at H2
        rw [(hg i).resolve_left H2, map_zero]
```

-- snippet 23
```lean
-- Mathlib.Data.DFinsupp.BigOperators.prod_eq_one (L172-L175)
theorem prod_eq_one [∀ i, Zero (β i)] [∀ (i) (x : β i), Decidable (x ≠ 0)] [CommMonoid γ]
    {f : Π₀ i, β i} {h : ∀ i, β i → γ} (hyp : ∀ i, h i (f i) = 1) : f.prod h = 1 :=
Finset.prod_eq_one fun i _ => hyp i
```

-- snippet 24
```lean
-- Mathlib.Data.DFinsupp.BigOperators.sumZeroHom (L223-L248)
def sumZeroHom [∀ i, Zero (β i)] [AddCommMonoid γ] (φ : ∀ i, ZeroHom (β i) γ) :
    ZeroHom (Π₀ i, β i) γ where
  toFun f :=
(f.support'.lift fun s => ∑ i ∈ Multiset.toFinset s.1, φ i (f i)) <| by
      rintro ⟨sx, hx⟩ ⟨sy, hy⟩
      dsimp only [Subtype.coe_mk, toFun_eq_coe] at *
      have H1 : sx.toFinset ∩ sy.toFinset ⊆ sx.toFinset := Finset.inter_subset_left
      have H2 : sx.toFinset ∩ sy.toFinset ⊆ sy.toFinset := Finset.inter_subset_right
      refine
        (Finset.sum_subset H1 ?_).symm.trans
          ((Finset.sum_congr rfl ?_).trans (Finset.sum_subset H2 ?_))
      · intro i H1 H2
        rw [Finset.mem_inter] at H2
        simp only [Multiset.mem_toFinset] at H1 H2
        convert map_zero (φ i)
        exact (hy i).resolve_left (mt (And.intro H1) H2)
      · intro i _
        rfl
      · intro i H1 H2
        rw [Finset.mem_inter] at H2
        simp only [Multiset.mem_toFinset] at H1 H2
        convert map_zero (φ i)
        exact (hx i).resolve_left (mt (fun H3 => And.intro H3 H1) H2)
  map_zero' := by
    simp only [toFun_eq_coe, coe_zero, Pi.zero_apply, map_zero, Finset.sum_const_zero]; rfl
```

-- snippet 25
```lean
-- Mathlib.Data.DFinsupp.BigOperators.finset_sum_apply (L66-L76)
theorem finset_sum_apply {α} [∀ i, AddCommMonoid (β i)] (s : Finset α) (g : α → Π₀ i, β i) (i : ι) :
    (∑ a ∈ s, g a) i = ∑ a ∈ s, g a i :=
map_sum (evalAddMonoidHom i) g s

end Algebra

section ProdAndSum

variable [DecidableEq ι]

/-- `DFinsupp.prod f g` is the product of `g i (f i)` over the support of `f`. -/
```

-- snippet 26
```lean
-- Mathlib.Data.DFinsupp.BigOperators.support_sum (L142-L153)
theorem support_sum {ι₁ : Type u₁} [DecidableEq ι₁] {β₁ : ι₁ → Type v₁} [∀ i₁, Zero (β₁ i₁)]
    [∀ (i) (x : β₁ i), Decidable (x ≠ 0)] [∀ i, AddCommMonoid (β i)]
    [∀ (i) (x : β i), Decidable (x ≠ 0)] {f : Π₀ i₁, β₁ i₁} {g : ∀ i₁, β₁ i₁ → Π₀ i, β i} :
    (f.sum g).support ⊆ f.support.biUnion fun i => (g i (f i)).support := by
have :
    ∀ i₁ : ι,
      (f.sum fun (i : ι₁) (b : β₁ i) => (g i b) i₁) ≠ 0 → ∃ i : ι₁, f i ≠ 0 ∧ ¬(g i (f i)) i₁ = 0 :=
    fun i₁ h =>
    let ⟨i, hi, Ne⟩ := Finset.exists_ne_zero_of_sum_ne_zero h
    ⟨i, mem_support_iff.1 hi, Ne⟩
  simpa [Finset.subset_iff, mem_support_iff, Finset.mem_biUnion, sum_apply] using this
```

-- snippet 27
```lean
-- Mathlib.Data.DFinsupp.BigOperators.sumZeroHom_single (L250-L254)
theorem sumZeroHom_single [∀ i, Zero (β i)] [AddCommMonoid γ] (φ : ∀ i, ZeroHom (β i) γ) (i)
    (x : β i) : sumZeroHom φ (single i x) = φ i x := by
dsimp [sumZeroHom, single, Trunc.lift_mk]
  rw [Multiset.toFinset_singleton, Finset.sum_singleton, Pi.single_eq_same]
```

-- snippet 28
```lean
-- Mathlib.Data.DFinsupp.BigOperators.prod_neg_index (L121-L125)
theorem prod_neg_index [∀ i, AddGroup (β i)] [∀ (i) (x : β i), Decidable (x ≠ 0)] [CommMonoid γ]
    {g : Π₀ i, β i} {h : ∀ i, β i → γ} (h0 : ∀ i, h i 0 = 1) :
    (-g).prod h = g.prod fun i b => h i (-b) :=
prod_mapRange_index h0
```

-- snippet 29
```lean
-- Mathlib.Data.DFinsupp.BigOperators.sumZeroHom_apply (L266-L281)
theorem sumZeroHom_apply [∀ i, AddZeroClass (β i)] [∀ (i) (x : β i), Decidable (x ≠ 0)]
    [AddCommMonoid γ] (φ : ∀ i, ZeroHom (β i) γ) (f : Π₀ i, β i) :
    sumZeroHom φ f = f.sum fun x => φ x := by
rcases f with ⟨f, s, hf⟩
  change (∑ i ∈ _, _) = ∑ i ∈ _ with _, _
  rw [Finset.sum_filter, Finset.sum_congr rfl]
  intro i _
  dsimp only [coe_mk', Subtype.coe_mk] at *
  split_ifs with h
  · rfl
  · rw [not_not.mp h, map_zero]

/--
When summing over an `AddMonoidHom`, the decidability assumption is not needed, and the result is
also an `AddMonoidHom`.
-/
```

-- snippet 30
```lean
-- Mathlib.Data.DFinsupp.BigOperators.prod_single_index (L112-L119)
theorem prod_single_index [∀ i, Zero (β i)] [∀ (i) (x : β i), Decidable (x ≠ 0)] [CommMonoid γ]
    {i : ι} {b : β i} {h : ∀ i, β i → γ} (h_zero : h i 0 = 1) : (single i b).prod h = h i b := by
by_cases h : b ≠ 0
  · simp [DFinsupp.prod, support_single_ne_zero h]
  · rw [not_not] at h
    simp [h, h_zero]
    rfl
```

-- snippet 31
```lean
-- Mathlib.Data.DFinsupp.BigOperators.prod_mapRange_index (L90-L105)
theorem prod_mapRange_index {β₁ : ι → Type v₁} {β₂ : ι → Type v₂} [∀ i, Zero (β₁ i)]
    [∀ i, Zero (β₂ i)] [∀ (i) (x : β₁ i), Decidable (x ≠ 0)] [∀ (i) (x : β₂ i), Decidable (x ≠ 0)]
    [CommMonoid γ] {f : ∀ i, β₁ i → β₂ i} {hf : ∀ i, f i 0 = 0} {g : Π₀ i, β₁ i} {h : ∀ i, β₂ i → γ}
    (h0 : ∀ i, h i 0 = 1) : (mapRange f hf g).prod h = g.prod fun i b => h i (f i b) := by
rw [mapRange_def]
  refine (Finset.prod_subset support_mk_subset ?_).trans ?_
  · intro i h1 h2
    simp only [mem_support_toFun, ne_eq] at h1
    simp only [Finset.coe_sort_coe, mem_support_toFun, mk_apply, ne_eq, h1, not_false_iff,
      dite_eq_ite, ite_true, not_not] at h2
    simp [h2, h0]
  · refine Finset.prod_congr rfl ?_
    intro i h1
    simp only [mem_support_toFun, ne_eq] at h1
    simp [h1]
```

-- snippet 32
```lean
-- Mathlib.Data.DFinsupp.BigOperators.prod_ne_zero_iff (L215-L222)
lemma prod_ne_zero_iff : f.prod g ≠ 0 ↔ ∀ i ∈ f.support, g i (f i) ≠ 0 := Finset.prod_ne_zero_iff
end CommMonoidWithZero

/--
When summing over an `ZeroHom`, the decidability assumption is not needed, and the result is
also an `ZeroHom`.
-/
```

-- snippet 33
```lean
-- Mathlib.Data.DFinsupp.BigOperators.prod_inv (L166-L170)
theorem prod_inv [∀ i, AddCommMonoid (β i)] [∀ (i) (x : β i), Decidable (x ≠ 0)]
    [DivisionCommMonoid γ] {f : Π₀ i, β i} {h : ∀ i, β i → γ} :
    (f.prod fun i b => (h i b)⁻¹) = (f.prod h)⁻¹ :=
(map_prod (invMonoidHom : γ →* γ) _ f.support).symm
```

-- snippet 34
```lean
-- Mathlib.Data.DFinsupp.BigOperators.smul_sum (L176-L180)
theorem smul_sum {α : Type*} [∀ i, Zero (β i)] [∀ (i) (x : β i), Decidable (x ≠ 0)]
    [AddCommMonoid γ] [DistribSMul α γ] {f : Π₀ i, β i} {h : ∀ i, β i → γ} {c : α} :
    c • f.sum h = f.sum fun a b => c • h a b :=
Finset.smul_sum
```

-- snippet 35
```lean
-- Mathlib.Data.DFinsupp.BigOperators.prod (L78-L81)
def prod [∀ i, Zero (β i)] [∀ (i) (x : β i), Decidable (x ≠ 0)] [CommMonoid γ] (f : Π₀ i, β i)
    (g : ∀ i, β i → γ) : γ :=
∏ i ∈ f.support, g i (f i)
```

-- snippet 36
```lean
-- Mathlib.Data.DFinsupp.BigOperators.prod_add_index (L182-L198)
theorem prod_add_index [∀ i, AddCommMonoid (β i)] [∀ (i) (x : β i), Decidable (x ≠ 0)]
    [CommMonoid γ] {f g : Π₀ i, β i} {h : ∀ i, β i → γ} (h_zero : ∀ i, h i 0 = 1)
    (h_add : ∀ i b₁ b₂, h i (b₁ + b₂) = h i b₁ * h i b₂) : (f + g).prod h = f.prod h * g.prod h :=
have f_eq : (∏ i ∈ f.support ∪ g.support, h i (f i)) = f.prod h :=
    (Finset.prod_subset Finset.subset_union_left <| by
        simp +contextual [h_zero]).symm
  have g_eq : (∏ i ∈ f.support ∪ g.support, h i (g i)) = g.prod h :=
    (Finset.prod_subset Finset.subset_union_right <| by
        simp +contextual [h_zero]).symm
  calc
    (∏ i ∈ (f + g).support, h i ((f + g) i)) = ∏ i ∈ f.support ∪ g.support, h i ((f + g) i) :=
      Finset.prod_subset support_add <| by
        simp +contextual [h_zero]
    _ = (∏ i ∈ f.support ∪ g.support, h i (f i)) * ∏ i ∈ f.support ∪ g.support, h i (g i) := by
      { simp [h_add, Finset.prod_mul_distrib] }
    _ = _ := by rw [f_eq, g_eq]
```

-- snippet 37
```lean
-- Mathlib.Data.DFinsupp.BigOperators.sumZeroHom_piSingle (L256-L265)
theorem sumZeroHom_piSingle [∀ i, Zero (β i)] [AddCommMonoid γ] (i) (φ : ZeroHom (β i) γ) :
    sumZeroHom (Pi.single i φ) = φ.comp { toFun := (· i), map_zero' := rfl } := by
ext ⟨f, sf, hf⟩
  simp only [sumZeroHom, Trunc.lift, toFun_eq_coe, ZeroHom.coe_mk, coe_mk', ZeroHom.coe_comp,
    Function.comp_apply]
  rw [Finset.sum_eq_single i (fun j _ hji => ?_) (fun hi => ?_), Pi.single_eq_same]
  · simp [hji]
  · simp [(hf i).resolve_left (by simpa using hi)]

/-- While we didn't need decidable instances to define it, we do to reduce it to a sum -/
```

-- snippet 38
```lean
-- Mathlib.Data.DFinsupp.BigOperators.prod_eq_zero_iff (L214-L214)
lemma prod_eq_zero_iff : f.prod g = 0 ↔ ∃ i ∈ f.support, g i (f i) = 0 := Finset.prod_eq_zero_iff
```

-- snippet 39
```lean
-- Mathlib.Data.DFinsupp.BigOperators.prod_zero_index (L107-L110)
theorem prod_zero_index [∀ i, AddCommMonoid (β i)] [∀ (i) (x : β i), Decidable (x ≠ 0)]
    [CommMonoid γ] {h : ∀ i, β i → γ} : (0 : Π₀ i, β i).prod h = 1 :=
rfl
```

-- snippet 40
```lean
-- Mathlib.Data.DFinsupp.BigOperators.prod_eq_prod_fintype (L200-L212)
theorem prod_eq_prod_fintype [Fintype ι] [∀ i, Zero (β i)] [∀ (i : ι) (x : β i), Decidable (x ≠ 0)]
    [CommMonoid γ] (v : Π₀ i, β i) {f : ∀ i, β i → γ} (hf : ∀ i, f i 0 = 1) :
    v.prod f = ∏ i, f i (DFinsupp.equivFunOnFintype v i) := by
suffices (∏ i ∈ v.support, f i (v i)) = ∏ i, f i (v i) by simp [DFinsupp.prod, this]
  apply Finset.prod_subset v.support.subset_univ
  intro i _ hi
  rw [mem_support_iff, not_not] at hi
  rw [hi, hf]

section CommMonoidWithZero
variable [Π i, Zero (β i)] [CommMonoidWithZero γ] [Nontrivial γ] [NoZeroDivisors γ]
  [Π i, DecidableEq (β i)] {f : Π₀ i, β i} {g : Π i, β i → γ}
```
[/INST]


[System] You are Leanstral, a Lean 4 proof assistant. Complete the task below using the provided Lean source context. The target mathlib commit is 5e932f97dd25535344f80f9dd8da3aab83df0fe6 (module Mathlib.Algebra.CharP.Two).

[User]
Prove the following theorem. The retrieved context below may help.

```lean
theorem intCast_eq_ite (n : ℤ) : (n : R) = if Even n then 0 else 1
```

## Retrieved context
-- snippet 1
```lean
-- Mathlib.Algebra.CharP.Two.of_one_ne_zero_of_two_eq_zero (L37-L46)
theorem of_one_ne_zero_of_two_eq_zero (h₁ : (1 : R) ≠ 0) (h₂ : (2 : R) = 0) : CharP R 2 where
  cast_eq_zero_iff n := by
obtain hn | hn := Nat.even_or_odd n
    · simp_rw [hn.two_dvd, iff_true]
      exact natCast_eq_zero_of_even_of_two_eq_zero hn h₂
    · simp_rw [hn.not_two_dvd_nat, iff_false]
      rwa [natCast_eq_one_of_odd_of_two_eq_zero hn h₂]

variable [CharP R 2]
```

-- snippet 2
```lean
-- Mathlib.Algebra.CharP.Two.two_eq_zero (L48-L50)
theorem two_eq_zero : (2 : R) = 0 := by
rw [← Nat.cast_two, CharP.cast_eq_zero]
```

-- snippet 3
```lean
-- Mathlib.Algebra.CharP.Two.natCast_eq_ite (L51-L53)
theorem natCast_eq_ite (n : ℕ) : (n : R) = if Even n then 0 else 1 := by
induction n <;> aesop (add simp [one_add_one_eq_two])
```

-- snippet 4
```lean
-- Mathlib.Algebra.CharP.Two.range_natCast (L55-L60)
theorem range_natCast : Set.range ((↑) : ℕ → R) = {0, 1} := by
rw [funext natCast_eq_ite, Set.range_ite_const]
  · use 0; simp
  · use 1; simp

variable (R) in
```

-- snippet 5
```lean
-- Mathlib.Algebra.CharP.Two.natCast_cases (L61-L63)
theorem natCast_cases (n : ℕ) : (n : R) = 0 ∨ (n : R) = 1 :=
range_natCast.le (Set.mem_range_self _)
```

-- snippet 6
```lean
-- Mathlib.Algebra.CharP.Two.natCast_eq_mod (L64-L66)
theorem natCast_eq_mod (n : ℕ) : (n : R) = (n % 2 : ℕ) := by
simp [natCast_eq_ite, Nat.even_iff]
```

-- snippet 7
```lean
-- Mathlib.Algebra.CharP.Two.ofNat_eq_mod (L68-L70)
theorem ofNat_eq_mod (n : ℕ) [n.AtLeastTwo] : (ofNat(n) : R) = (ofNat(n) % 2 : ℕ) :=
natCast_eq_mod n
```

-- snippet 8
```lean
-- Mathlib.Algebra.CharP.Two.add_self_eq_zero (L80-L81)
theorem add_self_eq_zero (x : R) : x + x = 0 := by rw [← two_mul x, two_eq_zero, zero_mul]
```

-- snippet 9
```lean
-- Mathlib.Algebra.CharP.Two.neg_eq (L100-L102)
theorem neg_eq (x : R) : -x = x := by
rw [neg_eq_iff_add_eq_zero, add_self_eq_zero]
```

-- snippet 10
```lean
-- Mathlib.Algebra.CharP.Two.neg_eq' (L103-L105)
theorem neg_eq' : Neg.neg = (id : R → R) :=
funext neg_eq
```

-- snippet 11
```lean
-- Mathlib.Algebra.CharP.Two.sub_eq_add (L107-L108)
theorem sub_eq_add (x y : R) : x - y = x + y := by rw [sub_eq_add_neg, neg_eq]
```

-- snippet 12
```lean
-- Mathlib.Algebra.CharP.Two.add_eq_iff_eq_add (L109-L111)
theorem add_eq_iff_eq_add {a b c : R} : a + b = c ↔ a = c + b := by
rw [← sub_eq_iff_eq_add, sub_eq_add]
```

-- snippet 13
```lean
-- Mathlib.Algebra.CharP.Two.eq_add_iff_add_eq (L112-L114)
theorem eq_add_iff_add_eq {a b c : R} : a = b + c ↔ a + c = b := by
rw [← eq_sub_iff_add_eq, sub_eq_add]
```

-- snippet 14
```lean
-- Mathlib.Algebra.CharP.Two.range_intCast (L126-L131)
theorem range_intCast : Set.range ((↑) : ℤ → R) = {0, 1} := by
rw [funext intCast_eq_ite, Set.range_ite_const]
  · use 0; simp
  · use 1; simp

variable (R) in
```

-- snippet 15
```lean
-- Mathlib.Algebra.CharP.Two.intCast_cases (L132-L134)
theorem intCast_cases (n : ℤ) : (n : R) = 0 ∨ (n : R) = 1 :=
(Set.ext_iff.1 range_intCast _).1 (Set.mem_range_self _)
```

-- snippet 16
```lean
-- Mathlib.Algebra.CharP.Basic.natCast_injOn_Iio (L59-L66)
lemma natCast_injOn_Iio : (Set.Iio p).InjOn ((↑) : ℕ → R) :=
fun _a ha _b hb hab ↦ ((natCast_eq_natCast _ _).1 hab).eq_of_lt_of_lt ha hb

end AddMonoidWithOne

section AddGroupWithOne
variable [AddGroupWithOne R] (p : ℕ) [CharP R p] {a b : ℤ}
```

-- snippet 17
```lean
-- Mathlib.Algebra.CharP.Algebra.charP_of_injective_algebraMap' (L66-L71)
theorem charP_of_injective_algebraMap' (R : Type*) [CommRing R] [Semiring A]
    [Algebra R A] [FaithfulSMul R A] (p : ℕ) [CharP R p] : CharP A p :=
charP_of_injective_ringHom (FaithfulSMul.algebraMap_injective R A) p

/-- If a ring homomorphism `R →+* A` is injective and `R` has characteristic zero
then so does `A`. -/
```

-- snippet 18
```lean
-- Mathlib.Algebra.CharP.Algebra.charP (L132-L132)
instance charP [CharP R p] : CharP L p := L.subtype.charP L.subtype_injective p
```

-- snippet 19
```lean
-- Mathlib.Algebra.CharP.Basic.natCast_eq_natCast (L52-L58)
lemma natCast_eq_natCast : (a : R) = b ↔ a ≡ b [MOD p] := by
wlog hle : a ≤ b
  · rw [eq_comm, this R p (le_of_not_ge hle), Nat.ModEq.comm]
  rw [Nat.modEq_iff_dvd' hle, ← cast_eq_zero_iff R p (b - a),
    ← add_right_cancel_iff (G := R) (a := a) (b := b - a), zero_add, ← Nat.cast_add,
    Nat.sub_add_cancel hle, eq_comm]
```

-- snippet 20
```lean
-- Mathlib.Algebra.CharP.Algebra.charP_of_isFractionRing (L208-L211)
theorem charP_of_isFractionRing [CharP R p] : CharP K p :=
charP_of_injective_algebraMap (IsFractionRing.injective R K) p

/-- If `R` has characteristic `0`, then so does Frac(R). -/
```

-- snippet 21
```lean
-- Mathlib.Algebra.CharP.Algebra.charZero (L197-L207)
instance charZero [CharZero R] : CharZero (FreeAlgebra R X) :=
charZero_of_injective_algebraMap FreeAlgebra.algebraMap_leftInverse.injective

end FreeAlgebra

namespace IsFractionRing

variable (R : Type*) {K : Type*} [CommRing R] [Field K] [Algebra R K] [IsFractionRing R K]
variable (p : ℕ)

/-- If `R` has characteristic `p`, then so does Frac(R). -/
```

-- snippet 22
```lean
-- Mathlib.Algebra.CharP.Algebra.charP_of_injective_ringHom (L56-L61)
theorem charP_of_injective_ringHom [NonAssocSemiring R] [NonAssocSemiring A]
    {f : R →+* A} (h : Function.Injective f) (p : ℕ) [CharP R p] : CharP A p where
  cast_eq_zero_iff x := by
rw [← CharP.cast_eq_zero_iff R p x, ← map_natCast f x, map_eq_zero_iff f h]

/-- If the algebra map `R →+* A` is injective then `A` has the same characteristic as `R`. -/
```

-- snippet 23
```lean
-- Mathlib.Algebra.CharP.Algebra.charZero_of_isFractionRing (L212-L217)
theorem charZero_of_isFractionRing [CharZero R] : CharZero K :=
@CharP.charP_to_charZero K _ (charP_of_isFractionRing R 0)

variable [IsDomain R]

/-- If `R` has characteristic `p`, then so does `FractionRing R`. -/
```

-- snippet 24
```lean
-- Mathlib.Algebra.CharP.Algebra.CharP (L38-L43)
theorem CharP.dvd_of_ringHom [NonAssocSemiring R] [NonAssocSemiring A]
    (f : R →+* A) (p q : ℕ) [CharP R p] [CharP A q] : q ∣ p := by
refine (CharP.cast_eq_zero_iff A q p).mp ?_
  rw [← map_natCast f p, CharP.cast_eq_zero, map_zero]

/-- Given `R →+* A`, where `R` is a domain with `char R > 0`, then `char A = char R`. -/
```

-- snippet 25
```lean
-- Mathlib.Algebra.CharP.Algebra.RingHom (L83-L95)
theorem RingHom.charP [NonAssocSemiring R] [NonAssocSemiring A] (f : R →+* A)
    (H : Function.Injective f) (p : ℕ) [CharP A p] : CharP R p := by
obtain ⟨q, h⟩ := CharP.exists R
  exact CharP.eq _ (charP_of_injective_ringHom H q) ‹CharP A p› ▸ h

/-- If `R →+* A` is injective, then `R` is of characteristic `p` if and only if `A` is also of
characteristic `p`. Similar to `RingHom.charZero_iff`. -/
protected theorem RingHom.charP_iff [NonAssocSemiring R] [NonAssocSemiring A]
    (f : R →+* A) (H : Function.Injective f) (p : ℕ) : CharP R p ↔ CharP A p :=
  ⟨fun _ ↦ charP_of_injective_ringHom H p, fun _ ↦ f.charP H p⟩

/-- If a ring homomorphism `R →+* A` is injective then `A` has the same exponential characteristic
as `R`. -/
```

-- snippet 26
```lean
-- Mathlib.Algebra.CharP.Algebra.Algebra (L182-L185)
theorem Algebra.ringChar_eq : ringChar K = ringChar L := by
rw [ringChar.eq_iff, Algebra.charP_iff K L]
  apply ringChar.charP
```

-- snippet 27
```lean
-- Mathlib.Algebra.CharP.Algebra.charP_of_injective_algebraMap (L62-L65)
theorem charP_of_injective_algebraMap [CommSemiring R] [Semiring A] [Algebra R A]
    (h : Function.Injective (algebraMap R A)) (p : ℕ) [CharP R p] : CharP A p :=
charP_of_injective_ringHom h p
```

-- snippet 28
```lean
-- Mathlib.Algebra.CharP.Algebra.expChar_of_injective_ringHom (L96-L104)
lemma expChar_of_injective_ringHom
    [NonAssocSemiring R] [NonAssocSemiring A] {f : R →+* A} (h : Function.Injective f)
    (q : ℕ) [hR : ExpChar R q] : ExpChar A q := by
rcases hR with _ | hprime
  · haveI := charZero_of_injective_ringHom h; exact .zero
  haveI := charP_of_injective_ringHom h q; exact .prime hprime

/-- If `R →+* A` is injective, and `A` is of exponential characteristic `p`, then `R` is also of
exponential characteristic `p`. Similar to `RingHom.charZero`. -/
```

-- snippet 29
```lean
-- Mathlib.Algebra.CharP.Algebra.charZero_of_injective_algebraMap (L77-L82)
theorem charZero_of_injective_algebraMap [CommSemiring R] [Semiring A] [Algebra R A]
    (h : Function.Injective (algebraMap R A)) [CharZero R] : CharZero A :=
charZero_of_injective_ringHom h

/-- If `R →+* A` is injective, and `A` is of characteristic `p`, then `R` is also of
characteristic `p`. Similar to `RingHom.charZero`. -/
```

-- snippet 30
```lean
-- Mathlib.Algebra.CharP.Basic.intCast_injOn_Ico (L73-L91)
lemma intCast_injOn_Ico [IsRightCancelAdd R] : InjOn (Int.cast : ℤ → R) (Ico 0 p) := by
rintro a ⟨ha₀, ha⟩ b ⟨hb₀, hb⟩ hab
  lift a to ℕ using ha₀
  lift b to ℕ using hb₀
  norm_cast at *
  exact natCast_injOn_Iio _ _ ha hb hab

end AddGroupWithOne
end CharP

namespace CharP

section NonAssocSemiring

variable {R} [NonAssocSemiring R]

variable (R) in
/-- If a ring `R` is of characteristic `p`, then for any prime number `q` different from `p`,
it is not zero in `R`. -/
```

-- snippet 31
```lean
-- Mathlib.Algebra.CharP.Algebra.charZero_of_injective_ringHom (L72-L76)
theorem charZero_of_injective_ringHom [NonAssocSemiring R] [NonAssocSemiring A]
    {f : R →+* A} (h : Function.Injective f) [CharZero R] : CharZero A where
  cast_injective _ _ _ := CharZero.cast_injective <| h <| by simpa only [map_natCast f]
/-- If the algebra map `R →+* A` is injective and `R` has characteristic zero then so does `A`. -/
```

-- snippet 32
```lean
-- Mathlib.Algebra.CharP.Algebra.expChar (L133-L149)
instance expChar [ExpChar R p] : ExpChar L p := L.subtype.expChar L.subtype_injective p
end Subfield

/-!
As an application, a `ℚ`-algebra has characteristic zero.
-/

-- `CharP.charP_to_charZero A _ (charP_of_injective_algebraMap h 0)` does not work
-- here as it would require `Ring A`.
section QAlgebra

variable (R : Type*) [Nontrivial R]

/-- A nontrivial `ℚ`-algebra has `CharP` equal to zero.

This cannot be a (local) instance because it would immediately form a loop with the
```

-- snippet 33
```lean
-- Mathlib.Algebra.CharP.Basic.cast_ne_zero_of_ne_of_prime (L92-L98)
lemma cast_ne_zero_of_ne_of_prime [Nontrivial R]
    {p q : ℕ} [CharP R p] (hq : q.Prime) (hneq : p ≠ q) : (q : R) ≠ 0 := fun h ↦ by
rw [cast_eq_zero_iff R p q] at h
  rcases hq.eq_one_or_self_of_dvd _ h with rfl | h
  · exact false_of_nontrivial_of_char_one (R := R)
  · exact hneq h
```

-- snippet 34
```lean
-- Mathlib.Algebra.CharP.Algebra.algebraRat (L153-L158)
theorem algebraRat.charP_zero [Semiring R] [Algebra ℚ R] : CharP R 0 :=
charP_of_injective_algebraMap (algebraMap ℚ R).injective 0

/-- A nontrivial `ℚ`-algebra has characteristic zero.

This cannot be a (local) instance because it would immediately form a loop with the
```

-- snippet 35
```lean
-- Mathlib.Algebra.CharP.Basic.intCast_eq_intCast (L67-L69)
lemma intCast_eq_intCast : (a : R) = b ↔ a ≡ b [ZMOD p] := by
rw [eq_comm, ← sub_eq_zero, ← Int.cast_sub, CharP.intCast_eq_zero_iff R p, Int.modEq_iff_dvd]
```

-- snippet 36
```lean
-- Mathlib.Algebra.CharP.Basic.natCast_eq_natCast' (L41-L46)
lemma natCast_eq_natCast' (h : a ≡ b [MOD p]) : (a : R) = b := by
wlog hle : a ≤ b
  · exact (this R p h.symm (le_of_not_ge hle)).symm
  rw [Nat.modEq_iff_dvd' hle] at h
  rw [← Nat.sub_add_cancel hle, Nat.cast_add, (cast_eq_zero_iff R p _).mpr h, zero_add]
```

-- snippet 37
```lean
-- Mathlib.Algebra.CharP.Algebra.ExpChar (L124-L131)
theorem ExpChar.of_injective_algebraMap' [CommRing R] [CommRing A]
    [Algebra R A] [FaithfulSMul R A] (q : ℕ) [ExpChar R q] : ExpChar A q :=
expChar_of_injective_ringHom (FaithfulSMul.algebraMap_injective R A) q

namespace Subfield

variable [DivisionRing R] (L : Subfield R) (p : ℕ)
```

-- snippet 38
```lean
-- Mathlib.Algebra.CharP.Basic.intCast_eq_intCast_mod (L70-L72)
lemma intCast_eq_intCast_mod : (a : R) = a % (p : ℤ) :=
(CharP.intCast_eq_intCast R p).mpr (Int.mod_modEq a p).symm
```

-- snippet 39
```lean
-- Mathlib.Algebra.CharP.Algebra.expChar_of_injective_algebraMap (L119-L123)
lemma expChar_of_injective_algebraMap [CommSemiring R] [Semiring A] [Algebra R A]
    (h : Function.Injective (algebraMap R A)) (q : ℕ) [ExpChar R q] : ExpChar A q :=
expChar_of_injective_ringHom h q

variable (R) in
```

-- snippet 40
```lean
-- Mathlib.Algebra.CharP.Basic.natCast_eq_natCast_mod (L47-L51)
lemma natCast_eq_natCast_mod (a : ℕ) : (a : R) = a % p :=
natCast_eq_natCast' R p (Nat.mod_modEq a p).symm

variable [IsRightCancelAdd R]
```

<s>[SYSTEM_PROMPT]You are Leanstral, a Lean 4 proof assistant. Complete the task below using the provided Lean source context. The target mathlib commit is 5e932f97dd25535344f80f9dd8da3aab83df0fe6 (module Mathlib.Algebra.CharP.Two).[/SYSTEM_PROMPT][MODEL_SETTINGS]{"reasoning_effort": "none"}[/MODEL_SETTINGS][INST]Prove the following theorem. The retrieved context below may help.

```lean
theorem intCast_eq_ite (n : ℤ) : (n : R) = if Even n then 0 else 1
```

## Retrieved context
-- snippet 1
```lean
-- Mathlib.Algebra.CharP.Two.of_one_ne_zero_of_two_eq_zero (L37-L46)
theorem of_one_ne_zero_of_two_eq_zero (h₁ : (1 : R) ≠ 0) (h₂ : (2 : R) = 0) : CharP R 2 where
  cast_eq_zero_iff n := by
obtain hn | hn := Nat.even_or_odd n
    · simp_rw [hn.two_dvd, iff_true]
      exact natCast_eq_zero_of_even_of_two_eq_zero hn h₂
    · simp_rw [hn.not_two_dvd_nat, iff_false]
      rwa [natCast_eq_one_of_odd_of_two_eq_zero hn h₂]

variable [CharP R 2]
```

-- snippet 2
```lean
-- Mathlib.Algebra.CharP.Two.two_eq_zero (L48-L50)
theorem two_eq_zero : (2 : R) = 0 := by
rw [← Nat.cast_two, CharP.cast_eq_zero]
```

-- snippet 3
```lean
-- Mathlib.Algebra.CharP.Two.natCast_eq_ite (L51-L53)
theorem natCast_eq_ite (n : ℕ) : (n : R) = if Even n then 0 else 1 := by
induction n <;> aesop (add simp [one_add_one_eq_two])
```

-- snippet 4
```lean
-- Mathlib.Algebra.CharP.Two.range_natCast (L55-L60)
theorem range_natCast : Set.range ((↑) : ℕ → R) = {0, 1} := by
rw [funext natCast_eq_ite, Set.range_ite_const]
  · use 0; simp
  · use 1; simp

variable (R) in
```

-- snippet 5
```lean
-- Mathlib.Algebra.CharP.Two.natCast_cases (L61-L63)
theorem natCast_cases (n : ℕ) : (n : R) = 0 ∨ (n : R) = 1 :=
range_natCast.le (Set.mem_range_self _)
```

-- snippet 6
```lean
-- Mathlib.Algebra.CharP.Two.natCast_eq_mod (L64-L66)
theorem natCast_eq_mod (n : ℕ) : (n : R) = (n % 2 : ℕ) := by
simp [natCast_eq_ite, Nat.even_iff]
```

-- snippet 7
```lean
-- Mathlib.Algebra.CharP.Two.ofNat_eq_mod (L68-L70)
theorem ofNat_eq_mod (n : ℕ) [n.AtLeastTwo] : (ofNat(n) : R) = (ofNat(n) % 2 : ℕ) :=
natCast_eq_mod n
```

-- snippet 8
```lean
-- Mathlib.Algebra.CharP.Two.add_self_eq_zero (L80-L81)
theorem add_self_eq_zero (x : R) : x + x = 0 := by rw [← two_mul x, two_eq_zero, zero_mul]
```

-- snippet 9
```lean
-- Mathlib.Algebra.CharP.Two.neg_eq (L100-L102)
theorem neg_eq (x : R) : -x = x := by
rw [neg_eq_iff_add_eq_zero, add_self_eq_zero]
```

-- snippet 10
```lean
-- Mathlib.Algebra.CharP.Two.neg_eq' (L103-L105)
theorem neg_eq' : Neg.neg = (id : R → R) :=
funext neg_eq
```

-- snippet 11
```lean
-- Mathlib.Algebra.CharP.Two.sub_eq_add (L107-L108)
theorem sub_eq_add (x y : R) : x - y = x + y := by rw [sub_eq_add_neg, neg_eq]
```

-- snippet 12
```lean
-- Mathlib.Algebra.CharP.Two.add_eq_iff_eq_add (L109-L111)
theorem add_eq_iff_eq_add {a b c : R} : a + b = c ↔ a = c + b := by
rw [← sub_eq_iff_eq_add, sub_eq_add]
```

-- snippet 13
```lean
-- Mathlib.Algebra.CharP.Two.eq_add_iff_add_eq (L112-L114)
theorem eq_add_iff_add_eq {a b c : R} : a = b + c ↔ a + c = b := by
rw [← eq_sub_iff_add_eq, sub_eq_add]
```

-- snippet 14
```lean
-- Mathlib.Algebra.CharP.Two.range_intCast (L126-L131)
theorem range_intCast : Set.range ((↑) : ℤ → R) = {0, 1} := by
rw [funext intCast_eq_ite, Set.range_ite_const]
  · use 0; simp
  · use 1; simp

variable (R) in
```

-- snippet 15
```lean
-- Mathlib.Algebra.CharP.Two.intCast_cases (L132-L134)
theorem intCast_cases (n : ℤ) : (n : R) = 0 ∨ (n : R) = 1 :=
(Set.ext_iff.1 range_intCast _).1 (Set.mem_range_self _)
```

-- snippet 16
```lean
-- Mathlib.Algebra.CharP.Basic.natCast_injOn_Iio (L59-L66)
lemma natCast_injOn_Iio : (Set.Iio p).InjOn ((↑) : ℕ → R) :=
fun _a ha _b hb hab ↦ ((natCast_eq_natCast _ _).1 hab).eq_of_lt_of_lt ha hb

end AddMonoidWithOne

section AddGroupWithOne
variable [AddGroupWithOne R] (p : ℕ) [CharP R p] {a b : ℤ}
```

-- snippet 17
```lean
-- Mathlib.Algebra.CharP.Algebra.charP_of_injective_algebraMap' (L66-L71)
theorem charP_of_injective_algebraMap' (R : Type*) [CommRing R] [Semiring A]
    [Algebra R A] [FaithfulSMul R A] (p : ℕ) [CharP R p] : CharP A p :=
charP_of_injective_ringHom (FaithfulSMul.algebraMap_injective R A) p

/-- If a ring homomorphism `R →+* A` is injective and `R` has characteristic zero
then so does `A`. -/
```

-- snippet 18
```lean
-- Mathlib.Algebra.CharP.Algebra.charP (L132-L132)
instance charP [CharP R p] : CharP L p := L.subtype.charP L.subtype_injective p
```

-- snippet 19
```lean
-- Mathlib.Algebra.CharP.Basic.natCast_eq_natCast (L52-L58)
lemma natCast_eq_natCast : (a : R) = b ↔ a ≡ b [MOD p] := by
wlog hle : a ≤ b
  · rw [eq_comm, this R p (le_of_not_ge hle), Nat.ModEq.comm]
  rw [Nat.modEq_iff_dvd' hle, ← cast_eq_zero_iff R p (b - a),
    ← add_right_cancel_iff (G := R) (a := a) (b := b - a), zero_add, ← Nat.cast_add,
    Nat.sub_add_cancel hle, eq_comm]
```

-- snippet 20
```lean
-- Mathlib.Algebra.CharP.Algebra.charP_of_isFractionRing (L208-L211)
theorem charP_of_isFractionRing [CharP R p] : CharP K p :=
charP_of_injective_algebraMap (IsFractionRing.injective R K) p

/-- If `R` has characteristic `0`, then so does Frac(R). -/
```

-- snippet 21
```lean
-- Mathlib.Algebra.CharP.Algebra.charZero (L197-L207)
instance charZero [CharZero R] : CharZero (FreeAlgebra R X) :=
charZero_of_injective_algebraMap FreeAlgebra.algebraMap_leftInverse.injective

end FreeAlgebra

namespace IsFractionRing

variable (R : Type*) {K : Type*} [CommRing R] [Field K] [Algebra R K] [IsFractionRing R K]
variable (p : ℕ)

/-- If `R` has characteristic `p`, then so does Frac(R). -/
```

-- snippet 22
```lean
-- Mathlib.Algebra.CharP.Algebra.charP_of_injective_ringHom (L56-L61)
theorem charP_of_injective_ringHom [NonAssocSemiring R] [NonAssocSemiring A]
    {f : R →+* A} (h : Function.Injective f) (p : ℕ) [CharP R p] : CharP A p where
  cast_eq_zero_iff x := by
rw [← CharP.cast_eq_zero_iff R p x, ← map_natCast f x, map_eq_zero_iff f h]

/-- If the algebra map `R →+* A` is injective then `A` has the same characteristic as `R`. -/
```

-- snippet 23
```lean
-- Mathlib.Algebra.CharP.Algebra.charZero_of_isFractionRing (L212-L217)
theorem charZero_of_isFractionRing [CharZero R] : CharZero K :=
@CharP.charP_to_charZero K _ (charP_of_isFractionRing R 0)

variable [IsDomain R]

/-- If `R` has characteristic `p`, then so does `FractionRing R`. -/
```

-- snippet 24
```lean
-- Mathlib.Algebra.CharP.Algebra.CharP (L38-L43)
theorem CharP.dvd_of_ringHom [NonAssocSemiring R] [NonAssocSemiring A]
    (f : R →+* A) (p q : ℕ) [CharP R p] [CharP A q] : q ∣ p := by
refine (CharP.cast_eq_zero_iff A q p).mp ?_
  rw [← map_natCast f p, CharP.cast_eq_zero, map_zero]

/-- Given `R →+* A`, where `R` is a domain with `char R > 0`, then `char A = char R`. -/
```

-- snippet 25
```lean
-- Mathlib.Algebra.CharP.Algebra.RingHom (L83-L95)
theorem RingHom.charP [NonAssocSemiring R] [NonAssocSemiring A] (f : R →+* A)
    (H : Function.Injective f) (p : ℕ) [CharP A p] : CharP R p := by
obtain ⟨q, h⟩ := CharP.exists R
  exact CharP.eq _ (charP_of_injective_ringHom H q) ‹CharP A p› ▸ h

/-- If `R →+* A` is injective, then `R` is of characteristic `p` if and only if `A` is also of
characteristic `p`. Similar to `RingHom.charZero_iff`. -/
protected theorem RingHom.charP_iff [NonAssocSemiring R] [NonAssocSemiring A]
    (f : R →+* A) (H : Function.Injective f) (p : ℕ) : CharP R p ↔ CharP A p :=
  ⟨fun _ ↦ charP_of_injective_ringHom H p, fun _ ↦ f.charP H p⟩

/-- If a ring homomorphism `R →+* A` is injective then `A` has the same exponential characteristic
as `R`. -/
```

-- snippet 26
```lean
-- Mathlib.Algebra.CharP.Algebra.Algebra (L182-L185)
theorem Algebra.ringChar_eq : ringChar K = ringChar L := by
rw [ringChar.eq_iff, Algebra.charP_iff K L]
  apply ringChar.charP
```

-- snippet 27
```lean
-- Mathlib.Algebra.CharP.Algebra.charP_of_injective_algebraMap (L62-L65)
theorem charP_of_injective_algebraMap [CommSemiring R] [Semiring A] [Algebra R A]
    (h : Function.Injective (algebraMap R A)) (p : ℕ) [CharP R p] : CharP A p :=
charP_of_injective_ringHom h p
```

-- snippet 28
```lean
-- Mathlib.Algebra.CharP.Algebra.expChar_of_injective_ringHom (L96-L104)
lemma expChar_of_injective_ringHom
    [NonAssocSemiring R] [NonAssocSemiring A] {f : R →+* A} (h : Function.Injective f)
    (q : ℕ) [hR : ExpChar R q] : ExpChar A q := by
rcases hR with _ | hprime
  · haveI := charZero_of_injective_ringHom h; exact .zero
  haveI := charP_of_injective_ringHom h q; exact .prime hprime

/-- If `R →+* A` is injective, and `A` is of exponential characteristic `p`, then `R` is also of
exponential characteristic `p`. Similar to `RingHom.charZero`. -/
```

-- snippet 29
```lean
-- Mathlib.Algebra.CharP.Algebra.charZero_of_injective_algebraMap (L77-L82)
theorem charZero_of_injective_algebraMap [CommSemiring R] [Semiring A] [Algebra R A]
    (h : Function.Injective (algebraMap R A)) [CharZero R] : CharZero A :=
charZero_of_injective_ringHom h

/-- If `R →+* A` is injective, and `A` is of characteristic `p`, then `R` is also of
characteristic `p`. Similar to `RingHom.charZero`. -/
```

-- snippet 30
```lean
-- Mathlib.Algebra.CharP.Basic.intCast_injOn_Ico (L73-L91)
lemma intCast_injOn_Ico [IsRightCancelAdd R] : InjOn (Int.cast : ℤ → R) (Ico 0 p) := by
rintro a ⟨ha₀, ha⟩ b ⟨hb₀, hb⟩ hab
  lift a to ℕ using ha₀
  lift b to ℕ using hb₀
  norm_cast at *
  exact natCast_injOn_Iio _ _ ha hb hab

end AddGroupWithOne
end CharP

namespace CharP

section NonAssocSemiring

variable {R} [NonAssocSemiring R]

variable (R) in
/-- If a ring `R` is of characteristic `p`, then for any prime number `q` different from `p`,
it is not zero in `R`. -/
```

-- snippet 31
```lean
-- Mathlib.Algebra.CharP.Algebra.charZero_of_injective_ringHom (L72-L76)
theorem charZero_of_injective_ringHom [NonAssocSemiring R] [NonAssocSemiring A]
    {f : R →+* A} (h : Function.Injective f) [CharZero R] : CharZero A where
  cast_injective _ _ _ := CharZero.cast_injective <| h <| by simpa only [map_natCast f]
/-- If the algebra map `R →+* A` is injective and `R` has characteristic zero then so does `A`. -/
```

-- snippet 32
```lean
-- Mathlib.Algebra.CharP.Algebra.expChar (L133-L149)
instance expChar [ExpChar R p] : ExpChar L p := L.subtype.expChar L.subtype_injective p
end Subfield

/-!
As an application, a `ℚ`-algebra has characteristic zero.
-/

-- `CharP.charP_to_charZero A _ (charP_of_injective_algebraMap h 0)` does not work
-- here as it would require `Ring A`.
section QAlgebra

variable (R : Type*) [Nontrivial R]

/-- A nontrivial `ℚ`-algebra has `CharP` equal to zero.

This cannot be a (local) instance because it would immediately form a loop with the
```

-- snippet 33
```lean
-- Mathlib.Algebra.CharP.Basic.cast_ne_zero_of_ne_of_prime (L92-L98)
lemma cast_ne_zero_of_ne_of_prime [Nontrivial R]
    {p q : ℕ} [CharP R p] (hq : q.Prime) (hneq : p ≠ q) : (q : R) ≠ 0 := fun h ↦ by
rw [cast_eq_zero_iff R p q] at h
  rcases hq.eq_one_or_self_of_dvd _ h with rfl | h
  · exact false_of_nontrivial_of_char_one (R := R)
  · exact hneq h
```

-- snippet 34
```lean
-- Mathlib.Algebra.CharP.Algebra.algebraRat (L153-L158)
theorem algebraRat.charP_zero [Semiring R] [Algebra ℚ R] : CharP R 0 :=
charP_of_injective_algebraMap (algebraMap ℚ R).injective 0

/-- A nontrivial `ℚ`-algebra has characteristic zero.

This cannot be a (local) instance because it would immediately form a loop with the
```

-- snippet 35
```lean
-- Mathlib.Algebra.CharP.Basic.intCast_eq_intCast (L67-L69)
lemma intCast_eq_intCast : (a : R) = b ↔ a ≡ b [ZMOD p] := by
rw [eq_comm, ← sub_eq_zero, ← Int.cast_sub, CharP.intCast_eq_zero_iff R p, Int.modEq_iff_dvd]
```

-- snippet 36
```lean
-- Mathlib.Algebra.CharP.Basic.natCast_eq_natCast' (L41-L46)
lemma natCast_eq_natCast' (h : a ≡ b [MOD p]) : (a : R) = b := by
wlog hle : a ≤ b
  · exact (this R p h.symm (le_of_not_ge hle)).symm
  rw [Nat.modEq_iff_dvd' hle] at h
  rw [← Nat.sub_add_cancel hle, Nat.cast_add, (cast_eq_zero_iff R p _).mpr h, zero_add]
```

-- snippet 37
```lean
-- Mathlib.Algebra.CharP.Algebra.ExpChar (L124-L131)
theorem ExpChar.of_injective_algebraMap' [CommRing R] [CommRing A]
    [Algebra R A] [FaithfulSMul R A] (q : ℕ) [ExpChar R q] : ExpChar A q :=
expChar_of_injective_ringHom (FaithfulSMul.algebraMap_injective R A) q

namespace Subfield

variable [DivisionRing R] (L : Subfield R) (p : ℕ)
```

-- snippet 38
```lean
-- Mathlib.Algebra.CharP.Basic.intCast_eq_intCast_mod (L70-L72)
lemma intCast_eq_intCast_mod : (a : R) = a % (p : ℤ) :=
(CharP.intCast_eq_intCast R p).mpr (Int.mod_modEq a p).symm
```

-- snippet 39
```lean
-- Mathlib.Algebra.CharP.Algebra.expChar_of_injective_algebraMap (L119-L123)
lemma expChar_of_injective_algebraMap [CommSemiring R] [Semiring A] [Algebra R A]
    (h : Function.Injective (algebraMap R A)) (q : ℕ) [ExpChar R q] : ExpChar A q :=
expChar_of_injective_ringHom h q

variable (R) in
```

-- snippet 40
```lean
-- Mathlib.Algebra.CharP.Basic.natCast_eq_natCast_mod (L47-L51)
lemma natCast_eq_natCast_mod (a : ℕ) : (a : R) = a % p :=
natCast_eq_natCast' R p (Nat.mod_modEq a p).symm

variable [IsRightCancelAdd R]
```
[/INST]

mistral-common:Tekken v15 (Mistral chat template, [INST]/[SYSTEM_PROMPT])


[System] You are Leanstral, a Lean 4 proof assistant. Complete the task below using the provided Lean source context. The target mathlib commit is 5e932f97dd25535344f80f9dd8da3aab83df0fe6 (module Mathlib.Algebra.Group.Subgroup.Ker).

[User]
Prove the following theorem. The retrieved context below may help.

```lean
lemma MapSubtype.orderIso_symm_apply (H : Subgroup G) (sH' : { H' : Subgroup G // H' ≤ H }) :
    (MapSubtype.orderIso H).symm sH' = sH'.1.subgroupOf H
```

## Retrieved context
-- snippet 1
```lean
-- Mathlib.Algebra.Group.Subgroup.Ker.range (L67-L69)
def range (f : G →* N) : Subgroup N :=
Subgroup.copy ((⊤ : Subgroup G).map f) (Set.range f) (by simp)
```

-- snippet 2
```lean
-- Mathlib.Algebra.Group.Subgroup.Ker.coe_range (L71-L73)
theorem coe_range (f : G →* N) : (f.range : Set N) = Set.range f :=
rfl
```

-- snippet 3
```lean
-- Mathlib.Algebra.Group.Subgroup.Ker.mem_range (L75-L77)
theorem mem_range {f : G →* N} {y : N} : y ∈ f.range ↔ ∃ x, f x = y :=
Iff.rfl
```

-- snippet 4
```lean
-- Mathlib.Algebra.Group.Subgroup.Ker.range_eq_map (L79-L80)
theorem range_eq_map (f : G →* N) : f.range = (⊤ : Subgroup G).map f := by ext; simp
```

-- snippet 5
```lean
-- Mathlib.Algebra.Group.Subgroup.Ker.range_isMulCommutative (L82-L85)
instance range_isMulCommutative {G : Type*} [CommGroup G] {N : Type*} [Group N] (f : G →* N) :
    IsMulCommutative f.range :=
range_eq_map f ▸ Subgroup.map_isMulCommutative ⊤ f
```

-- snippet 6
```lean
-- Mathlib.Algebra.Group.Subgroup.Ker.restrict_range (L87-L92)
theorem restrict_range (f : G →* N) : (f.restrict K).range = K.map f := by
simp_rw [SetLike.ext_iff, mem_range, mem_map, restrict_apply, SetLike.exists,
    exists_prop, forall_const]

/-- The canonical surjective group homomorphism `G →* f(G)` induced by a group
homomorphism `G →* N`. -/
```

-- snippet 7
```lean
-- Mathlib.Algebra.Group.Subgroup.Ker.rangeRestrict (L96-L98)
def rangeRestrict (f : G →* N) : G →* f.range :=
codRestrict f _ fun x => ⟨x, rfl⟩
```

-- snippet 8
```lean
-- Mathlib.Algebra.Group.Subgroup.Ker.coe_rangeRestrict (L100-L102)
theorem coe_rangeRestrict (f : G →* N) (g : G) : (f.rangeRestrict g : N) = f g :=
rfl
```

-- snippet 9
```lean
-- Mathlib.Algebra.Group.Subgroup.Ker.coe_comp_rangeRestrict (L104-L107)
theorem coe_comp_rangeRestrict (f : G →* N) :
    ((↑) : f.range → N) ∘ (⇑f.rangeRestrict : G → f.range) = f :=
rfl
```

-- snippet 10
```lean
-- Mathlib.Algebra.Group.Subgroup.Ker.subtype_comp_rangeRestrict (L109-L111)
theorem subtype_comp_rangeRestrict (f : G →* N) : f.range.subtype.comp f.rangeRestrict = f :=
ext <| f.coe_rangeRestrict
```

-- snippet 11
```lean
-- Mathlib.Algebra.Group.Subgroup.Ker.rangeRestrict_surjective (L113-L115)
theorem rangeRestrict_surjective (f : G →* N) : Function.Surjective f.rangeRestrict :=
fun ⟨_, g, rfl⟩ => ⟨g, rfl⟩
```

-- snippet 12
```lean
-- Mathlib.Algebra.Group.Subgroup.Ker.rangeRestrict_injective_iff (L117-L119)
lemma rangeRestrict_injective_iff {f : G →* N} : Injective f.rangeRestrict ↔ Injective f := by
convert Set.injective_codRestrict _
```

-- snippet 13
```lean
-- Mathlib.Algebra.Group.Subgroup.Ker.map_range (L121-L123)
theorem map_range (g : N →* P) (f : G →* N) : f.range.map g = (g.comp f).range := by
rw [range_eq_map, range_eq_map]; exact (⊤ : Subgroup G).map_map g f
```

-- snippet 14
```lean
-- Mathlib.Algebra.Group.Subgroup.Ker.range_comp (L125-L126)
lemma range_comp (g : N →* P) (f : G →* N) : (g.comp f).range = f.range.map g := (map_range ..).symm
```

-- snippet 15
```lean
-- Mathlib.Algebra.Group.Subgroup.Ker.range_eq_top (L128-L132)
theorem range_eq_top {N} [Group N] {f : G →* N} :
    f.range = (⊤ : Subgroup N) ↔ Function.Surjective f :=
SetLike.ext'_iff.trans <| Iff.trans (by rw [coe_range, coe_top]) Set.range_eq_univ

/-- The range of a surjective monoid homomorphism is the whole of the codomain. -/
```

-- snippet 16
```lean
-- Mathlib.Algebra.Group.Action.Basic.toFun_apply (L156-L182)
lemma toFun_apply (x : M) (y : α) : MulAction.toFun M α y x = x • y := rfl
end MulAction

section MulDistribMulAction
variable [Monoid M] [Monoid A] [MulDistribMulAction M A]

/-- Pullback a multiplicative distributive multiplicative action along an injective monoid
homomorphism. -/
-- See note [reducible non-instances]
protected abbrev Function.Injective.mulDistribMulAction [Monoid B] [SMul M B] (f : B →* A)
    (hf : Injective f) (smul : ∀ (c : M) (x), f (c • x) = c • f x) : MulDistribMulAction M B where
  __ := hf.mulAction f smul
  smul_mul c x y := hf <| by simp only [smul, f.map_mul, smul_mul']
  smul_one c := hf <| by simp only [smul, f.map_one, smul_one]

/-- Pushforward a multiplicative distributive multiplicative action along a surjective monoid
homomorphism. -/
-- See note [reducible non-instances]
protected abbrev Function.Surjective.mulDistribMulAction [Monoid B] [SMul M B] (f : A →* B)
    (hf : Surjective f) (smul : ∀ (c : M) (x), f (c • x) = c • f x) : MulDistribMulAction M B where
  __ := hf.mulAction f smul
  smul_mul c := by simp only [hf.forall, smul_mul', ← smul, ← f.map_mul, implies_true]
  smul_one c := by rw [← f.map_one, ← smul, smul_one]

variable (A) in
/-- Scalar multiplication by `r` as a `MonoidHom`. -/
```

-- snippet 17
```lean
-- Mathlib.Algebra.Group.Action.Defs.smul_assoc (L214-L216)
lemma smul_assoc {M N} [SMul M N] [SMul N α] [SMul M α] [IsScalarTower M N α] (x : M) (y : N)
    (z : α) : (x • y) • z = x • y • z := IsScalarTower.smul_assoc x y z
```

-- snippet 18
```lean
-- Mathlib.Algebra.Group.Action.Defs.smul_eq_mul (L73-L74)
lemma smul_eq_mul {α : Type*} [Mul α] (a b : α) : a • b = a * b := rfl
```

-- snippet 19
```lean
-- Mathlib.Algebra.Group.Action.Basic.smul_left_cancel (L59-L60)
lemma smul_left_cancel (g : α) {x y : β} (h : g • x = g • y) : x = y := MulAction.injective g h
```

-- snippet 20
```lean
-- Mathlib.Algebra.Group.Action.Basic.MulDistribMulAction (L194-L203)
def MulDistribMulAction.toMonoidEnd : M →* Monoid.End A where
  toFun := MulDistribMulAction.toMonoidHom A
map_one' := MonoidHom.ext <| one_smul M
  map_mul' x y := MonoidHom.ext <| mul_smul x y

end MulDistribMulAction

section MulDistribMulAction
variable [Monoid M] [Group A] [MulDistribMulAction M A]
```

-- snippet 21
```lean
-- Mathlib.Algebra.Group.Action.Defs.SMulCommClass (L176-L182)
lemma SMulCommClass.symm (M N α : Type*) [SMul M α] [SMul N α] [SMulCommClass M N α] :
    SMulCommClass N M α where smul_comm a' a b := (smul_comm a a' b).symm
/-- Commutativity of additive actions is a symmetric relation. This lemma can't be an instance
because this would cause a loop in the instance search graph. -/
add_decl_doc VAddCommClass.symm
```

-- snippet 22
```lean
-- Mathlib.Algebra.Group.Action.Defs.MulOpposite (L79-L101)
lemma MulOpposite.smul_eq_mul_unop [Mul α] (a : αᵐᵒᵖ) (b : α) : a • b = b * a.unop := rfl
/-- Type class for actions by additive semigroups, with notation `g +ᵥ p`.

The `AddSemigroupAction G P` typeclass says that the additive semigroup `G` acts additively on a
type `P`.  More precisely this means that the action satisfies the axiom
`(g₁ + g₂) +ᵥ p = g₁ +ᵥ (g₂ +ᵥ p)`.  A mathematician might simply say that the additive semigroup
`G` acts on `P`.

For example, if `A` is an additive semigroup and `X` is a type, if a mathematician says
say "let `A` act on the set `X`" they will usually mean `[AddSemigroupAction A X]`. -/
class AddSemigroupAction (G P : Type*) [AddSemigroup G] extends VAdd G P where
  /-- Associativity of `+ᵥ` and `+` -/
  add_vadd : ∀ (g₁ g₂ : G) (p : P), (g₁ + g₂) +ᵥ p = g₁ +ᵥ g₂ +ᵥ p

/-- Type class for actions by semigroups, with notation `g • p`.

The `SemigroupAction G P` typeclass says that the semigroup `G` acts multiplicatively on a type `P`.
More precisely this means that the action satisfies the axiom `(g₁ * g₂) • p = g₁ • (g₂ • p)`.
A mathematician might simply say that the semigroup `G` acts on `P`.

For example, if `G` is a semigroup and `X` is a type, if a mathematician says
say "let `G` act on the set `X`" they will probably mean  `[SemigroupAction G X]`. -/
```

-- snippet 23
```lean
-- Mathlib.Algebra.Group.Action.Basic.invOf_smul_eq_iff (L86-L87)
lemma invOf_smul_eq_iff : ⅟c • x = y ↔ x = c • y := inv_smul_eq_iff (g := unitOfInvertible c)
```

-- snippet 24
```lean
-- Mathlib.Algebra.Group.Action.Basic.arrowAction (L100-L108)
def arrowAction : MulAction G (A → B) where
  smul g F a := F (g⁻¹ • a)
one_smul f := by
    change (fun x => f ((1 : G)⁻¹ • x)) = f
    simp only [inv_one, one_smul]
  mul_smul x y f := by
    change (fun a => f ((x * y)⁻¹ • a)) = (fun a => f (y⁻¹ • x⁻¹ • a))
    simp only [mul_smul, mul_inv_rev]
```

-- snippet 25
```lean
-- Mathlib.Algebra.Group.Action.Basic.arrowMulDistribMulAction (L115-L123)
def arrowMulDistribMulAction : MulDistribMulAction G (A → M) where
  smul_one _ := rfl
smul_mul _ _ _ := rfl

end Arrow

namespace IsUnit
variable [Monoid α] [MulAction α β]
```

-- snippet 26
```lean
-- Mathlib.Algebra.Group.Action.Defs.IsCentralScalar (L249-L255)
lemma IsCentralScalar.unop_smul_eq_smul {M α : Type*} [SMul M α] [SMul Mᵐᵒᵖ α]
    [IsCentralScalar M α] (m : Mᵐᵒᵖ) (a : α) : MulOpposite.unop m • a = m • a := by
induction m; exact (IsCentralScalar.op_smul_eq_smul _ a).symm

export IsCentralVAdd (op_vadd_eq_vadd unop_vadd_eq_vadd)
export IsCentralScalar (op_smul_eq_smul unop_smul_eq_smul)
```

-- snippet 27
```lean
-- Mathlib.Algebra.Group.Action.Basic.smul_zpow' (L210-L213)
lemma smul_zpow' (r : M) (x : A) (z : ℤ) : r • (x ^ z) = (r • x) ^ z :=
map_zpow (MulDistribMulAction.toMonoidHom A r) x z

end MulDistribMulAction
```

-- snippet 28
```lean
-- Mathlib.Algebra.Group.Action.Defs.Semigroup (L218-L242)
instance Semigroup.isScalarTower [Semigroup α] : IsScalarTower α α α := ⟨mul_assoc⟩
/-- An instance of `SMulDistribClass G R S` states that the multiplicative
action of `G` on `S` is determined by the multiplicative actions of `G` on `R`
and `R` on `S`.

This is similar to `IsScalarTower` except that the action of `G` distributes
over the action of `R` on `S`.

E.g. if `M/L/K` is a tower of galois extensions then `SMulDistribClass Gal(M/K) L M`. -/
class SMulDistribClass (G R S : Type*) [SMul G R] [SMul G S] [SMul R S] : Prop where
  smul_distrib_smul (g : G) (r : R) (s : S) : g • r • s = (g • r) • (g • s)

export SMulDistribClass (smul_distrib_smul)

/-- A typeclass indicating that the right (aka `AddOpposite`) and left actions by `M` on `α` are
equal, that is that `M` acts centrally on `α`. This can be thought of as a version of commutativity
for `+ᵥ`. -/
class IsCentralVAdd (M α : Type*) [VAdd M α] [VAdd Mᵃᵒᵖ α] : Prop where
  /-- The right and left actions of `M` on `α` are equal. -/
  op_vadd_eq_vadd : ∀ (m : M) (a : α), AddOpposite.op m +ᵥ a = m +ᵥ a

/-- A typeclass indicating that the right (aka `MulOpposite`) and left actions by `M` on `α` are
equal, that is that `M` acts centrally on `α`. This can be thought of as a version of commutativity
for `•`. -/
```

-- snippet 29
```lean
-- Mathlib.Algebra.Group.Action.Basic.smul_div' (L207-L209)
lemma smul_div' (r : M) (x y : A) : r • (x / y) = r • x / r • y :=
map_div (MulDistribMulAction.toMonoidHom A r) x y
```

-- snippet 30
```lean
-- Mathlib.Algebra.Group.Action.Basic.smul_eq_iff_eq_invOf_smul (L88-L97)
lemma smul_eq_iff_eq_invOf_smul : c • x = y ↔ x = ⅟c • y :=
smul_eq_iff_eq_inv_smul (g := unitOfInvertible c)

end Monoid
end MulAction

section Arrow
variable {G A B : Type*} [DivisionMonoid G] [MulAction G A]

/-- If `G` acts on `A`, then it acts also on `A → B`, by `(g • F) a = F (g⁻¹ • a)`. -/
```

-- snippet 31
```lean
-- Mathlib.Algebra.Group.Action.Basic.smul_eq_iff_eq_inv_smul (L66-L68)
lemma smul_eq_iff_eq_inv_smul (g : α) {x y : β} : g • x = y ↔ x = g⁻¹ • y :=
(MulAction.toPerm g).apply_eq_iff_eq_symm_apply
```

-- snippet 32
```lean
-- Mathlib.Algebra.Group.Action.Defs.Function (L184-L188)
lemma Function.Injective.smulCommClass [SMul M α] [SMul N α] [SMul M β] [SMul N β]
    [SMulCommClass M N β] {f : α → β} (hf : Injective f) (h₁ : ∀ (c : M) x, f (c • x) = c • f x)
    (h₂ : ∀ (c : N) x, f (c • x) = c • f x) : SMulCommClass M N α where
  smul_comm c₁ c₂ x := hf <| by simp only [h₁, h₂, smul_comm c₁ c₂ (f x)]
```

-- snippet 33
```lean
-- Mathlib.Algebra.Group.Action.Basic.isCancelSMul_iff_eq_one_of_smul_eq (L70-L80)
lemma isCancelSMul_iff_eq_one_of_smul_eq :
    IsCancelSMul α β ↔ (∀ (g : α) (x : β), g • x = x → g = 1) := by
refine ⟨fun H _ _ ↦ IsCancelSMul.eq_one_of_smul, fun H ↦ ⟨fun g h x ↦ ?_⟩⟩
  rw [smul_eq_iff_eq_inv_smul, eq_comm, ← mul_smul, ← inv_mul_eq_one (G := α)]
  exact H (g⁻¹ * h) x

end Group

section Monoid
variable [Monoid α] [MulAction α β] (c : α) (x y : β) [Invertible c]
```

-- snippet 34
```lean
-- Mathlib.Algebra.Group.Action.Basic.smul_bijective (L125-L129)
theorem smul_bijective {m : α} (hm : IsUnit m) :
    Function.Bijective (fun (a : β) ↦ m • a) := by
lift m to αˣ using hm
  exact MulAction.bijective m
```

-- snippet 35
```lean
-- Mathlib.Algebra.Group.Action.Defs.smulCommClass_self (L196-L207)
instance smulCommClass_self (M α : Type*) [CommMonoid M] [MulAction M α] : SMulCommClass M M α where
  smul_comm a a' b := by rw [← mul_smul, mul_comm, mul_smul]
/-- An instance of `VAddAssocClass M N α` states that the additive action of `M` on `α` is
determined by the additive actions of `M` on `N` and `N` on `α`. -/
class VAddAssocClass (M N α : Type*) [VAdd M N] [VAdd N α] [VAdd M α] : Prop where
  /-- Associativity of `+ᵥ` -/
  vadd_assoc : ∀ (x : M) (y : N) (z : α), (x +ᵥ y) +ᵥ z = x +ᵥ y +ᵥ z

/-- An instance of `IsScalarTower M N α` states that the multiplicative
action of `M` on `α` is determined by the multiplicative actions of `M` on `N`
and `N` on `α`. -/
```

-- snippet 36
```lean
-- Mathlib.Algebra.Group.Action.Basic.MulAction (L34-L40)
def MulAction.toPerm (a : α) : Equiv.Perm β :=
⟨fun x => a • x, fun x => a⁻¹ • x, inv_smul_smul a, smul_inv_smul a⟩

/-- Given an action of an additive group `α` on `β`, each `g : α` defines a permutation of `β`. -/
add_decl_doc AddAction.toPerm

/-- `MulAction.toPerm` is injective on faithful actions. -/
```

-- snippet 37
```lean
-- Mathlib.Algebra.Group.Action.Basic.toFun (L152-L154)
def toFun : α ↪ M → α :=
⟨fun y x ↦ x • y, fun y₁ y₂ H ↦ one_smul M y₁ ▸ one_smul M y₂ ▸ by convert congr_fun H 1⟩
```

-- snippet 38
```lean
-- Mathlib.Algebra.Group.Action.Defs.op_smul_eq_mul (L76-L77)
lemma op_smul_eq_mul {α : Type*} [Mul α] (a b : α) : MulOpposite.op a • b = b * a := rfl
```

-- snippet 39
```lean
-- Mathlib.Algebra.Group.Action.Basic.smul_left_cancel_iff (L62-L64)
lemma smul_left_cancel_iff (g : α) {x y : β} : g • x = g • y ↔ x = y :=
(MulAction.injective g).eq_iff
```

-- snippet 40
```lean
-- Mathlib.Algebra.Group.Action.Defs.Mul (L61-L65)
def Mul.toSMul (α : Type*) [Mul α] : SMul α α := ⟨(· * ·)⟩
/-- Like `Mul.toSMul`, but multiplies on the right.

See also `Monoid.toOppositeMulAction` and `MonoidWithZero.toOppositeMulActionWithZero`. -/
```

<s>[SYSTEM_PROMPT]You are Leanstral, a Lean 4 proof assistant. Complete the task below using the provided Lean source context. The target mathlib commit is 5e932f97dd25535344f80f9dd8da3aab83df0fe6 (module Mathlib.Algebra.Group.Subgroup.Ker).[/SYSTEM_PROMPT][MODEL_SETTINGS]{"reasoning_effort": "none"}[/MODEL_SETTINGS][INST]Prove the following theorem. The retrieved context below may help.

```lean
lemma MapSubtype.orderIso_symm_apply (H : Subgroup G) (sH' : { H' : Subgroup G // H' ≤ H }) :
    (MapSubtype.orderIso H).symm sH' = sH'.1.subgroupOf H
```

## Retrieved context
-- snippet 1
```lean
-- Mathlib.Algebra.Group.Subgroup.Ker.range (L67-L69)
def range (f : G →* N) : Subgroup N :=
Subgroup.copy ((⊤ : Subgroup G).map f) (Set.range f) (by simp)
```

-- snippet 2
```lean
-- Mathlib.Algebra.Group.Subgroup.Ker.coe_range (L71-L73)
theorem coe_range (f : G →* N) : (f.range : Set N) = Set.range f :=
rfl
```

-- snippet 3
```lean
-- Mathlib.Algebra.Group.Subgroup.Ker.mem_range (L75-L77)
theorem mem_range {f : G →* N} {y : N} : y ∈ f.range ↔ ∃ x, f x = y :=
Iff.rfl
```

-- snippet 4
```lean
-- Mathlib.Algebra.Group.Subgroup.Ker.range_eq_map (L79-L80)
theorem range_eq_map (f : G →* N) : f.range = (⊤ : Subgroup G).map f := by ext; simp
```

-- snippet 5
```lean
-- Mathlib.Algebra.Group.Subgroup.Ker.range_isMulCommutative (L82-L85)
instance range_isMulCommutative {G : Type*} [CommGroup G] {N : Type*} [Group N] (f : G →* N) :
    IsMulCommutative f.range :=
range_eq_map f ▸ Subgroup.map_isMulCommutative ⊤ f
```

-- snippet 6
```lean
-- Mathlib.Algebra.Group.Subgroup.Ker.restrict_range (L87-L92)
theorem restrict_range (f : G →* N) : (f.restrict K).range = K.map f := by
simp_rw [SetLike.ext_iff, mem_range, mem_map, restrict_apply, SetLike.exists,
    exists_prop, forall_const]

/-- The canonical surjective group homomorphism `G →* f(G)` induced by a group
homomorphism `G →* N`. -/
```

-- snippet 7
```lean
-- Mathlib.Algebra.Group.Subgroup.Ker.rangeRestrict (L96-L98)
def rangeRestrict (f : G →* N) : G →* f.range :=
codRestrict f _ fun x => ⟨x, rfl⟩
```

-- snippet 8
```lean
-- Mathlib.Algebra.Group.Subgroup.Ker.coe_rangeRestrict (L100-L102)
theorem coe_rangeRestrict (f : G →* N) (g : G) : (f.rangeRestrict g : N) = f g :=
rfl
```

-- snippet 9
```lean
-- Mathlib.Algebra.Group.Subgroup.Ker.coe_comp_rangeRestrict (L104-L107)
theorem coe_comp_rangeRestrict (f : G →* N) :
    ((↑) : f.range → N) ∘ (⇑f.rangeRestrict : G → f.range) = f :=
rfl
```

-- snippet 10
```lean
-- Mathlib.Algebra.Group.Subgroup.Ker.subtype_comp_rangeRestrict (L109-L111)
theorem subtype_comp_rangeRestrict (f : G →* N) : f.range.subtype.comp f.rangeRestrict = f :=
ext <| f.coe_rangeRestrict
```

-- snippet 11
```lean
-- Mathlib.Algebra.Group.Subgroup.Ker.rangeRestrict_surjective (L113-L115)
theorem rangeRestrict_surjective (f : G →* N) : Function.Surjective f.rangeRestrict :=
fun ⟨_, g, rfl⟩ => ⟨g, rfl⟩
```

-- snippet 12
```lean
-- Mathlib.Algebra.Group.Subgroup.Ker.rangeRestrict_injective_iff (L117-L119)
lemma rangeRestrict_injective_iff {f : G →* N} : Injective f.rangeRestrict ↔ Injective f := by
convert Set.injective_codRestrict _
```

-- snippet 13
```lean
-- Mathlib.Algebra.Group.Subgroup.Ker.map_range (L121-L123)
theorem map_range (g : N →* P) (f : G →* N) : f.range.map g = (g.comp f).range := by
rw [range_eq_map, range_eq_map]; exact (⊤ : Subgroup G).map_map g f
```

-- snippet 14
```lean
-- Mathlib.Algebra.Group.Subgroup.Ker.range_comp (L125-L126)
lemma range_comp (g : N →* P) (f : G →* N) : (g.comp f).range = f.range.map g := (map_range ..).symm
```

-- snippet 15
```lean
-- Mathlib.Algebra.Group.Subgroup.Ker.range_eq_top (L128-L132)
theorem range_eq_top {N} [Group N] {f : G →* N} :
    f.range = (⊤ : Subgroup N) ↔ Function.Surjective f :=
SetLike.ext'_iff.trans <| Iff.trans (by rw [coe_range, coe_top]) Set.range_eq_univ

/-- The range of a surjective monoid homomorphism is the whole of the codomain. -/
```

-- snippet 16
```lean
-- Mathlib.Algebra.Group.Action.Basic.toFun_apply (L156-L182)
lemma toFun_apply (x : M) (y : α) : MulAction.toFun M α y x = x • y := rfl
end MulAction

section MulDistribMulAction
variable [Monoid M] [Monoid A] [MulDistribMulAction M A]

/-- Pullback a multiplicative distributive multiplicative action along an injective monoid
homomorphism. -/
-- See note [reducible non-instances]
protected abbrev Function.Injective.mulDistribMulAction [Monoid B] [SMul M B] (f : B →* A)
    (hf : Injective f) (smul : ∀ (c : M) (x), f (c • x) = c • f x) : MulDistribMulAction M B where
  __ := hf.mulAction f smul
  smul_mul c x y := hf <| by simp only [smul, f.map_mul, smul_mul']
  smul_one c := hf <| by simp only [smul, f.map_one, smul_one]

/-- Pushforward a multiplicative distributive multiplicative action along a surjective monoid
homomorphism. -/
-- See note [reducible non-instances]
protected abbrev Function.Surjective.mulDistribMulAction [Monoid B] [SMul M B] (f : A →* B)
    (hf : Surjective f) (smul : ∀ (c : M) (x), f (c • x) = c • f x) : MulDistribMulAction M B where
  __ := hf.mulAction f smul
  smul_mul c := by simp only [hf.forall, smul_mul', ← smul, ← f.map_mul, implies_true]
  smul_one c := by rw [← f.map_one, ← smul, smul_one]

variable (A) in
/-- Scalar multiplication by `r` as a `MonoidHom`. -/
```

-- snippet 17
```lean
-- Mathlib.Algebra.Group.Action.Defs.smul_assoc (L214-L216)
lemma smul_assoc {M N} [SMul M N] [SMul N α] [SMul M α] [IsScalarTower M N α] (x : M) (y : N)
    (z : α) : (x • y) • z = x • y • z := IsScalarTower.smul_assoc x y z
```

-- snippet 18
```lean
-- Mathlib.Algebra.Group.Action.Defs.smul_eq_mul (L73-L74)
lemma smul_eq_mul {α : Type*} [Mul α] (a b : α) : a • b = a * b := rfl
```

-- snippet 19
```lean
-- Mathlib.Algebra.Group.Action.Basic.smul_left_cancel (L59-L60)
lemma smul_left_cancel (g : α) {x y : β} (h : g • x = g • y) : x = y := MulAction.injective g h
```

-- snippet 20
```lean
-- Mathlib.Algebra.Group.Action.Basic.MulDistribMulAction (L194-L203)
def MulDistribMulAction.toMonoidEnd : M →* Monoid.End A where
  toFun := MulDistribMulAction.toMonoidHom A
map_one' := MonoidHom.ext <| one_smul M
  map_mul' x y := MonoidHom.ext <| mul_smul x y

end MulDistribMulAction

section MulDistribMulAction
variable [Monoid M] [Group A] [MulDistribMulAction M A]
```

-- snippet 21
```lean
-- Mathlib.Algebra.Group.Action.Defs.SMulCommClass (L176-L182)
lemma SMulCommClass.symm (M N α : Type*) [SMul M α] [SMul N α] [SMulCommClass M N α] :
    SMulCommClass N M α where smul_comm a' a b := (smul_comm a a' b).symm
/-- Commutativity of additive actions is a symmetric relation. This lemma can't be an instance
because this would cause a loop in the instance search graph. -/
add_decl_doc VAddCommClass.symm
```

-- snippet 22
```lean
-- Mathlib.Algebra.Group.Action.Defs.MulOpposite (L79-L101)
lemma MulOpposite.smul_eq_mul_unop [Mul α] (a : αᵐᵒᵖ) (b : α) : a • b = b * a.unop := rfl
/-- Type class for actions by additive semigroups, with notation `g +ᵥ p`.

The `AddSemigroupAction G P` typeclass says that the additive semigroup `G` acts additively on a
type `P`.  More precisely this means that the action satisfies the axiom
`(g₁ + g₂) +ᵥ p = g₁ +ᵥ (g₂ +ᵥ p)`.  A mathematician might simply say that the additive semigroup
`G` acts on `P`.

For example, if `A` is an additive semigroup and `X` is a type, if a mathematician says
say "let `A` act on the set `X`" they will usually mean `[AddSemigroupAction A X]`. -/
class AddSemigroupAction (G P : Type*) [AddSemigroup G] extends VAdd G P where
  /-- Associativity of `+ᵥ` and `+` -/
  add_vadd : ∀ (g₁ g₂ : G) (p : P), (g₁ + g₂) +ᵥ p = g₁ +ᵥ g₂ +ᵥ p

/-- Type class for actions by semigroups, with notation `g • p`.

The `SemigroupAction G P` typeclass says that the semigroup `G` acts multiplicatively on a type `P`.
More precisely this means that the action satisfies the axiom `(g₁ * g₂) • p = g₁ • (g₂ • p)`.
A mathematician might simply say that the semigroup `G` acts on `P`.

For example, if `G` is a semigroup and `X` is a type, if a mathematician says
say "let `G` act on the set `X`" they will probably mean  `[SemigroupAction G X]`. -/
```

-- snippet 23
```lean
-- Mathlib.Algebra.Group.Action.Basic.invOf_smul_eq_iff (L86-L87)
lemma invOf_smul_eq_iff : ⅟c • x = y ↔ x = c • y := inv_smul_eq_iff (g := unitOfInvertible c)
```

-- snippet 24
```lean
-- Mathlib.Algebra.Group.Action.Basic.arrowAction (L100-L108)
def arrowAction : MulAction G (A → B) where
  smul g F a := F (g⁻¹ • a)
one_smul f := by
    change (fun x => f ((1 : G)⁻¹ • x)) = f
    simp only [inv_one, one_smul]
  mul_smul x y f := by
    change (fun a => f ((x * y)⁻¹ • a)) = (fun a => f (y⁻¹ • x⁻¹ • a))
    simp only [mul_smul, mul_inv_rev]
```

-- snippet 25
```lean
-- Mathlib.Algebra.Group.Action.Basic.arrowMulDistribMulAction (L115-L123)
def arrowMulDistribMulAction : MulDistribMulAction G (A → M) where
  smul_one _ := rfl
smul_mul _ _ _ := rfl

end Arrow

namespace IsUnit
variable [Monoid α] [MulAction α β]
```

-- snippet 26
```lean
-- Mathlib.Algebra.Group.Action.Defs.IsCentralScalar (L249-L255)
lemma IsCentralScalar.unop_smul_eq_smul {M α : Type*} [SMul M α] [SMul Mᵐᵒᵖ α]
    [IsCentralScalar M α] (m : Mᵐᵒᵖ) (a : α) : MulOpposite.unop m • a = m • a := by
induction m; exact (IsCentralScalar.op_smul_eq_smul _ a).symm

export IsCentralVAdd (op_vadd_eq_vadd unop_vadd_eq_vadd)
export IsCentralScalar (op_smul_eq_smul unop_smul_eq_smul)
```

-- snippet 27
```lean
-- Mathlib.Algebra.Group.Action.Basic.smul_zpow' (L210-L213)
lemma smul_zpow' (r : M) (x : A) (z : ℤ) : r • (x ^ z) = (r • x) ^ z :=
map_zpow (MulDistribMulAction.toMonoidHom A r) x z

end MulDistribMulAction
```

-- snippet 28
```lean
-- Mathlib.Algebra.Group.Action.Defs.Semigroup (L218-L242)
instance Semigroup.isScalarTower [Semigroup α] : IsScalarTower α α α := ⟨mul_assoc⟩
/-- An instance of `SMulDistribClass G R S` states that the multiplicative
action of `G` on `S` is determined by the multiplicative actions of `G` on `R`
and `R` on `S`.

This is similar to `IsScalarTower` except that the action of `G` distributes
over the action of `R` on `S`.

E.g. if `M/L/K` is a tower of galois extensions then `SMulDistribClass Gal(M/K) L M`. -/
class SMulDistribClass (G R S : Type*) [SMul G R] [SMul G S] [SMul R S] : Prop where
  smul_distrib_smul (g : G) (r : R) (s : S) : g • r • s = (g • r) • (g • s)

export SMulDistribClass (smul_distrib_smul)

/-- A typeclass indicating that the right (aka `AddOpposite`) and left actions by `M` on `α` are
equal, that is that `M` acts centrally on `α`. This can be thought of as a version of commutativity
for `+ᵥ`. -/
class IsCentralVAdd (M α : Type*) [VAdd M α] [VAdd Mᵃᵒᵖ α] : Prop where
  /-- The right and left actions of `M` on `α` are equal. -/
  op_vadd_eq_vadd : ∀ (m : M) (a : α), AddOpposite.op m +ᵥ a = m +ᵥ a

/-- A typeclass indicating that the right (aka `MulOpposite`) and left actions by `M` on `α` are
equal, that is that `M` acts centrally on `α`. This can be thought of as a version of commutativity
for `•`. -/
```

-- snippet 29
```lean
-- Mathlib.Algebra.Group.Action.Basic.smul_div' (L207-L209)
lemma smul_div' (r : M) (x y : A) : r • (x / y) = r • x / r • y :=
map_div (MulDistribMulAction.toMonoidHom A r) x y
```

-- snippet 30
```lean
-- Mathlib.Algebra.Group.Action.Basic.smul_eq_iff_eq_invOf_smul (L88-L97)
lemma smul_eq_iff_eq_invOf_smul : c • x = y ↔ x = ⅟c • y :=
smul_eq_iff_eq_inv_smul (g := unitOfInvertible c)

end Monoid
end MulAction

section Arrow
variable {G A B : Type*} [DivisionMonoid G] [MulAction G A]

/-- If `G` acts on `A`, then it acts also on `A → B`, by `(g • F) a = F (g⁻¹ • a)`. -/
```

-- snippet 31
```lean
-- Mathlib.Algebra.Group.Action.Basic.smul_eq_iff_eq_inv_smul (L66-L68)
lemma smul_eq_iff_eq_inv_smul (g : α) {x y : β} : g • x = y ↔ x = g⁻¹ • y :=
(MulAction.toPerm g).apply_eq_iff_eq_symm_apply
```

-- snippet 32
```lean
-- Mathlib.Algebra.Group.Action.Defs.Function (L184-L188)
lemma Function.Injective.smulCommClass [SMul M α] [SMul N α] [SMul M β] [SMul N β]
    [SMulCommClass M N β] {f : α → β} (hf : Injective f) (h₁ : ∀ (c : M) x, f (c • x) = c • f x)
    (h₂ : ∀ (c : N) x, f (c • x) = c • f x) : SMulCommClass M N α where
  smul_comm c₁ c₂ x := hf <| by simp only [h₁, h₂, smul_comm c₁ c₂ (f x)]
```

-- snippet 33
```lean
-- Mathlib.Algebra.Group.Action.Basic.isCancelSMul_iff_eq_one_of_smul_eq (L70-L80)
lemma isCancelSMul_iff_eq_one_of_smul_eq :
    IsCancelSMul α β ↔ (∀ (g : α) (x : β), g • x = x → g = 1) := by
refine ⟨fun H _ _ ↦ IsCancelSMul.eq_one_of_smul, fun H ↦ ⟨fun g h x ↦ ?_⟩⟩
  rw [smul_eq_iff_eq_inv_smul, eq_comm, ← mul_smul, ← inv_mul_eq_one (G := α)]
  exact H (g⁻¹ * h) x

end Group

section Monoid
variable [Monoid α] [MulAction α β] (c : α) (x y : β) [Invertible c]
```

-- snippet 34
```lean
-- Mathlib.Algebra.Group.Action.Basic.smul_bijective (L125-L129)
theorem smul_bijective {m : α} (hm : IsUnit m) :
    Function.Bijective (fun (a : β) ↦ m • a) := by
lift m to αˣ using hm
  exact MulAction.bijective m
```

-- snippet 35
```lean
-- Mathlib.Algebra.Group.Action.Defs.smulCommClass_self (L196-L207)
instance smulCommClass_self (M α : Type*) [CommMonoid M] [MulAction M α] : SMulCommClass M M α where
  smul_comm a a' b := by rw [← mul_smul, mul_comm, mul_smul]
/-- An instance of `VAddAssocClass M N α` states that the additive action of `M` on `α` is
determined by the additive actions of `M` on `N` and `N` on `α`. -/
class VAddAssocClass (M N α : Type*) [VAdd M N] [VAdd N α] [VAdd M α] : Prop where
  /-- Associativity of `+ᵥ` -/
  vadd_assoc : ∀ (x : M) (y : N) (z : α), (x +ᵥ y) +ᵥ z = x +ᵥ y +ᵥ z

/-- An instance of `IsScalarTower M N α` states that the multiplicative
action of `M` on `α` is determined by the multiplicative actions of `M` on `N`
and `N` on `α`. -/
```

-- snippet 36
```lean
-- Mathlib.Algebra.Group.Action.Basic.MulAction (L34-L40)
def MulAction.toPerm (a : α) : Equiv.Perm β :=
⟨fun x => a • x, fun x => a⁻¹ • x, inv_smul_smul a, smul_inv_smul a⟩

/-- Given an action of an additive group `α` on `β`, each `g : α` defines a permutation of `β`. -/
add_decl_doc AddAction.toPerm

/-- `MulAction.toPerm` is injective on faithful actions. -/
```

-- snippet 37
```lean
-- Mathlib.Algebra.Group.Action.Basic.toFun (L152-L154)
def toFun : α ↪ M → α :=
⟨fun y x ↦ x • y, fun y₁ y₂ H ↦ one_smul M y₁ ▸ one_smul M y₂ ▸ by convert congr_fun H 1⟩
```

-- snippet 38
```lean
-- Mathlib.Algebra.Group.Action.Defs.op_smul_eq_mul (L76-L77)
lemma op_smul_eq_mul {α : Type*} [Mul α] (a b : α) : MulOpposite.op a • b = b * a := rfl
```

-- snippet 39
```lean
-- Mathlib.Algebra.Group.Action.Basic.smul_left_cancel_iff (L62-L64)
lemma smul_left_cancel_iff (g : α) {x y : β} : g • x = g • y ↔ x = y :=
(MulAction.injective g).eq_iff
```

-- snippet 40
```lean
-- Mathlib.Algebra.Group.Action.Defs.Mul (L61-L65)
def Mul.toSMul (α : Type*) [Mul α] : SMul α α := ⟨(· * ·)⟩
/-- Like `Mul.toSMul`, but multiplies on the right.

See also `Monoid.toOppositeMulAction` and `MonoidWithZero.toOppositeMulActionWithZero`. -/
```
[/INST]