[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.Finsupp).

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

```lean
def eraseAddHom (a : ι) : (ι →₀ M) →+ ι →₀ M where
  toFun
```

## Retrieved context
-- snippet 1
```lean
-- Mathlib.Algebra.Group.Finsupp.apply_single (L31-L35)
lemma apply_single [FunLike F M N] [ZeroHomClass F M N] (e : F) (i : ι) (m : M) (b : ι) :
    e (single i m b) = single i (e m) b := apply_single' e (map_zero e) i m b
/-- Composition with a fixed zero-preserving homomorphism is itself a zero-preserving homomorphism
on functions. -/
```

-- snippet 2
```lean
-- Mathlib.Algebra.Group.Finsupp.mapRange (L37-L40)
def mapRange.zeroHom (f : ZeroHom M N) : ZeroHom (ι →₀ M) (ι →₀ N) where
  toFun := Finsupp.mapRange f f.map_zero
map_zero' := mapRange_zero
```

-- snippet 3
```lean
-- Mathlib.Algebra.Group.Finsupp.mapRange (L43-L51)
lemma mapRange.zeroHom_comp (f : ZeroHom N O) (f₂ : ZeroHom M N) :
    mapRange.zeroHom (ι := ι) (f.comp f₂) = (mapRange.zeroHom f).comp (mapRange.zeroHom f₂) := by
ext; simp

end Zero

section AddZeroClass
variable [AddZeroClass M] [AddZeroClass N] {f : M → N} {g₁ g₂ : ι →₀ M}
```

-- snippet 4
```lean
-- Mathlib.Algebra.Group.Finsupp.instAdd (L52-L53)
instance instAdd : Add (ι →₀ M) where add := zipWith (· + ·) (add_zero 0)
```

-- snippet 5
```lean
-- Mathlib.Algebra.Group.Finsupp.add_apply (L56-L57)
lemma add_apply (g₁ g₂ : ι →₀ M) (a : ι) : (g₁ + g₂) a = g₁ a + g₂ a := rfl
```

-- snippet 6
```lean
-- Mathlib.Algebra.Group.Finsupp.support_add (L58-L59)
lemma support_add [DecidableEq ι] : (g₁ + g₂).support ⊆ g₁.support ∪ g₂.support := support_zipWith
```

-- snippet 7
```lean
-- Mathlib.Algebra.Group.Finsupp.support_add_eq (L60-L64)
lemma support_add_eq [DecidableEq ι] (h : Disjoint g₁.support g₂.support) :
    (g₁ + g₂).support = g₁.support ∪ g₂.support :=
le_antisymm support_zipWith fun a ha => by
    cases (Finset.mem_union_of_disjoint h).mp ha <;> simp_all
```

-- snippet 8
```lean
-- Mathlib.Algebra.Group.Finsupp.instAddZeroClass (L65-L67)
instance instAddZeroClass : AddZeroClass (ι →₀ M) :=
fast_instance% DFunLike.coe_injective.addZeroClass _ coe_zero coe_add
```

-- snippet 9
```lean
-- Mathlib.Algebra.Group.Finsupp.instIsLeftCancelAdd (L68-L79)
instance instIsLeftCancelAdd [IsLeftCancelAdd M] : IsLeftCancelAdd (ι →₀ M) where
  add_left_cancel _ _ _ h := ext fun x => add_left_cancel <| DFunLike.congr_fun h x
/-- When ι is finite and M is an AddMonoid,
  then Finsupp.equivFunOnFinite gives an AddEquiv -/
noncomputable def addEquivFunOnFinite {ι : Type*} [Finite ι] :
    (ι →₀ M) ≃+ (ι → M) where
  __ := Finsupp.equivFunOnFinite
  map_add' _ _ := rfl

/-- If `M` is the trivial monoid, then the monoid of finitely supported functions `ι →₀ M` is
is isomorphic to `M`. -/
```

-- snippet 10
```lean
-- Mathlib.Algebra.Group.Finsupp.instIsRightCancelAdd (L85-L87)
instance instIsRightCancelAdd [IsRightCancelAdd M] : IsRightCancelAdd (ι →₀ M) where
  add_right_cancel _ _ _ h := ext fun x => add_right_cancel <| DFunLike.congr_fun h x
```

-- snippet 11
```lean
-- Mathlib.Algebra.Group.Finsupp.instIsCancelAdd (L88-L93)
instance instIsCancelAdd [IsCancelAdd M] : IsCancelAdd (ι →₀ M) where

/-- Evaluation of a function `f : ι →₀ M` at a point as an additive monoid homomorphism.

See `Finsupp.lapply` in `Mathlib/LinearAlgebra/Finsupp/Defs.lean` for the stronger version as a
linear map. -/
```

-- snippet 12
```lean
-- Mathlib.Algebra.Group.Finsupp.applyAddHom (L95-L100)
def applyAddHom (a : ι) : (ι →₀ M) →+ M where
  toFun g := g a
map_zero' := zero_apply
  map_add' _ _ := add_apply _ _ _

/-- Coercion from a `Finsupp` to a function type is an `AddMonoidHom`. -/
```

-- snippet 13
```lean
-- Mathlib.Algebra.Group.Finsupp.mapRange_add (L107-L110)
lemma mapRange_add {hf : f 0 = 0} (hf' : ∀ x y, f (x + y) = f x + f y) (v₁ v₂ : ι →₀ M) :
    mapRange f hf (v₁ + v₂) = mapRange f hf v₁ + mapRange f hf v₂ :=
ext fun _ => by simp only [hf', add_apply, mapRange_apply]
```

-- snippet 14
```lean
-- Mathlib.Algebra.Group.Finsupp.mapRange_add' (L111-L115)
lemma mapRange_add' [FunLike F M N] [AddMonoidHomClass F M N] {f : F} (g₁ g₂ : ι →₀ M) :
    mapRange f (map_zero f) (g₁ + g₂) = mapRange f (map_zero f) g₁ + mapRange f (map_zero f) g₂ :=
mapRange_add (map_add f) g₁ g₂

/-- Bundle `Finsupp.embDomain f` as an additive map from `ι →₀ M` to `F →₀ M`. -/
```

-- snippet 15
```lean
-- Mathlib.Algebra.Group.Finsupp.embDomain (L117-L126)
def embDomain.addMonoidHom (f : ι ↪ F) : (ι →₀ M) →+ F →₀ M where
  toFun v := embDomain f v
map_zero' := by simp
  map_add' v w := by
    ext b
    by_cases h : b ∈ Set.range f
    · rcases h with ⟨a, rfl⟩
      simp
    · simp only [coe_add, Pi.add_apply, embDomain_notin_range _ _ _ h, add_zero]
```

-- snippet 16
```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 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.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 19
```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 20
```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 21
```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 22
```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 23
```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 24
```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`. -/
```

-- snippet 25
```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 26
```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 27
```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 28
```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 29
```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 30
```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 31
```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 32
```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 33
```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 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.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 36
```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 37
```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 38
```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 39
```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 40
```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
```

<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.Finsupp).[/SYSTEM_PROMPT][MODEL_SETTINGS]{"reasoning_effort": "none"}[/MODEL_SETTINGS][INST]Prove the following theorem. The retrieved context below may help.

```lean
def eraseAddHom (a : ι) : (ι →₀ M) →+ ι →₀ M where
  toFun
```

## Retrieved context
-- snippet 1
```lean
-- Mathlib.Algebra.Group.Finsupp.apply_single (L31-L35)
lemma apply_single [FunLike F M N] [ZeroHomClass F M N] (e : F) (i : ι) (m : M) (b : ι) :
    e (single i m b) = single i (e m) b := apply_single' e (map_zero e) i m b
/-- Composition with a fixed zero-preserving homomorphism is itself a zero-preserving homomorphism
on functions. -/
```

-- snippet 2
```lean
-- Mathlib.Algebra.Group.Finsupp.mapRange (L37-L40)
def mapRange.zeroHom (f : ZeroHom M N) : ZeroHom (ι →₀ M) (ι →₀ N) where
  toFun := Finsupp.mapRange f f.map_zero
map_zero' := mapRange_zero
```

-- snippet 3
```lean
-- Mathlib.Algebra.Group.Finsupp.mapRange (L43-L51)
lemma mapRange.zeroHom_comp (f : ZeroHom N O) (f₂ : ZeroHom M N) :
    mapRange.zeroHom (ι := ι) (f.comp f₂) = (mapRange.zeroHom f).comp (mapRange.zeroHom f₂) := by
ext; simp

end Zero

section AddZeroClass
variable [AddZeroClass M] [AddZeroClass N] {f : M → N} {g₁ g₂ : ι →₀ M}
```

-- snippet 4
```lean
-- Mathlib.Algebra.Group.Finsupp.instAdd (L52-L53)
instance instAdd : Add (ι →₀ M) where add := zipWith (· + ·) (add_zero 0)
```

-- snippet 5
```lean
-- Mathlib.Algebra.Group.Finsupp.add_apply (L56-L57)
lemma add_apply (g₁ g₂ : ι →₀ M) (a : ι) : (g₁ + g₂) a = g₁ a + g₂ a := rfl
```

-- snippet 6
```lean
-- Mathlib.Algebra.Group.Finsupp.support_add (L58-L59)
lemma support_add [DecidableEq ι] : (g₁ + g₂).support ⊆ g₁.support ∪ g₂.support := support_zipWith
```

-- snippet 7
```lean
-- Mathlib.Algebra.Group.Finsupp.support_add_eq (L60-L64)
lemma support_add_eq [DecidableEq ι] (h : Disjoint g₁.support g₂.support) :
    (g₁ + g₂).support = g₁.support ∪ g₂.support :=
le_antisymm support_zipWith fun a ha => by
    cases (Finset.mem_union_of_disjoint h).mp ha <;> simp_all
```

-- snippet 8
```lean
-- Mathlib.Algebra.Group.Finsupp.instAddZeroClass (L65-L67)
instance instAddZeroClass : AddZeroClass (ι →₀ M) :=
fast_instance% DFunLike.coe_injective.addZeroClass _ coe_zero coe_add
```

-- snippet 9
```lean
-- Mathlib.Algebra.Group.Finsupp.instIsLeftCancelAdd (L68-L79)
instance instIsLeftCancelAdd [IsLeftCancelAdd M] : IsLeftCancelAdd (ι →₀ M) where
  add_left_cancel _ _ _ h := ext fun x => add_left_cancel <| DFunLike.congr_fun h x
/-- When ι is finite and M is an AddMonoid,
  then Finsupp.equivFunOnFinite gives an AddEquiv -/
noncomputable def addEquivFunOnFinite {ι : Type*} [Finite ι] :
    (ι →₀ M) ≃+ (ι → M) where
  __ := Finsupp.equivFunOnFinite
  map_add' _ _ := rfl

/-- If `M` is the trivial monoid, then the monoid of finitely supported functions `ι →₀ M` is
is isomorphic to `M`. -/
```

-- snippet 10
```lean
-- Mathlib.Algebra.Group.Finsupp.instIsRightCancelAdd (L85-L87)
instance instIsRightCancelAdd [IsRightCancelAdd M] : IsRightCancelAdd (ι →₀ M) where
  add_right_cancel _ _ _ h := ext fun x => add_right_cancel <| DFunLike.congr_fun h x
```

-- snippet 11
```lean
-- Mathlib.Algebra.Group.Finsupp.instIsCancelAdd (L88-L93)
instance instIsCancelAdd [IsCancelAdd M] : IsCancelAdd (ι →₀ M) where

/-- Evaluation of a function `f : ι →₀ M` at a point as an additive monoid homomorphism.

See `Finsupp.lapply` in `Mathlib/LinearAlgebra/Finsupp/Defs.lean` for the stronger version as a
linear map. -/
```

-- snippet 12
```lean
-- Mathlib.Algebra.Group.Finsupp.applyAddHom (L95-L100)
def applyAddHom (a : ι) : (ι →₀ M) →+ M where
  toFun g := g a
map_zero' := zero_apply
  map_add' _ _ := add_apply _ _ _

/-- Coercion from a `Finsupp` to a function type is an `AddMonoidHom`. -/
```

-- snippet 13
```lean
-- Mathlib.Algebra.Group.Finsupp.mapRange_add (L107-L110)
lemma mapRange_add {hf : f 0 = 0} (hf' : ∀ x y, f (x + y) = f x + f y) (v₁ v₂ : ι →₀ M) :
    mapRange f hf (v₁ + v₂) = mapRange f hf v₁ + mapRange f hf v₂ :=
ext fun _ => by simp only [hf', add_apply, mapRange_apply]
```

-- snippet 14
```lean
-- Mathlib.Algebra.Group.Finsupp.mapRange_add' (L111-L115)
lemma mapRange_add' [FunLike F M N] [AddMonoidHomClass F M N] {f : F} (g₁ g₂ : ι →₀ M) :
    mapRange f (map_zero f) (g₁ + g₂) = mapRange f (map_zero f) g₁ + mapRange f (map_zero f) g₂ :=
mapRange_add (map_add f) g₁ g₂

/-- Bundle `Finsupp.embDomain f` as an additive map from `ι →₀ M` to `F →₀ M`. -/
```

-- snippet 15
```lean
-- Mathlib.Algebra.Group.Finsupp.embDomain (L117-L126)
def embDomain.addMonoidHom (f : ι ↪ F) : (ι →₀ M) →+ F →₀ M where
  toFun v := embDomain f v
map_zero' := by simp
  map_add' v w := by
    ext b
    by_cases h : b ∈ Set.range f
    · rcases h with ⟨a, rfl⟩
      simp
    · simp only [coe_add, Pi.add_apply, embDomain_notin_range _ _ _ h, add_zero]
```

-- snippet 16
```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 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.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 19
```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 20
```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 21
```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 22
```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 23
```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 24
```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`. -/
```

-- snippet 25
```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 26
```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 27
```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 28
```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 29
```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 30
```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 31
```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 32
```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 33
```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 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.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 36
```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 37
```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 38
```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 39
```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 40
```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
```
[/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.DirectSum.Ring).

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

```lean
instance GradeZero.module {i} : Module (A 0) (A i)
```

## Retrieved context
-- snippet 1
```lean
-- Mathlib.Algebra.DirectSum.Ring.of_eq_of_gradedMonoid_eq (L144-L157)
theorem of_eq_of_gradedMonoid_eq {A : ι → Type*} [∀ i : ι, AddCommMonoid (A i)] {i j : ι} {a : A i}
    {b : A j} (h : GradedMonoid.mk i a = GradedMonoid.mk j b) :
    DirectSum.of A i a = DirectSum.of A j b :=
DFinsupp.single_eq_of_sigma_eq h

variable (A : ι → Type*)

/-! ### Instances for `⨁ i, A i` -/

section One

variable [Zero ι] [GradedMonoid.GOne A] [∀ i, AddCommMonoid (A i)]
```

-- snippet 2
```lean
-- Mathlib.Algebra.DirectSum.Ring.one_def (L160-L170)
theorem one_def : 1 = DirectSum.of A 0 GradedMonoid.GOne.one := rfl
end One

section Mul

variable [Add ι] [∀ i, AddCommMonoid (A i)] [GNonUnitalNonAssocSemiring A]

open AddMonoidHom (flip_apply coe_comp compHom)

/-- The piecewise multiplication from the `Mul` instance, as a bundled homomorphism. -/
```

-- snippet 3
```lean
-- Mathlib.Algebra.DirectSum.Ring.gMulHom (L172-L181)
def gMulHom {i j} : A i →+ A j →+ A (i + j) where
  toFun a :=
{ toFun := fun b => GradedMonoid.GMul.mul a b
      map_zero' := GNonUnitalNonAssocSemiring.mul_zero _
      map_add' := GNonUnitalNonAssocSemiring.mul_add _ }
  map_zero' := AddMonoidHom.ext fun a => GNonUnitalNonAssocSemiring.zero_mul a
  map_add' _ _ := AddMonoidHom.ext fun _ => GNonUnitalNonAssocSemiring.add_mul _ _ _

/-- The multiplication from the `Mul` instance, as a bundled homomorphism. -/
-- See note [non-reducible instance]
```

-- snippet 4
```lean
-- Mathlib.Algebra.DirectSum.Ring.mulHom (L183-L188)
def mulHom : (⨁ i, A i) →+ (⨁ i, A i) →+ ⨁ i, A i :=
DirectSum.toAddMonoid fun _ =>
    AddMonoidHom.flip <|
      DirectSum.toAddMonoid fun _ =>
        AddMonoidHom.flip <| (DirectSum.of A _).compHom.comp <| gMulHom A
```

-- snippet 5
```lean
-- Mathlib.Algebra.DirectSum.Ring.instMul (L189-L191)
instance instMul : Mul (⨁ i, A i) where
  mul := fun a b => mulHom A a b
```

-- snippet 6
```lean
-- Mathlib.Algebra.DirectSum.Ring.mulHom_apply (L201-L202)
theorem mulHom_apply (a b : ⨁ i, A i) : mulHom A a b = a * b := rfl
```

-- snippet 7
```lean
-- Mathlib.Algebra.DirectSum.Ring.mulHom_of_of (L203-L206)
theorem mulHom_of_of {i j} (a : A i) (b : A j) :
    mulHom A (of A i a) (of A j b) = of A (i + j) (GradedMonoid.GMul.mul a b) := by
simp
```

-- snippet 8
```lean
-- Mathlib.Algebra.DirectSum.Ring.of_mul_of (L207-L243)
theorem of_mul_of {i j} (a : A i) (b : A j) :
    of A i a * of A j b = of _ (i + j) (GradedMonoid.GMul.mul a b) :=
mulHom_of_of a b

end Mul

section Semiring

variable [∀ i, AddCommMonoid (A i)] [AddMonoid ι] [GSemiring A]

open AddMonoidHom (flipHom coe_comp compHom flip_apply)

private nonrec theorem one_mul (x : ⨁ i, A i) : 1 * x = x := by
  suffices mulHom A One.one = AddMonoidHom.id (⨁ i, A i) from DFunLike.congr_fun this x
  apply addHom_ext; intro i xi
  simp only [One.one]
  rw [mulHom_of_of]
  exact of_eq_of_gradedMonoid_eq (one_mul <| GradedMonoid.mk i xi)

private nonrec theorem mul_one (x : ⨁ i, A i) : x * 1 = x := by
  suffices (mulHom A).flip One.one = AddMonoidHom.id (⨁ i, A i) from DFunLike.congr_fun this x
  apply addHom_ext; intro i xi
  simp only [One.one]
  rw [flip_apply, mulHom_of_of]
  exact of_eq_of_gradedMonoid_eq (mul_one <| GradedMonoid.mk i xi)

private theorem mul_assoc (a b c : ⨁ i, A i) : a * b * c = a * (b * c) := by
  -- (`fun a b c => a * b * c` as a bundled hom) = (`fun a b c => a * (b * c)` as a bundled hom)
  suffices AddMonoidHom.mulLeft₃ = AddMonoidHom.mulRight₃ by
      simpa only [AddMonoidHom.mulLeft₃_apply, AddMonoidHom.mulRight₃_apply] using
        DFunLike.congr_fun (DFunLike.congr_fun (DFunLike.congr_fun this a) b) c
  ext ai ax bi bx ci cx : 6
  dsimp only [coe_comp, Function.comp_apply, AddMonoidHom.mulLeft₃_apply,
    AddMonoidHom.mulRight₃_apply]
  simp_rw [of_mul_of]
  exact of_eq_of_gradedMonoid_eq (_root_.mul_assoc (GradedMonoid.mk ai ax) ⟨bi, bx⟩ ⟨ci, cx⟩)
```

-- snippet 9
```lean
-- Mathlib.Algebra.DirectSum.Ring.instNatCast (L244-L247)
instance instNatCast : NatCast (⨁ i, A i) where
  natCast := fun n => of _ _ (GSemiring.natCast n)
/-- The `Semiring` structure derived from `GSemiring A`. -/
```

-- snippet 10
```lean
-- Mathlib.Algebra.DirectSum.Ring.semiring (L248-L258)
instance semiring : Semiring (⨁ i, A i) where
  one_mul := private one_mul A
mul_one := private mul_one A
  mul_assoc := private mul_assoc A
  toNatCast := instNatCast _
  natCast_zero := by simp only [NatCast.natCast, GSemiring.natCast_zero, map_zero]
  natCast_succ := fun n => by
    simp_rw [NatCast.natCast, GSemiring.natCast_succ]
    rw [map_add]
    rfl
```

-- snippet 11
```lean
-- Mathlib.Algebra.DirectSum.Ring.ofPow (L259-L266)
theorem ofPow {i} (a : A i) (n : ℕ) :
    of _ i a ^ n = of _ (n • i) (GradedMonoid.GMonoid.gnpow _ a) := by
induction n with
  | zero => exact of_eq_of_gradedMonoid_eq (pow_zero <| GradedMonoid.mk _ a).symm
  | succ n n_ih =>
    rw [pow_succ, n_ih, of_mul_of]
    exact of_eq_of_gradedMonoid_eq (pow_succ (GradedMonoid.mk _ a) n).symm
```

-- snippet 12
```lean
-- Mathlib.Algebra.DirectSum.Ring.ofList_dProd (L267-L276)
theorem ofList_dProd {α} (l : List α) (fι : α → ι) (fA : ∀ a, A (fι a)) :
    of A _ (l.dProd fι fA) = (l.map fun a => of A (fι a) (fA a)).prod := by
induction l with
  | nil => simp only [List.map_nil, List.prod_nil, List.dProd_nil]; rfl
  | cons head tail =>
    rename_i ih
    simp only [List.map_cons, List.prod_cons, List.dProd_cons, ← ih]
    rw [DirectSum.of_mul_of (fA head)]
    rfl
```

-- snippet 13
```lean
-- Mathlib.Algebra.DirectSum.Ring.list_prod_ofFn_of_eq_dProd (L277-L281)
theorem list_prod_ofFn_of_eq_dProd (n : ℕ) (fι : Fin n → ι) (fA : ∀ a, A (fι a)) :
    (List.ofFn fun a => of A (fι a) (fA a)).prod = of A _ ((List.finRange n).dProd fι fA) := by
rw [List.ofFn_eq_map, ofList_dProd]

set_option backward.isDefEq.respectTransparency false in
```

-- snippet 14
```lean
-- Mathlib.Algebra.DirectSum.Ring.mul_eq_dfinsuppSum (L282-L296)
theorem mul_eq_dfinsuppSum [∀ (i : ι) (x : A i), Decidable (x ≠ 0)] (a a' : ⨁ i, A i) :
    a * a'
      = a.sum fun _ ai => a'.sum fun _ aj => DirectSum.of _ _ <| GradedMonoid.GMul.mul ai aj := by
change mulHom _ a a' = _
  -- Porting note: I have no idea how the proof from ml3 worked it used to be
  -- simpa only [mul_hom, to_add_monoid, dfinsupp.lift_add_hom_apply, dfinsupp.sum_add_hom_apply,
  -- add_monoid_hom.dfinsupp_sum_apply, flip_apply, add_monoid_hom.dfinsupp_sum_add_hom_apply],
  rw [mulHom, toAddMonoid, DFinsupp.liftAddHom_apply]
  dsimp only [DirectSum]
  rw [DFinsupp.sumAddHom_apply, AddMonoidHom.dfinsuppSum_apply]
  apply congrArg _
  funext x
  simp [AddMonoidHom.dfinsuppSum_apply, DFinsupp.sumAddHom_apply, DirectSum.toAddMonoid]

/-- A heavily unfolded version of the definition of multiplication -/
```

-- snippet 15
```lean
-- Mathlib.Algebra.DirectSum.Ring.mul_eq_sum_support_ghas_mul (L297-L316)
theorem mul_eq_sum_support_ghas_mul [∀ (i : ι) (x : A i), Decidable (x ≠ 0)] (a a' : ⨁ i, A i) :
    a * a' =
      ∑ ij ∈ DFinsupp.support a ×ˢ DFinsupp.support a',
        DirectSum.of _ _ (GradedMonoid.GMul.mul (a ij.fst) (a' ij.snd)) := by
simp only [mul_eq_dfinsuppSum, DFinsupp.sum, Finset.sum_product]

end Semiring

section CommSemiring

variable [∀ i, AddCommMonoid (A i)] [AddCommMonoid ι] [GCommSemiring A]

private theorem mul_comm (a b : ⨁ i, A i) : a * b = b * a := by
  suffices mulHom A = (mulHom A).flip by
    rw [← mulHom_apply, this, AddMonoidHom.flip_apply, mulHom_apply]
  apply addHom_ext; intro ai ax; apply addHom_ext; intro bi bx
  rw [AddMonoidHom.flip_apply, mulHom_of_of, mulHom_of_of]
  exact of_eq_of_gradedMonoid_eq (GCommSemiring.mul_comm ⟨ai, ax⟩ ⟨bi, bx⟩)

/-- The `CommSemiring` structure derived from `GCommSemiring A`. -/
```

-- snippet 16
```lean
-- Mathlib.Algebra.DirectSum.Basic.of_eq_of_ne (L136-L138)
theorem of_eq_of_ne (i j : ι) (x : β i) (h : j ≠ i) : (of _ i x) j = 0 :=
DFinsupp.single_eq_of_ne h
```

-- snippet 17
```lean
-- Mathlib.Algebra.DirectSum.Basic.coeFnAddMonoidHom (L69-L72)
def coeFnAddMonoidHom [∀ i, AddCommMonoid (β i)] : (⨁ i, β i) →+ (Π i, β i) where
  toFun x := x
__ := DFinsupp.coeFnAddMonoidHom
```

-- snippet 18
```lean
-- Mathlib.Algebra.DirectSum.Algebra.toAlgebra (L116-L128)
def toAlgebra (f : ∀ i, A i →ₗ[R] B) (hone : f _ GradedMonoid.GOne.one = 1)
    (hmul : ∀ {i j} (ai : A i) (aj : A j), f _ (GradedMonoid.GMul.mul ai aj) = f _ ai * f _ aj) :
    (⨁ i, A i) →ₐ[R] B :=
{ toSemiring (fun i => (f i).toAddMonoidHom) hone @hmul with
    toFun := toSemiring (fun i => (f i).toAddMonoidHom) hone @hmul
    commutes' := fun r => by
      change toModule R _ _ f (algebraMap R _ r) = _
      rw [Algebra.algebraMap_eq_smul_one, Algebra.algebraMap_eq_smul_one, map_smul, one_def,
        ← lof_eq_of R, toModule_lof, hone] }

/-- Two `AlgHom`s out of a direct sum are equal if they agree on the generators.

See note [partially-applied ext lemmas]. -/
```

-- snippet 19
```lean
-- Mathlib.Algebra.DirectSum.Basic.of_eq_same (L133-L135)
theorem of_eq_same (i : ι) (x : β i) : (of _ i x) i = x :=
DFinsupp.single_eq_same
```

-- snippet 20
```lean
-- Mathlib.Algebra.DirectSum.Algebra.algebraMap_apply (L100-L103)
theorem algebraMap_apply (r : R) :
    algebraMap R (⨁ i, A i) r = DirectSum.of A 0 (GAlgebra.toFun r) :=
rfl
```

-- snippet 21
```lean
-- Mathlib.Algebra.DirectSum.Algebra.gMulLHom (L141-L156)
def gMulLHom {i j} : A i →ₗ[R] A j →ₗ[R] A (i + j) where
  toFun a :=
{ toFun := fun b => GradedMonoid.GMul.mul a b
      map_smul' := fun r x => by
        injection (smul_comm r (GradedMonoid.mk _ a) (GradedMonoid.mk _ x)).symm
      map_add' := GNonUnitalNonAssocSemiring.mul_add _ }
  map_smul' r x := LinearMap.ext fun y => by
    injection smul_assoc r (GradedMonoid.mk _ x) (GradedMonoid.mk _ y)
  map_add' _ _ := LinearMap.ext fun _ => GNonUnitalNonAssocSemiring.add_mul _ _ _

end DirectSum

/-! ### Concrete instances -/

/-- A direct sum of copies of an `Algebra` inherits the algebra structure. -/
```

-- snippet 22
```lean
-- Mathlib.Algebra.DirectSum.Basic.support_of (L155-L158)
theorem support_of [∀ (i : ι) (x : β i), Decidable (x ≠ 0)] (i : ι) (x : β i) (h : x ≠ 0) :
    (of _ i x).support = {i} :=
DFinsupp.support_single_ne_zero h
```

-- snippet 23
```lean
-- Mathlib.Algebra.DirectSum.Basic.mk_apply_of_notMem (L146-L149)
theorem mk_apply_of_notMem {s : Finset ι} {f : ∀ i : (↑s : Set ι), β i.val} {n : ι} (hn : n ∉ s) :
    mk β s f n = 0 :=
DFinsupp.mk_of_notMem hn
```

-- snippet 24
```lean
-- Mathlib.Algebra.DirectSum.Algebra.algHom_ext' (L130-L133)
theorem algHom_ext' ⦃f g : (⨁ i, A i) →ₐ[R] B⦄
    (h : ∀ i, f.toLinearMap.comp (lof _ _ A i) = g.toLinearMap.comp (lof _ _ A i)) : f = g :=
AlgHom.toLinearMap_injective <| DirectSum.linearMap_ext _ h
```

-- snippet 25
```lean
-- Mathlib.Algebra.DirectSum.Basic.coeFnAddMonoidHom_apply (L74-L81)
lemma coeFnAddMonoidHom_apply [∀ i, AddCommMonoid (β i)] (v : ⨁ i, β i) :
    coeFnAddMonoidHom β v = v :=
rfl

section AddCommGroup

variable [∀ i, AddCommGroup (β i)]
```

-- snippet 26
```lean
-- Mathlib.Algebra.DirectSum.Basic.sub_apply (L88-L94)
theorem sub_apply (g₁ g₂ : ⨁ i, β i) (i : ι) : (g₁ - g₂) i = g₁ i - g₂ i :=
rfl

end AddCommGroup

variable [∀ i, AddCommMonoid (β i)]
```

-- snippet 27
```lean
-- Mathlib.Algebra.DirectSum.AddChar.directSum_injective (L32-L39)
lemma directSum_injective :
    Injective (directSum : (∀ i, AddChar (G i) R) → AddChar (⨁ i, G i) R) := by
refine toAddMonoidHomEquiv.symm.injective.comp <| DirectSum.toAddMonoid_injective.comp ?_
  rintro ψ χ h
  simpa [funext_iff] using h

end DirectSum
end AddChar
```

-- snippet 28
```lean
-- Mathlib.Algebra.DirectSum.Basic.of_apply (L139-L141)
lemma of_apply {i : ι} (j : ι) (x : β i) : of β i x j = if h : i = j then Eq.recOn h x else 0 :=
DFinsupp.single_apply
```

-- snippet 29
```lean
-- Mathlib.Algebra.DirectSum.Basic.mk (L121-L126)
def mk (s : Finset ι) : (∀ i : (↑s : Set ι), β i.1) →+ ⨁ i, β i where
  toFun := DFinsupp.mk s
map_add' _ _ := DFinsupp.mk_add
  map_zero' := DFinsupp.mk_zero

/-- `of i` is the natural inclusion map from `β i` to `⨁ i, β i`. -/
```

-- snippet 30
```lean
-- Mathlib.Algebra.DirectSum.Basic.mk_apply_of_mem (L142-L145)
theorem mk_apply_of_mem {s : Finset ι} {f : ∀ i : (↑s : Set ι), β i.val} {n : ι} (hn : n ∈ s) :
    mk β s f n = f ⟨n, hn⟩ :=
DFinsupp.mk_of_mem hn
```

-- snippet 31
```lean
-- Mathlib.Algebra.DirectSum.AddChar.directSum (L29-L31)
def directSum (ψ : ∀ i, AddChar (G i) R) : AddChar (⨁ i, G i) R :=
toAddMonoidHomEquiv.symm <| DirectSum.toAddMonoid fun i ↦ toAddMonoidHomEquiv (ψ i)
```

-- snippet 32
```lean
-- Mathlib.Algebra.DirectSum.Algebra.algebraMap_toAddMonoid_hom (L104-L114)
theorem algebraMap_toAddMonoid_hom :
    ↑(algebraMap R (⨁ i, A i)) = (DirectSum.of A 0).comp (GAlgebra.toFun : R →+ A 0) :=
rfl

/-- A family of `LinearMap`s preserving `DirectSum.GOne.one` and `DirectSum.GMul.mul`
describes an `AlgHom` on `⨁ i, A i`. This is a stronger version of `DirectSum.toSemiring`.

Of particular interest is the case when `A i` are bundled subobjects, `f` is the family of
coercions such as `Submodule.subtype (A i)`, and the `[GMonoid A]` structure originates from
`DirectSum.GMonoid.ofAddSubmodules`, in which case the proofs about `GOne` and `GMul`
can be discharged by `rfl`. -/
```

-- snippet 33
```lean
-- Mathlib.Algebra.DirectSum.Basic.zero_apply (L99-L103)
theorem zero_apply (i : ι) : (0 : ⨁ i, β i) i = 0 :=
rfl

variable {β}
```

-- snippet 34
```lean
-- Mathlib.Algebra.DirectSum.Algebra.algHom_ext (L134-L139)
theorem algHom_ext ⦃f g : (⨁ i, A i) →ₐ[R] B⦄ (h : ∀ i x, f (of A i x) = g (of A i x)) : f = g :=
algHom_ext' R A fun i => LinearMap.ext <| h i

/-- The piecewise multiplication from the `Mul` instance, as a bundled linear map.

This is the graded version of `LinearMap.mul`, and the linear version of `DirectSum.gMulHom` -/
```

-- snippet 35
```lean
-- Mathlib.Algebra.DirectSum.Basic.support_zero (L151-L153)
theorem support_zero [∀ (i : ι) (x : β i), Decidable (x ≠ 0)] : (0 : ⨁ i, β i).support = ∅ :=
DFinsupp.support_zero
```

-- snippet 36
```lean
-- Mathlib.Algebra.DirectSum.Basic.add_apply (L105-L107)
theorem add_apply (g₁ g₂ : ⨁ i, β i) (i : ι) : (g₁ + g₂) i = g₁ i + g₂ i :=
rfl
```

-- snippet 37
```lean
-- Mathlib.Algebra.DirectSum.Basic.of (L127-L131)
def of (i : ι) : β i →+ ⨁ i, β i :=
DFinsupp.singleAddHom β i

variable {β}
```

-- snippet 38
```lean
-- Mathlib.Algebra.DirectSum.Basic.sum_apply (L109-L120)
theorem sum_apply {α} (s : Finset α) (g : α → ⨁ i, β i) (i : ι) :
    (∑ a ∈ s, g a) i = ∑ a ∈ s, g a i :=
DFinsupp.finset_sum_apply s g i

section DecidableEq

variable [DecidableEq ι]

variable (β)

/-- `mk β s x` is the element of `⨁ i, β i` that is zero outside `s`
and has coefficient `x i` for `i` in `s`. -/
```

-- snippet 39
```lean
-- Mathlib.Algebra.DirectSum.Basic.DirectSum (L38-L59)
def DirectSum [∀ i, AddCommMonoid (β i)] : Type _ :=
Π₀ i, β i
deriving AddCommMonoid, Inhabited, DFunLike

set_option backward.inferInstanceAs.wrap.data false in
deriving instance CoeFun for DirectSum

/-- `⨁ i, f i` is notation for `DirectSum _ f` and equals the direct sum of `fun i ↦ f i`.
Taking the direct sum over multiple arguments is possible, e.g. `⨁ (i) (j), f i j`. -/
scoped[DirectSum] notation3 "⨁ "(...)", "r:(scoped f => DirectSum _ f) => r

-- Porting note: The below recreates some of the lean3 notation, not fully yet
-- section
-- open Batteries.ExtendedBinder
-- syntax (name := bigdirectsum) "⨁ " extBinders ", " term : term
-- macro_rules (kind := bigdirectsum)
--   | `(⨁ $_:ident, $y:ident → $z:ident) => `(DirectSum _ (fun $y ↦ $z))
--   | `(⨁ $x:ident, $p) => `(DirectSum _ (fun $x ↦ $p))
--   | `(⨁ $_:ident : $t:ident, $p) => `(DirectSum _ (fun $t ↦ $p))
--   | `(⨁ ($x:ident) ($y:ident), $p) => `(DirectSum _ (fun $x ↦ fun $y ↦ $p))
-- end
```

-- snippet 40
```lean
-- Mathlib.Algebra.DirectSum.Algebra.Algebra (L158-L165)
instance Algebra.directSumGAlgebra {R A : Type*} [AddMonoid ι] [CommSemiring R]
    [Semiring A] [Algebra R A] : DirectSum.GAlgebra R fun _ : ι => A where
  toFun := (algebraMap R A).toAddMonoidHom
map_one := (algebraMap R A).map_one
  map_mul a b := Sigma.ext (zero_add _).symm (heq_of_eq <| (algebraMap R A).map_mul a b)
  commutes := fun _ ⟨_, _⟩ =>
    Sigma.ext ((zero_add _).trans (add_zero _).symm) (heq_of_eq <| Algebra.commutes _ _)
  smul_def := fun _ ⟨_, _⟩ => Sigma.ext (zero_add _).symm (heq_of_eq <| Algebra.smul_def _ _)
```

<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.DirectSum.Ring).[/SYSTEM_PROMPT][MODEL_SETTINGS]{"reasoning_effort": "none"}[/MODEL_SETTINGS][INST]Prove the following theorem. The retrieved context below may help.

```lean
instance GradeZero.module {i} : Module (A 0) (A i)
```

## Retrieved context
-- snippet 1
```lean
-- Mathlib.Algebra.DirectSum.Ring.of_eq_of_gradedMonoid_eq (L144-L157)
theorem of_eq_of_gradedMonoid_eq {A : ι → Type*} [∀ i : ι, AddCommMonoid (A i)] {i j : ι} {a : A i}
    {b : A j} (h : GradedMonoid.mk i a = GradedMonoid.mk j b) :
    DirectSum.of A i a = DirectSum.of A j b :=
DFinsupp.single_eq_of_sigma_eq h

variable (A : ι → Type*)

/-! ### Instances for `⨁ i, A i` -/

section One

variable [Zero ι] [GradedMonoid.GOne A] [∀ i, AddCommMonoid (A i)]
```

-- snippet 2
```lean
-- Mathlib.Algebra.DirectSum.Ring.one_def (L160-L170)
theorem one_def : 1 = DirectSum.of A 0 GradedMonoid.GOne.one := rfl
end One

section Mul

variable [Add ι] [∀ i, AddCommMonoid (A i)] [GNonUnitalNonAssocSemiring A]

open AddMonoidHom (flip_apply coe_comp compHom)

/-- The piecewise multiplication from the `Mul` instance, as a bundled homomorphism. -/
```

-- snippet 3
```lean
-- Mathlib.Algebra.DirectSum.Ring.gMulHom (L172-L181)
def gMulHom {i j} : A i →+ A j →+ A (i + j) where
  toFun a :=
{ toFun := fun b => GradedMonoid.GMul.mul a b
      map_zero' := GNonUnitalNonAssocSemiring.mul_zero _
      map_add' := GNonUnitalNonAssocSemiring.mul_add _ }
  map_zero' := AddMonoidHom.ext fun a => GNonUnitalNonAssocSemiring.zero_mul a
  map_add' _ _ := AddMonoidHom.ext fun _ => GNonUnitalNonAssocSemiring.add_mul _ _ _

/-- The multiplication from the `Mul` instance, as a bundled homomorphism. -/
-- See note [non-reducible instance]
```

-- snippet 4
```lean
-- Mathlib.Algebra.DirectSum.Ring.mulHom (L183-L188)
def mulHom : (⨁ i, A i) →+ (⨁ i, A i) →+ ⨁ i, A i :=
DirectSum.toAddMonoid fun _ =>
    AddMonoidHom.flip <|
      DirectSum.toAddMonoid fun _ =>
        AddMonoidHom.flip <| (DirectSum.of A _).compHom.comp <| gMulHom A
```

-- snippet 5
```lean
-- Mathlib.Algebra.DirectSum.Ring.instMul (L189-L191)
instance instMul : Mul (⨁ i, A i) where
  mul := fun a b => mulHom A a b
```

-- snippet 6
```lean
-- Mathlib.Algebra.DirectSum.Ring.mulHom_apply (L201-L202)
theorem mulHom_apply (a b : ⨁ i, A i) : mulHom A a b = a * b := rfl
```

-- snippet 7
```lean
-- Mathlib.Algebra.DirectSum.Ring.mulHom_of_of (L203-L206)
theorem mulHom_of_of {i j} (a : A i) (b : A j) :
    mulHom A (of A i a) (of A j b) = of A (i + j) (GradedMonoid.GMul.mul a b) := by
simp
```

-- snippet 8
```lean
-- Mathlib.Algebra.DirectSum.Ring.of_mul_of (L207-L243)
theorem of_mul_of {i j} (a : A i) (b : A j) :
    of A i a * of A j b = of _ (i + j) (GradedMonoid.GMul.mul a b) :=
mulHom_of_of a b

end Mul

section Semiring

variable [∀ i, AddCommMonoid (A i)] [AddMonoid ι] [GSemiring A]

open AddMonoidHom (flipHom coe_comp compHom flip_apply)

private nonrec theorem one_mul (x : ⨁ i, A i) : 1 * x = x := by
  suffices mulHom A One.one = AddMonoidHom.id (⨁ i, A i) from DFunLike.congr_fun this x
  apply addHom_ext; intro i xi
  simp only [One.one]
  rw [mulHom_of_of]
  exact of_eq_of_gradedMonoid_eq (one_mul <| GradedMonoid.mk i xi)

private nonrec theorem mul_one (x : ⨁ i, A i) : x * 1 = x := by
  suffices (mulHom A).flip One.one = AddMonoidHom.id (⨁ i, A i) from DFunLike.congr_fun this x
  apply addHom_ext; intro i xi
  simp only [One.one]
  rw [flip_apply, mulHom_of_of]
  exact of_eq_of_gradedMonoid_eq (mul_one <| GradedMonoid.mk i xi)

private theorem mul_assoc (a b c : ⨁ i, A i) : a * b * c = a * (b * c) := by
  -- (`fun a b c => a * b * c` as a bundled hom) = (`fun a b c => a * (b * c)` as a bundled hom)
  suffices AddMonoidHom.mulLeft₃ = AddMonoidHom.mulRight₃ by
      simpa only [AddMonoidHom.mulLeft₃_apply, AddMonoidHom.mulRight₃_apply] using
        DFunLike.congr_fun (DFunLike.congr_fun (DFunLike.congr_fun this a) b) c
  ext ai ax bi bx ci cx : 6
  dsimp only [coe_comp, Function.comp_apply, AddMonoidHom.mulLeft₃_apply,
    AddMonoidHom.mulRight₃_apply]
  simp_rw [of_mul_of]
  exact of_eq_of_gradedMonoid_eq (_root_.mul_assoc (GradedMonoid.mk ai ax) ⟨bi, bx⟩ ⟨ci, cx⟩)
```

-- snippet 9
```lean
-- Mathlib.Algebra.DirectSum.Ring.instNatCast (L244-L247)
instance instNatCast : NatCast (⨁ i, A i) where
  natCast := fun n => of _ _ (GSemiring.natCast n)
/-- The `Semiring` structure derived from `GSemiring A`. -/
```

-- snippet 10
```lean
-- Mathlib.Algebra.DirectSum.Ring.semiring (L248-L258)
instance semiring : Semiring (⨁ i, A i) where
  one_mul := private one_mul A
mul_one := private mul_one A
  mul_assoc := private mul_assoc A
  toNatCast := instNatCast _
  natCast_zero := by simp only [NatCast.natCast, GSemiring.natCast_zero, map_zero]
  natCast_succ := fun n => by
    simp_rw [NatCast.natCast, GSemiring.natCast_succ]
    rw [map_add]
    rfl
```

-- snippet 11
```lean
-- Mathlib.Algebra.DirectSum.Ring.ofPow (L259-L266)
theorem ofPow {i} (a : A i) (n : ℕ) :
    of _ i a ^ n = of _ (n • i) (GradedMonoid.GMonoid.gnpow _ a) := by
induction n with
  | zero => exact of_eq_of_gradedMonoid_eq (pow_zero <| GradedMonoid.mk _ a).symm
  | succ n n_ih =>
    rw [pow_succ, n_ih, of_mul_of]
    exact of_eq_of_gradedMonoid_eq (pow_succ (GradedMonoid.mk _ a) n).symm
```

-- snippet 12
```lean
-- Mathlib.Algebra.DirectSum.Ring.ofList_dProd (L267-L276)
theorem ofList_dProd {α} (l : List α) (fι : α → ι) (fA : ∀ a, A (fι a)) :
    of A _ (l.dProd fι fA) = (l.map fun a => of A (fι a) (fA a)).prod := by
induction l with
  | nil => simp only [List.map_nil, List.prod_nil, List.dProd_nil]; rfl
  | cons head tail =>
    rename_i ih
    simp only [List.map_cons, List.prod_cons, List.dProd_cons, ← ih]
    rw [DirectSum.of_mul_of (fA head)]
    rfl
```

-- snippet 13
```lean
-- Mathlib.Algebra.DirectSum.Ring.list_prod_ofFn_of_eq_dProd (L277-L281)
theorem list_prod_ofFn_of_eq_dProd (n : ℕ) (fι : Fin n → ι) (fA : ∀ a, A (fι a)) :
    (List.ofFn fun a => of A (fι a) (fA a)).prod = of A _ ((List.finRange n).dProd fι fA) := by
rw [List.ofFn_eq_map, ofList_dProd]

set_option backward.isDefEq.respectTransparency false in
```

-- snippet 14
```lean
-- Mathlib.Algebra.DirectSum.Ring.mul_eq_dfinsuppSum (L282-L296)
theorem mul_eq_dfinsuppSum [∀ (i : ι) (x : A i), Decidable (x ≠ 0)] (a a' : ⨁ i, A i) :
    a * a'
      = a.sum fun _ ai => a'.sum fun _ aj => DirectSum.of _ _ <| GradedMonoid.GMul.mul ai aj := by
change mulHom _ a a' = _
  -- Porting note: I have no idea how the proof from ml3 worked it used to be
  -- simpa only [mul_hom, to_add_monoid, dfinsupp.lift_add_hom_apply, dfinsupp.sum_add_hom_apply,
  -- add_monoid_hom.dfinsupp_sum_apply, flip_apply, add_monoid_hom.dfinsupp_sum_add_hom_apply],
  rw [mulHom, toAddMonoid, DFinsupp.liftAddHom_apply]
  dsimp only [DirectSum]
  rw [DFinsupp.sumAddHom_apply, AddMonoidHom.dfinsuppSum_apply]
  apply congrArg _
  funext x
  simp [AddMonoidHom.dfinsuppSum_apply, DFinsupp.sumAddHom_apply, DirectSum.toAddMonoid]

/-- A heavily unfolded version of the definition of multiplication -/
```

-- snippet 15
```lean
-- Mathlib.Algebra.DirectSum.Ring.mul_eq_sum_support_ghas_mul (L297-L316)
theorem mul_eq_sum_support_ghas_mul [∀ (i : ι) (x : A i), Decidable (x ≠ 0)] (a a' : ⨁ i, A i) :
    a * a' =
      ∑ ij ∈ DFinsupp.support a ×ˢ DFinsupp.support a',
        DirectSum.of _ _ (GradedMonoid.GMul.mul (a ij.fst) (a' ij.snd)) := by
simp only [mul_eq_dfinsuppSum, DFinsupp.sum, Finset.sum_product]

end Semiring

section CommSemiring

variable [∀ i, AddCommMonoid (A i)] [AddCommMonoid ι] [GCommSemiring A]

private theorem mul_comm (a b : ⨁ i, A i) : a * b = b * a := by
  suffices mulHom A = (mulHom A).flip by
    rw [← mulHom_apply, this, AddMonoidHom.flip_apply, mulHom_apply]
  apply addHom_ext; intro ai ax; apply addHom_ext; intro bi bx
  rw [AddMonoidHom.flip_apply, mulHom_of_of, mulHom_of_of]
  exact of_eq_of_gradedMonoid_eq (GCommSemiring.mul_comm ⟨ai, ax⟩ ⟨bi, bx⟩)

/-- The `CommSemiring` structure derived from `GCommSemiring A`. -/
```

-- snippet 16
```lean
-- Mathlib.Algebra.DirectSum.Basic.of_eq_of_ne (L136-L138)
theorem of_eq_of_ne (i j : ι) (x : β i) (h : j ≠ i) : (of _ i x) j = 0 :=
DFinsupp.single_eq_of_ne h
```

-- snippet 17
```lean
-- Mathlib.Algebra.DirectSum.Basic.coeFnAddMonoidHom (L69-L72)
def coeFnAddMonoidHom [∀ i, AddCommMonoid (β i)] : (⨁ i, β i) →+ (Π i, β i) where
  toFun x := x
__ := DFinsupp.coeFnAddMonoidHom
```

-- snippet 18
```lean
-- Mathlib.Algebra.DirectSum.Algebra.toAlgebra (L116-L128)
def toAlgebra (f : ∀ i, A i →ₗ[R] B) (hone : f _ GradedMonoid.GOne.one = 1)
    (hmul : ∀ {i j} (ai : A i) (aj : A j), f _ (GradedMonoid.GMul.mul ai aj) = f _ ai * f _ aj) :
    (⨁ i, A i) →ₐ[R] B :=
{ toSemiring (fun i => (f i).toAddMonoidHom) hone @hmul with
    toFun := toSemiring (fun i => (f i).toAddMonoidHom) hone @hmul
    commutes' := fun r => by
      change toModule R _ _ f (algebraMap R _ r) = _
      rw [Algebra.algebraMap_eq_smul_one, Algebra.algebraMap_eq_smul_one, map_smul, one_def,
        ← lof_eq_of R, toModule_lof, hone] }

/-- Two `AlgHom`s out of a direct sum are equal if they agree on the generators.

See note [partially-applied ext lemmas]. -/
```

-- snippet 19
```lean
-- Mathlib.Algebra.DirectSum.Basic.of_eq_same (L133-L135)
theorem of_eq_same (i : ι) (x : β i) : (of _ i x) i = x :=
DFinsupp.single_eq_same
```

-- snippet 20
```lean
-- Mathlib.Algebra.DirectSum.Algebra.algebraMap_apply (L100-L103)
theorem algebraMap_apply (r : R) :
    algebraMap R (⨁ i, A i) r = DirectSum.of A 0 (GAlgebra.toFun r) :=
rfl
```

-- snippet 21
```lean
-- Mathlib.Algebra.DirectSum.Algebra.gMulLHom (L141-L156)
def gMulLHom {i j} : A i →ₗ[R] A j →ₗ[R] A (i + j) where
  toFun a :=
{ toFun := fun b => GradedMonoid.GMul.mul a b
      map_smul' := fun r x => by
        injection (smul_comm r (GradedMonoid.mk _ a) (GradedMonoid.mk _ x)).symm
      map_add' := GNonUnitalNonAssocSemiring.mul_add _ }
  map_smul' r x := LinearMap.ext fun y => by
    injection smul_assoc r (GradedMonoid.mk _ x) (GradedMonoid.mk _ y)
  map_add' _ _ := LinearMap.ext fun _ => GNonUnitalNonAssocSemiring.add_mul _ _ _

end DirectSum

/-! ### Concrete instances -/

/-- A direct sum of copies of an `Algebra` inherits the algebra structure. -/
```

-- snippet 22
```lean
-- Mathlib.Algebra.DirectSum.Basic.support_of (L155-L158)
theorem support_of [∀ (i : ι) (x : β i), Decidable (x ≠ 0)] (i : ι) (x : β i) (h : x ≠ 0) :
    (of _ i x).support = {i} :=
DFinsupp.support_single_ne_zero h
```

-- snippet 23
```lean
-- Mathlib.Algebra.DirectSum.Basic.mk_apply_of_notMem (L146-L149)
theorem mk_apply_of_notMem {s : Finset ι} {f : ∀ i : (↑s : Set ι), β i.val} {n : ι} (hn : n ∉ s) :
    mk β s f n = 0 :=
DFinsupp.mk_of_notMem hn
```

-- snippet 24
```lean
-- Mathlib.Algebra.DirectSum.Algebra.algHom_ext' (L130-L133)
theorem algHom_ext' ⦃f g : (⨁ i, A i) →ₐ[R] B⦄
    (h : ∀ i, f.toLinearMap.comp (lof _ _ A i) = g.toLinearMap.comp (lof _ _ A i)) : f = g :=
AlgHom.toLinearMap_injective <| DirectSum.linearMap_ext _ h
```

-- snippet 25
```lean
-- Mathlib.Algebra.DirectSum.Basic.coeFnAddMonoidHom_apply (L74-L81)
lemma coeFnAddMonoidHom_apply [∀ i, AddCommMonoid (β i)] (v : ⨁ i, β i) :
    coeFnAddMonoidHom β v = v :=
rfl

section AddCommGroup

variable [∀ i, AddCommGroup (β i)]
```

-- snippet 26
```lean
-- Mathlib.Algebra.DirectSum.Basic.sub_apply (L88-L94)
theorem sub_apply (g₁ g₂ : ⨁ i, β i) (i : ι) : (g₁ - g₂) i = g₁ i - g₂ i :=
rfl

end AddCommGroup

variable [∀ i, AddCommMonoid (β i)]
```

-- snippet 27
```lean
-- Mathlib.Algebra.DirectSum.AddChar.directSum_injective (L32-L39)
lemma directSum_injective :
    Injective (directSum : (∀ i, AddChar (G i) R) → AddChar (⨁ i, G i) R) := by
refine toAddMonoidHomEquiv.symm.injective.comp <| DirectSum.toAddMonoid_injective.comp ?_
  rintro ψ χ h
  simpa [funext_iff] using h

end DirectSum
end AddChar
```

-- snippet 28
```lean
-- Mathlib.Algebra.DirectSum.Basic.of_apply (L139-L141)
lemma of_apply {i : ι} (j : ι) (x : β i) : of β i x j = if h : i = j then Eq.recOn h x else 0 :=
DFinsupp.single_apply
```

-- snippet 29
```lean
-- Mathlib.Algebra.DirectSum.Basic.mk (L121-L126)
def mk (s : Finset ι) : (∀ i : (↑s : Set ι), β i.1) →+ ⨁ i, β i where
  toFun := DFinsupp.mk s
map_add' _ _ := DFinsupp.mk_add
  map_zero' := DFinsupp.mk_zero

/-- `of i` is the natural inclusion map from `β i` to `⨁ i, β i`. -/
```

-- snippet 30
```lean
-- Mathlib.Algebra.DirectSum.Basic.mk_apply_of_mem (L142-L145)
theorem mk_apply_of_mem {s : Finset ι} {f : ∀ i : (↑s : Set ι), β i.val} {n : ι} (hn : n ∈ s) :
    mk β s f n = f ⟨n, hn⟩ :=
DFinsupp.mk_of_mem hn
```

-- snippet 31
```lean
-- Mathlib.Algebra.DirectSum.AddChar.directSum (L29-L31)
def directSum (ψ : ∀ i, AddChar (G i) R) : AddChar (⨁ i, G i) R :=
toAddMonoidHomEquiv.symm <| DirectSum.toAddMonoid fun i ↦ toAddMonoidHomEquiv (ψ i)
```

-- snippet 32
```lean
-- Mathlib.Algebra.DirectSum.Algebra.algebraMap_toAddMonoid_hom (L104-L114)
theorem algebraMap_toAddMonoid_hom :
    ↑(algebraMap R (⨁ i, A i)) = (DirectSum.of A 0).comp (GAlgebra.toFun : R →+ A 0) :=
rfl

/-- A family of `LinearMap`s preserving `DirectSum.GOne.one` and `DirectSum.GMul.mul`
describes an `AlgHom` on `⨁ i, A i`. This is a stronger version of `DirectSum.toSemiring`.

Of particular interest is the case when `A i` are bundled subobjects, `f` is the family of
coercions such as `Submodule.subtype (A i)`, and the `[GMonoid A]` structure originates from
`DirectSum.GMonoid.ofAddSubmodules`, in which case the proofs about `GOne` and `GMul`
can be discharged by `rfl`. -/
```

-- snippet 33
```lean
-- Mathlib.Algebra.DirectSum.Basic.zero_apply (L99-L103)
theorem zero_apply (i : ι) : (0 : ⨁ i, β i) i = 0 :=
rfl

variable {β}
```

-- snippet 34
```lean
-- Mathlib.Algebra.DirectSum.Algebra.algHom_ext (L134-L139)
theorem algHom_ext ⦃f g : (⨁ i, A i) →ₐ[R] B⦄ (h : ∀ i x, f (of A i x) = g (of A i x)) : f = g :=
algHom_ext' R A fun i => LinearMap.ext <| h i

/-- The piecewise multiplication from the `Mul` instance, as a bundled linear map.

This is the graded version of `LinearMap.mul`, and the linear version of `DirectSum.gMulHom` -/
```

-- snippet 35
```lean
-- Mathlib.Algebra.DirectSum.Basic.support_zero (L151-L153)
theorem support_zero [∀ (i : ι) (x : β i), Decidable (x ≠ 0)] : (0 : ⨁ i, β i).support = ∅ :=
DFinsupp.support_zero
```

-- snippet 36
```lean
-- Mathlib.Algebra.DirectSum.Basic.add_apply (L105-L107)
theorem add_apply (g₁ g₂ : ⨁ i, β i) (i : ι) : (g₁ + g₂) i = g₁ i + g₂ i :=
rfl
```

-- snippet 37
```lean
-- Mathlib.Algebra.DirectSum.Basic.of (L127-L131)
def of (i : ι) : β i →+ ⨁ i, β i :=
DFinsupp.singleAddHom β i

variable {β}
```

-- snippet 38
```lean
-- Mathlib.Algebra.DirectSum.Basic.sum_apply (L109-L120)
theorem sum_apply {α} (s : Finset α) (g : α → ⨁ i, β i) (i : ι) :
    (∑ a ∈ s, g a) i = ∑ a ∈ s, g a i :=
DFinsupp.finset_sum_apply s g i

section DecidableEq

variable [DecidableEq ι]

variable (β)

/-- `mk β s x` is the element of `⨁ i, β i` that is zero outside `s`
and has coefficient `x i` for `i` in `s`. -/
```

-- snippet 39
```lean
-- Mathlib.Algebra.DirectSum.Basic.DirectSum (L38-L59)
def DirectSum [∀ i, AddCommMonoid (β i)] : Type _ :=
Π₀ i, β i
deriving AddCommMonoid, Inhabited, DFunLike

set_option backward.inferInstanceAs.wrap.data false in
deriving instance CoeFun for DirectSum

/-- `⨁ i, f i` is notation for `DirectSum _ f` and equals the direct sum of `fun i ↦ f i`.
Taking the direct sum over multiple arguments is possible, e.g. `⨁ (i) (j), f i j`. -/
scoped[DirectSum] notation3 "⨁ "(...)", "r:(scoped f => DirectSum _ f) => r

-- Porting note: The below recreates some of the lean3 notation, not fully yet
-- section
-- open Batteries.ExtendedBinder
-- syntax (name := bigdirectsum) "⨁ " extBinders ", " term : term
-- macro_rules (kind := bigdirectsum)
--   | `(⨁ $_:ident, $y:ident → $z:ident) => `(DirectSum _ (fun $y ↦ $z))
--   | `(⨁ $x:ident, $p) => `(DirectSum _ (fun $x ↦ $p))
--   | `(⨁ $_:ident : $t:ident, $p) => `(DirectSum _ (fun $t ↦ $p))
--   | `(⨁ ($x:ident) ($y:ident), $p) => `(DirectSum _ (fun $x ↦ fun $y ↦ $p))
-- end
```

-- snippet 40
```lean
-- Mathlib.Algebra.DirectSum.Algebra.Algebra (L158-L165)
instance Algebra.directSumGAlgebra {R A : Type*} [AddMonoid ι] [CommSemiring R]
    [Semiring A] [Algebra R A] : DirectSum.GAlgebra R fun _ : ι => A where
  toFun := (algebraMap R A).toAddMonoidHom
map_one := (algebraMap R A).map_one
  map_mul a b := Sigma.ext (zero_add _).symm (heq_of_eq <| (algebraMap R A).map_mul a b)
  commutes := fun _ ⟨_, _⟩ =>
    Sigma.ext ((zero_add _).trans (add_zero _).symm) (heq_of_eq <| Algebra.commutes _ _)
  smul_def := fun _ ⟨_, _⟩ => Sigma.ext (zero_add _).symm (heq_of_eq <| Algebra.smul_def _ _)
```
[/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.RingTheory.Jacobson.Radical).

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

```lean
theorem jacobson_smul_lt_top [Nontrivial M] [IsCoatomic (Submodule R M)] (N : Submodule R M) :
    Ring.jacobson R • N < ⊤
```

## Retrieved context
-- snippet 1
```lean
-- Mathlib.RingTheory.Jacobson.Radical.jacobson (L43-L47)
def jacobson : Submodule R M :=
sInf { m : Submodule R M | IsCoatom m }

variable {R R₂ M M₂}
```

-- snippet 2
```lean
-- Mathlib.RingTheory.Jacobson.Radical.le_comap_jacobson (L48-L54)
theorem le_comap_jacobson : jacobson R M ≤ comap f (jacobson R₂ M₂) := by
conv_rhs => rw [jacobson, sInf_eq_iInf', comap_iInf]
  refine le_iInf_iff.mpr fun S m hm ↦ ?_
  obtain h | h := isCoatom_comap_or_eq_top f S.2
  · exact mem_sInf.mp hm _ h
  · simpa only [h] using mem_top
```

-- snippet 3
```lean
-- Mathlib.RingTheory.Jacobson.Radical.map_jacobson_le (L55-L57)
theorem map_jacobson_le : map f (jacobson R M) ≤ jacobson R₂ M₂ :=
map_le_iff_le_comap.mpr (le_comap_jacobson f)
```

-- snippet 4
```lean
-- Mathlib.RingTheory.Jacobson.Radical.jacobson_eq_bot_of_injective (L58-L64)
theorem jacobson_eq_bot_of_injective (inj : Function.Injective f) (h : jacobson R₂ M₂ = ⊥) :
    jacobson R M = ⊥ :=
le_bot_iff.mp <| (le_comap_jacobson f).trans <| by
    simp_rw [h, comap_bot, (LinearMap.ker_eq_bot.mpr inj).le]

variable {f}
```

-- snippet 5
```lean
-- Mathlib.RingTheory.Jacobson.Radical.map_jacobson_of_ker_le (L65-L72)
theorem map_jacobson_of_ker_le (surj : Function.Surjective f)
    (le : LinearMap.ker f ≤ jacobson R M) :
    map f (jacobson R M) = jacobson R₂ M₂ :=
le_antisymm (map_jacobson_le f) <| by
    rw [jacobson, sInf_eq_iInf'] at le
    conv_rhs => rw [jacobson, sInf_eq_iInf', map_iInf_of_ker_le surj le]
    exact le_iInf fun m ↦ sInf_le (isCoatom_map_of_ker_le surj (le_iInf_iff.mp le m) m.2)
```

-- snippet 6
```lean
-- Mathlib.RingTheory.Jacobson.Radical.comap_jacobson_of_ker_le (L73-L77)
theorem comap_jacobson_of_ker_le (surj : Function.Surjective f)
    (le : LinearMap.ker f ≤ jacobson R M) :
    comap f (jacobson R₂ M₂) = jacobson R M := by
rw [← map_jacobson_of_ker_le surj le, comap_map_eq_self le]
```

-- snippet 7
```lean
-- Mathlib.RingTheory.Jacobson.Radical.map_jacobson_of_bijective (L78-L81)
theorem map_jacobson_of_bijective (hf : Function.Bijective f) :
    map f (jacobson R M) = jacobson R₂ M₂ :=
map_jacobson_of_ker_le hf.2 <| by simp_rw [LinearMap.ker_eq_bot.mpr hf.1, bot_le]
```

-- snippet 8
```lean
-- Mathlib.RingTheory.Jacobson.Radical.comap_jacobson_of_bijective (L82-L85)
theorem comap_jacobson_of_bijective (hf : Function.Bijective f) :
    comap f (jacobson R₂ M₂) = jacobson R M :=
comap_jacobson_of_ker_le hf.2 <| by simp_rw [LinearMap.ker_eq_bot.mpr hf.1, bot_le]
```

-- snippet 9
```lean
-- Mathlib.RingTheory.Jacobson.Radical.jacobson_quotient_of_le (L86-L89)
theorem jacobson_quotient_of_le {N : Submodule R M} (le : N ≤ jacobson R M) :
    jacobson R (M ⧸ N) = map N.mkQ (jacobson R M) :=
(map_jacobson_of_ker_le N.mkQ_surjective <| by rwa [ker_mkQ]).symm
```

-- snippet 10
```lean
-- Mathlib.RingTheory.Jacobson.Radical.jacobson_le_of_eq_bot (L90-L95)
theorem jacobson_le_of_eq_bot {N : Submodule R M} (h : jacobson R (M ⧸ N) = ⊥) :
    jacobson R M ≤ N := by
simp_rw [← N.ker_mkQ, ← comap_bot, ← h, le_comap_jacobson]

variable (R M)
```

-- snippet 11
```lean
-- Mathlib.RingTheory.Jacobson.Radical.jacobson_quotient_jacobson (L97-L99)
theorem jacobson_quotient_jacobson : jacobson R (M ⧸ jacobson R M) = ⊥ := by
rw [jacobson_quotient_of_le le_rfl, mkQ_map_self]
```

-- snippet 12
```lean
-- Mathlib.RingTheory.Jacobson.Radical.jacobson_lt_top (L100-L103)
theorem jacobson_lt_top [Nontrivial M] [IsCoatomic (Submodule R M)] : jacobson R M < ⊤ := by
obtain ⟨m, hm, -⟩ := (eq_top_or_exists_le_coatom (⊥ : Submodule R M)).resolve_left bot_ne_top
  exact (sInf_le <| Set.mem_setOf.mpr hm).trans_lt hm.1.lt_top
```

-- snippet 13
```lean
-- Mathlib.RingTheory.Jacobson.Radical.jacobson_pi_le (L108-L114)
theorem jacobson_pi_le : jacobson R (Π i, M i) ≤ Submodule.pi Set.univ (jacobson R <| M ·) := by
simp_rw [← iInf_comap_proj, jacobson, sInf_eq_iInf', comap_iInf, le_iInf_iff]
  intro i m
  exact iInf_le_of_le ⟨_, (isCoatom_comap_iff <| LinearMap.proj_surjective i).mpr m.2⟩ le_rfl

/-- A product of modules with trivial Jacobson radical (e.g. simple modules) also has trivial
Jacobson radical. -/
```

-- snippet 14
```lean
-- Mathlib.RingTheory.Jacobson.Radical.jacobson_pi_eq_bot (L115-L119)
theorem jacobson_pi_eq_bot (h : ∀ i, jacobson R (M i) = ⊥) : jacobson R (Π i, M i) = ⊥ :=
le_bot_iff.mp <| (jacobson_pi_le R M).trans <| by simp_rw [h, pi_univ_bot, le_rfl]

end Module
```

-- snippet 15
```lean
-- Mathlib.RingTheory.Jacobson.Radical.jacobson (L129-L130)
abbrev jacobson : Ideal R := Module.jacobson R R
```

-- snippet 16
```lean
-- Mathlib.RingTheory.Jacobson.Ideal.jacobson (L65-L67)
def jacobson (I : Ideal R) : Ideal R :=
sInf { J : Ideal R | I ≤ J ∧ IsMaximal J }
```

-- snippet 17
```lean
-- Mathlib.RingTheory.Jacobson.Ideal.map_jacobson_of_bijective (L196-L200)
theorem map_jacobson_of_bijective {f : R →+* S} (hf : Function.Bijective f) :
    map f I.jacobson = (map f I).jacobson :=
map_jacobson_of_surjective hf.right
    (le_trans (le_of_eq ((RingHom.injective_iff_ker_eq_bot f).1 hf.left)) bot_le)
```

-- snippet 18
```lean
-- Mathlib.RingTheory.Jacobson.Ideal.jacobson_eq_top_iff (L82-L89)
theorem jacobson_eq_top_iff : jacobson I = ⊤ ↔ I = ⊤ :=
⟨fun H =>
    by_contradiction fun hi => let ⟨M, hm, him⟩ := exists_le_maximal I hi
      lt_top_iff_ne_top.1
        (lt_of_le_of_lt (show jacobson I ≤ M from sInf_le ⟨him, hm⟩) <|
          lt_top_iff_ne_top.2 hm.ne_top) H,
    fun H => eq_top_iff.2 <| le_sInf fun _ ⟨hij, _⟩ => H ▸ hij⟩
```

-- snippet 19
```lean
-- Mathlib.RingTheory.Jacobson.Ideal.jacobson_idem (L71-L73)
theorem jacobson_idem : jacobson (jacobson I) = jacobson I :=
le_antisymm (sInf_le_sInf fun _ hJ => ⟨sInf_le hJ, hJ.2⟩) le_jacobson
```

-- snippet 20
```lean
-- Mathlib.RingTheory.Jacobson.Ideal.jacobson_eq_bot (L90-L91)
theorem jacobson_eq_bot : jacobson I = ⊥ → I = ⊥ := fun h => eq_bot_iff.mpr (h ▸ le_jacobson)
```

-- snippet 21
```lean
-- Mathlib.RingTheory.Jacobson.Ideal.radical_le_jacobson (L273-L275)
theorem radical_le_jacobson : radical I ≤ jacobson I :=
le_sInf fun _ hJ => (radical_eq_sInf I).symm ▸ sInf_le ⟨hJ.left, IsMaximal.isPrime hJ.right⟩
```

-- snippet 22
```lean
-- Mathlib.RingTheory.Jacobson.Ideal.map_jacobson_of_surjective (L177-L195)
theorem map_jacobson_of_surjective {f : R →+* S} (hf : Function.Surjective f) :
    RingHom.ker f ≤ I → map f I.jacobson = (map f I).jacobson := by
intro h
  unfold Ideal.jacobson
  -- Porting note (https://github.com/leanprover-community/mathlib4/issues/11036): dot notation for `RingHom.ker` does not work
  have : ∀ J ∈ { J : Ideal R | I ≤ J ∧ J.IsMaximal }, RingHom.ker f ≤ J :=
    fun J hJ => le_trans h hJ.left
  refine Trans.trans (map_sInf hf this) (le_antisymm ?_ ?_)
  · refine
      sInf_le_sInf fun J hJ =>
        ⟨comap f J, ⟨⟨le_comap_of_map_le hJ.1, ?_⟩, map_comap_of_surjective f hf J⟩⟩
    haveI : J.IsMaximal := hJ.right
    exact comap_isMaximal_of_surjective f hf
  · refine sInf_le_sInf_of_subset_insert_top fun j hj => hj.recOn fun J hJ => ?_
    rw [← hJ.2]
    rcases map_eq_top_or_isMaximal_of_surjective f hf hJ.left.right with htop | hmax
    · exact htop.symm ▸ Set.mem_insert ⊤ _
    · exact Set.mem_insert_of_mem ⊤ ⟨map_mono hJ.1.1, hmax⟩
```

-- snippet 23
```lean
-- Mathlib.RingTheory.Jacobson.Ideal.exists_mul_add_sub_mem_of_mem_jacobson (L121-L127)
theorem exists_mul_add_sub_mem_of_mem_jacobson {I : Ideal R} (r : R) (h : r ∈ jacobson I) :
    ∃ s, s * (r + 1) - 1 ∈ I := by
obtain ⟨s, hs⟩ := mem_jacobson_iff.1 h 1
  use s
  rw [mul_add, mul_one]
  simpa using hs
```

-- snippet 24
```lean
-- Mathlib.RingTheory.Jacobson.Ideal.eq_jacobson_iff_sInf_maximal' (L146-L163)
theorem eq_jacobson_iff_sInf_maximal' :
    I.jacobson = I ↔ ∃ M : Set (Ideal R), (∀ J ∈ M, ∀ (K : Ideal R), J < K → K = ⊤) ∧ I = sInf M :=
eq_jacobson_iff_sInf_maximal.trans
    ⟨fun h =>
      let ⟨M, hM⟩ := h
      ⟨M,
        ⟨fun J hJ K hK =>
          Or.recOn (hM.1 J hJ) (fun h => h.1.2 K hK) fun h => eq_top_iff.2 (le_of_lt (h ▸ hK)),
          hM.2⟩⟩,
      fun h =>
      let ⟨M, hM⟩ := h
      ⟨M,
        ⟨fun J hJ =>
          Or.recOn (Classical.em (J = ⊤)) (fun h => Or.inr h) fun h => Or.inl ⟨⟨h, hM.1 J hJ⟩⟩,
          hM.2⟩⟩⟩

/-- An ideal `I` equals its Jacobson radical if and only if every element outside `I`
also lies outside of a maximal ideal containing `I`. -/
```

-- snippet 25
```lean
-- Mathlib.RingTheory.Jacobson.Ideal.isRadical_jacobson (L279-L281)
lemma isRadical_jacobson (I : Ideal R) : I.jacobson.IsRadical :=
isRadical_of_eq_jacobson jacobson_idem
```

-- snippet 26
```lean
-- Mathlib.RingTheory.Jacobson.Ideal.isUnit_of_sub_one_mem_jacobson_bot (L282-L287)
theorem isUnit_of_sub_one_mem_jacobson_bot (r : R) (h : r - 1 ∈ jacobson (⊥ : Ideal R)) :
    IsUnit r := by
obtain ⟨s, hs⟩ := exists_mul_sub_mem_of_sub_one_mem_jacobson r h
  rw [mem_bot, sub_eq_zero, mul_comm] at hs
  exact .of_mul_eq_one _ hs
```

-- snippet 27
```lean
-- Mathlib.RingTheory.Jacobson.Ideal.mem_jacobson_iff (L99-L120)
theorem mem_jacobson_iff {x : R} : x ∈ jacobson I ↔ ∀ y, ∃ z, z * y * x + z - 1 ∈ I :=
⟨fun hx y =>
    by_cases
      (fun hxy : I ⊔ span {y * x + 1} = ⊤ =>
        let ⟨p, hpi, q, hq, hpq⟩ := Submodule.mem_sup.1 ((eq_top_iff_one _).1 hxy)
        let ⟨r, hr⟩ := mem_span_singleton'.1 hq
        ⟨r, by
          rw [mul_assoc, ← mul_add_one, hr, ← hpq, ← neg_sub, add_sub_cancel_right]
          exact I.neg_mem hpi⟩)
      fun hxy : I ⊔ span {y * x + 1} ≠ ⊤ => let ⟨M, hm1, hm2⟩ := exists_le_maximal _ hxy
      suffices x ∉ M from (this <| mem_sInf.1 hx ⟨le_trans le_sup_left hm2, hm1⟩).elim
      fun hxm => hm1.1.1 <| (eq_top_iff_one _).2 <| add_sub_cancel_left (y * x) 1 ▸
        M.sub_mem (le_sup_right.trans hm2 <| subset_span rfl) (M.mul_mem_left _ hxm),
    fun hx => mem_sInf.2 fun M ⟨him, hm⟩ => by_contradiction fun hxm =>
      let ⟨y, i, hi, df⟩ := hm.exists_inv hxm
      let ⟨z, hz⟩ := hx (-y)
      hm.1.1 <| (eq_top_iff_one _).2 <| sub_sub_cancel (z * -y * x + z) 1 ▸
        M.sub_mem (by
          rw [mul_assoc, ← mul_add_one, neg_mul, ← sub_eq_iff_eq_add.mpr df.symm, neg_sub,
            sub_add_cancel]
          exact M.mul_mem_left _ hi) <| him hz⟩
```

-- snippet 28
```lean
-- Mathlib.RingTheory.Jacobson.Ideal.comap_jacobson_of_surjective (L205-L223)
theorem comap_jacobson_of_surjective {f : R →+* S} (hf : Function.Surjective f) {K : Ideal S} :
    comap f K.jacobson = (comap f K).jacobson := by
unfold Ideal.jacobson
  refine le_antisymm ?_ ?_
  · rw [← top_inf_eq (sInf _), ← sInf_insert, comap_sInf', sInf_eq_iInf]
    refine iInf_le_iInf_of_subset fun J hJ => ?_
    have : comap f (map f J) = J :=
      Trans.trans (comap_map_of_surjective f hf J)
        (le_antisymm (sup_le_iff.2 ⟨le_of_eq rfl, le_trans (comap_mono bot_le) hJ.left⟩)
          le_sup_left)
    rcases map_eq_top_or_isMaximal_of_surjective _ hf hJ.right with htop | hmax
    · exact ⟨⊤, Set.mem_insert ⊤ _, htop ▸ this⟩
    · exact ⟨map f J, Set.mem_insert_of_mem _ ⟨le_map_of_comap_le_of_surjective f hf hJ.1, hmax⟩,
        this⟩
  · simp_rw [comap_sInf, le_iInf_iff]
    intro J hJ
    haveI : J.IsMaximal := hJ.right
    exact sInf_le ⟨comap_mono hJ.left, comap_isMaximal_of_surjective _ hf⟩
```

-- snippet 29
```lean
-- Mathlib.RingTheory.Jacobson.Artinian.Module (L25-L34)
lemma Module.finite_of_isSemisimpleRing [IsJacobsonRing R] [IsSemisimpleRing A] :
    Module.Finite R A :=
have (I : MaximalSpectrum A) := finite_of_finite_type_of_isJacobsonRing R (A ⧸ I.asIdeal)
  .equiv ((IsArtinianRing.equivPi A).restrictScalars R).toLinearEquiv.symm

/-- If `A` is a finite type algebra over `R`, then `A` is an Artinian ring and `R` is Jacobson
implies `A` is finite over `R`. -/
/- If made an instance, causes timeouts synthesizing `FaithfulSMul R I.ResidueField` at
`Ideal.algebraMap_residueField_eq_zero` and `Ideal.ker_algebraMap_residueField` during
simpNF linting. -/
```

-- snippet 30
```lean
-- Mathlib.RingTheory.Jacobson.Ideal.jacobson_bot (L78-L80)
theorem jacobson_bot : jacobson (⊥ : Ideal R) = Ring.jacobson R := by
simp_rw [jacobson, Ring.jacobson, Module.jacobson, bot_le, true_and, isMaximal_def]
```

-- snippet 31
```lean
-- Mathlib.RingTheory.Jacobson.Ideal.jacobson_eq_self_of_isMaximal (L92-L94)
theorem jacobson_eq_self_of_isMaximal [H : IsMaximal I] : I.jacobson = I :=
le_antisymm (sInf_le ⟨le_of_eq rfl, H⟩) le_jacobson
```

-- snippet 32
```lean
-- Mathlib.RingTheory.Jacobson.Ideal.jacobson_mono (L225-L229)
theorem jacobson_mono {I J : Ideal R} : I ≤ J → I.jacobson ≤ J.jacobson := by
intro h x hx
  rw [jacobson, mem_sInf] at hx ⊢
  exact fun K ⟨hK, hK_max⟩ => hx ⟨Trans.trans h hK, hK_max⟩
```

-- snippet 33
```lean
-- Mathlib.RingTheory.Jacobson.Ideal.eq_jacobson_iff_sInf_maximal (L135-L145)
theorem eq_jacobson_iff_sInf_maximal :
    I.jacobson = I ↔ ∃ M : Set (Ideal R), (∀ J ∈ M, IsMaximal J ∨ J = ⊤) ∧ I = sInf M := by
use fun hI => ⟨{ J : Ideal R | I ≤ J ∧ J.IsMaximal }, ⟨fun _ hJ => Or.inl hJ.right, hI.symm⟩⟩
  rintro ⟨M, hM, hInf⟩
  refine le_antisymm (fun x hx => ?_) le_jacobson
  rw [hInf, mem_sInf]
  intro I hI
  rcases hM I hI with is_max | is_top
  · exact (mem_sInf.1 hx) ⟨le_sInf_iff.1 (le_of_eq hInf) I hI, is_max⟩
  · exact is_top.symm ▸ Submodule.mem_top
```

-- snippet 34
```lean
-- Mathlib.RingTheory.Jacobson.Ideal.le_jacobson (L68-L69)
theorem le_jacobson : I ≤ jacobson I := fun _ hx => mem_sInf.mpr fun _ hJ => hJ.left hx
```

-- snippet 35
```lean
-- Mathlib.RingTheory.Jacobson.Ideal.isRadical_of_eq_jacobson (L276-L278)
theorem isRadical_of_eq_jacobson (h : jacobson I = I) : I.IsRadical :=
radical_le_jacobson.trans h.le
```

-- snippet 36
```lean
-- Mathlib.RingTheory.Jacobson.Ideal.jacobson_top (L75-L77)
theorem jacobson_top : jacobson (⊤ : Ideal R) = ⊤ :=
eq_top_iff.2 le_jacobson
```

-- snippet 37
```lean
-- Mathlib.RingTheory.Jacobson.Ideal.comap_jacobson (L201-L204)
theorem comap_jacobson {f : R →+* S} {K : Ideal S} :
    comap f K.jacobson = sInf (comap f '' { J : Ideal S | K ≤ J ∧ J.IsMaximal }) :=
Trans.trans (comap_sInf' f _) sInf_eq_iInf.symm
```

-- snippet 38
```lean
-- Mathlib.RingTheory.Jacobson.Ideal.eq_jacobson_iff_notMem (L164-L176)
theorem eq_jacobson_iff_notMem :
    I.jacobson = I ↔ ∀ x ∉ I, ∃ M : Ideal R, (I ≤ M ∧ M.IsMaximal) ∧ x ∉ M := by
constructor
  · intro h x hx
    rw [← h, Ideal.jacobson, mem_sInf] at hx
    push Not at hx
    exact hx
  · refine fun h => le_antisymm (fun x hx => ?_) le_jacobson
    contrapose hx
    rw [Ideal.jacobson, mem_sInf]
    push Not
    exact h x hx
```

-- snippet 39
```lean
-- Mathlib.RingTheory.Jacobson.Ideal.exists_mul_sub_mem_of_sub_one_mem_jacobson (L128-L134)
theorem exists_mul_sub_mem_of_sub_one_mem_jacobson {I : Ideal R} (r : R) (h : r - 1 ∈ jacobson I) :
    ∃ s, s * r - 1 ∈ I := by
convert exists_mul_add_sub_mem_of_mem_jacobson _ h
  simp

/-- An ideal equals its Jacobson radical iff it is the intersection of a set of maximal ideals.
Allowing the set to include ⊤ is equivalent, and is included only to simplify some proofs. -/
```

-- snippet 40
```lean
-- Mathlib.RingTheory.Jacobson.Ideal.ringJacobson_le_jacobson (L230-L233)
theorem ringJacobson_le_jacobson {I : Ideal R} : Ring.jacobson R ≤ I.jacobson :=
jacobson_bot.symm.trans_le (jacobson_mono bot_le)

/-- The Jacobson radical of a two-sided ideal is two-sided. -/
```

<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.RingTheory.Jacobson.Radical).[/SYSTEM_PROMPT][MODEL_SETTINGS]{"reasoning_effort": "none"}[/MODEL_SETTINGS][INST]Prove the following theorem. The retrieved context below may help.

```lean
theorem jacobson_smul_lt_top [Nontrivial M] [IsCoatomic (Submodule R M)] (N : Submodule R M) :
    Ring.jacobson R • N < ⊤
```

## Retrieved context
-- snippet 1
```lean
-- Mathlib.RingTheory.Jacobson.Radical.jacobson (L43-L47)
def jacobson : Submodule R M :=
sInf { m : Submodule R M | IsCoatom m }

variable {R R₂ M M₂}
```

-- snippet 2
```lean
-- Mathlib.RingTheory.Jacobson.Radical.le_comap_jacobson (L48-L54)
theorem le_comap_jacobson : jacobson R M ≤ comap f (jacobson R₂ M₂) := by
conv_rhs => rw [jacobson, sInf_eq_iInf', comap_iInf]
  refine le_iInf_iff.mpr fun S m hm ↦ ?_
  obtain h | h := isCoatom_comap_or_eq_top f S.2
  · exact mem_sInf.mp hm _ h
  · simpa only [h] using mem_top
```

-- snippet 3
```lean
-- Mathlib.RingTheory.Jacobson.Radical.map_jacobson_le (L55-L57)
theorem map_jacobson_le : map f (jacobson R M) ≤ jacobson R₂ M₂ :=
map_le_iff_le_comap.mpr (le_comap_jacobson f)
```

-- snippet 4
```lean
-- Mathlib.RingTheory.Jacobson.Radical.jacobson_eq_bot_of_injective (L58-L64)
theorem jacobson_eq_bot_of_injective (inj : Function.Injective f) (h : jacobson R₂ M₂ = ⊥) :
    jacobson R M = ⊥ :=
le_bot_iff.mp <| (le_comap_jacobson f).trans <| by
    simp_rw [h, comap_bot, (LinearMap.ker_eq_bot.mpr inj).le]

variable {f}
```

-- snippet 5
```lean
-- Mathlib.RingTheory.Jacobson.Radical.map_jacobson_of_ker_le (L65-L72)
theorem map_jacobson_of_ker_le (surj : Function.Surjective f)
    (le : LinearMap.ker f ≤ jacobson R M) :
    map f (jacobson R M) = jacobson R₂ M₂ :=
le_antisymm (map_jacobson_le f) <| by
    rw [jacobson, sInf_eq_iInf'] at le
    conv_rhs => rw [jacobson, sInf_eq_iInf', map_iInf_of_ker_le surj le]
    exact le_iInf fun m ↦ sInf_le (isCoatom_map_of_ker_le surj (le_iInf_iff.mp le m) m.2)
```

-- snippet 6
```lean
-- Mathlib.RingTheory.Jacobson.Radical.comap_jacobson_of_ker_le (L73-L77)
theorem comap_jacobson_of_ker_le (surj : Function.Surjective f)
    (le : LinearMap.ker f ≤ jacobson R M) :
    comap f (jacobson R₂ M₂) = jacobson R M := by
rw [← map_jacobson_of_ker_le surj le, comap_map_eq_self le]
```

-- snippet 7
```lean
-- Mathlib.RingTheory.Jacobson.Radical.map_jacobson_of_bijective (L78-L81)
theorem map_jacobson_of_bijective (hf : Function.Bijective f) :
    map f (jacobson R M) = jacobson R₂ M₂ :=
map_jacobson_of_ker_le hf.2 <| by simp_rw [LinearMap.ker_eq_bot.mpr hf.1, bot_le]
```

-- snippet 8
```lean
-- Mathlib.RingTheory.Jacobson.Radical.comap_jacobson_of_bijective (L82-L85)
theorem comap_jacobson_of_bijective (hf : Function.Bijective f) :
    comap f (jacobson R₂ M₂) = jacobson R M :=
comap_jacobson_of_ker_le hf.2 <| by simp_rw [LinearMap.ker_eq_bot.mpr hf.1, bot_le]
```

-- snippet 9
```lean
-- Mathlib.RingTheory.Jacobson.Radical.jacobson_quotient_of_le (L86-L89)
theorem jacobson_quotient_of_le {N : Submodule R M} (le : N ≤ jacobson R M) :
    jacobson R (M ⧸ N) = map N.mkQ (jacobson R M) :=
(map_jacobson_of_ker_le N.mkQ_surjective <| by rwa [ker_mkQ]).symm
```

-- snippet 10
```lean
-- Mathlib.RingTheory.Jacobson.Radical.jacobson_le_of_eq_bot (L90-L95)
theorem jacobson_le_of_eq_bot {N : Submodule R M} (h : jacobson R (M ⧸ N) = ⊥) :
    jacobson R M ≤ N := by
simp_rw [← N.ker_mkQ, ← comap_bot, ← h, le_comap_jacobson]

variable (R M)
```

-- snippet 11
```lean
-- Mathlib.RingTheory.Jacobson.Radical.jacobson_quotient_jacobson (L97-L99)
theorem jacobson_quotient_jacobson : jacobson R (M ⧸ jacobson R M) = ⊥ := by
rw [jacobson_quotient_of_le le_rfl, mkQ_map_self]
```

-- snippet 12
```lean
-- Mathlib.RingTheory.Jacobson.Radical.jacobson_lt_top (L100-L103)
theorem jacobson_lt_top [Nontrivial M] [IsCoatomic (Submodule R M)] : jacobson R M < ⊤ := by
obtain ⟨m, hm, -⟩ := (eq_top_or_exists_le_coatom (⊥ : Submodule R M)).resolve_left bot_ne_top
  exact (sInf_le <| Set.mem_setOf.mpr hm).trans_lt hm.1.lt_top
```

-- snippet 13
```lean
-- Mathlib.RingTheory.Jacobson.Radical.jacobson_pi_le (L108-L114)
theorem jacobson_pi_le : jacobson R (Π i, M i) ≤ Submodule.pi Set.univ (jacobson R <| M ·) := by
simp_rw [← iInf_comap_proj, jacobson, sInf_eq_iInf', comap_iInf, le_iInf_iff]
  intro i m
  exact iInf_le_of_le ⟨_, (isCoatom_comap_iff <| LinearMap.proj_surjective i).mpr m.2⟩ le_rfl

/-- A product of modules with trivial Jacobson radical (e.g. simple modules) also has trivial
Jacobson radical. -/
```

-- snippet 14
```lean
-- Mathlib.RingTheory.Jacobson.Radical.jacobson_pi_eq_bot (L115-L119)
theorem jacobson_pi_eq_bot (h : ∀ i, jacobson R (M i) = ⊥) : jacobson R (Π i, M i) = ⊥ :=
le_bot_iff.mp <| (jacobson_pi_le R M).trans <| by simp_rw [h, pi_univ_bot, le_rfl]

end Module
```

-- snippet 15
```lean
-- Mathlib.RingTheory.Jacobson.Radical.jacobson (L129-L130)
abbrev jacobson : Ideal R := Module.jacobson R R
```

-- snippet 16
```lean
-- Mathlib.RingTheory.Jacobson.Ideal.jacobson (L65-L67)
def jacobson (I : Ideal R) : Ideal R :=
sInf { J : Ideal R | I ≤ J ∧ IsMaximal J }
```

-- snippet 17
```lean
-- Mathlib.RingTheory.Jacobson.Ideal.map_jacobson_of_bijective (L196-L200)
theorem map_jacobson_of_bijective {f : R →+* S} (hf : Function.Bijective f) :
    map f I.jacobson = (map f I).jacobson :=
map_jacobson_of_surjective hf.right
    (le_trans (le_of_eq ((RingHom.injective_iff_ker_eq_bot f).1 hf.left)) bot_le)
```

-- snippet 18
```lean
-- Mathlib.RingTheory.Jacobson.Ideal.jacobson_eq_top_iff (L82-L89)
theorem jacobson_eq_top_iff : jacobson I = ⊤ ↔ I = ⊤ :=
⟨fun H =>
    by_contradiction fun hi => let ⟨M, hm, him⟩ := exists_le_maximal I hi
      lt_top_iff_ne_top.1
        (lt_of_le_of_lt (show jacobson I ≤ M from sInf_le ⟨him, hm⟩) <|
          lt_top_iff_ne_top.2 hm.ne_top) H,
    fun H => eq_top_iff.2 <| le_sInf fun _ ⟨hij, _⟩ => H ▸ hij⟩
```

-- snippet 19
```lean
-- Mathlib.RingTheory.Jacobson.Ideal.jacobson_idem (L71-L73)
theorem jacobson_idem : jacobson (jacobson I) = jacobson I :=
le_antisymm (sInf_le_sInf fun _ hJ => ⟨sInf_le hJ, hJ.2⟩) le_jacobson
```

-- snippet 20
```lean
-- Mathlib.RingTheory.Jacobson.Ideal.jacobson_eq_bot (L90-L91)
theorem jacobson_eq_bot : jacobson I = ⊥ → I = ⊥ := fun h => eq_bot_iff.mpr (h ▸ le_jacobson)
```

-- snippet 21
```lean
-- Mathlib.RingTheory.Jacobson.Ideal.radical_le_jacobson (L273-L275)
theorem radical_le_jacobson : radical I ≤ jacobson I :=
le_sInf fun _ hJ => (radical_eq_sInf I).symm ▸ sInf_le ⟨hJ.left, IsMaximal.isPrime hJ.right⟩
```

-- snippet 22
```lean
-- Mathlib.RingTheory.Jacobson.Ideal.map_jacobson_of_surjective (L177-L195)
theorem map_jacobson_of_surjective {f : R →+* S} (hf : Function.Surjective f) :
    RingHom.ker f ≤ I → map f I.jacobson = (map f I).jacobson := by
intro h
  unfold Ideal.jacobson
  -- Porting note (https://github.com/leanprover-community/mathlib4/issues/11036): dot notation for `RingHom.ker` does not work
  have : ∀ J ∈ { J : Ideal R | I ≤ J ∧ J.IsMaximal }, RingHom.ker f ≤ J :=
    fun J hJ => le_trans h hJ.left
  refine Trans.trans (map_sInf hf this) (le_antisymm ?_ ?_)
  · refine
      sInf_le_sInf fun J hJ =>
        ⟨comap f J, ⟨⟨le_comap_of_map_le hJ.1, ?_⟩, map_comap_of_surjective f hf J⟩⟩
    haveI : J.IsMaximal := hJ.right
    exact comap_isMaximal_of_surjective f hf
  · refine sInf_le_sInf_of_subset_insert_top fun j hj => hj.recOn fun J hJ => ?_
    rw [← hJ.2]
    rcases map_eq_top_or_isMaximal_of_surjective f hf hJ.left.right with htop | hmax
    · exact htop.symm ▸ Set.mem_insert ⊤ _
    · exact Set.mem_insert_of_mem ⊤ ⟨map_mono hJ.1.1, hmax⟩
```

-- snippet 23
```lean
-- Mathlib.RingTheory.Jacobson.Ideal.exists_mul_add_sub_mem_of_mem_jacobson (L121-L127)
theorem exists_mul_add_sub_mem_of_mem_jacobson {I : Ideal R} (r : R) (h : r ∈ jacobson I) :
    ∃ s, s * (r + 1) - 1 ∈ I := by
obtain ⟨s, hs⟩ := mem_jacobson_iff.1 h 1
  use s
  rw [mul_add, mul_one]
  simpa using hs
```

-- snippet 24
```lean
-- Mathlib.RingTheory.Jacobson.Ideal.eq_jacobson_iff_sInf_maximal' (L146-L163)
theorem eq_jacobson_iff_sInf_maximal' :
    I.jacobson = I ↔ ∃ M : Set (Ideal R), (∀ J ∈ M, ∀ (K : Ideal R), J < K → K = ⊤) ∧ I = sInf M :=
eq_jacobson_iff_sInf_maximal.trans
    ⟨fun h =>
      let ⟨M, hM⟩ := h
      ⟨M,
        ⟨fun J hJ K hK =>
          Or.recOn (hM.1 J hJ) (fun h => h.1.2 K hK) fun h => eq_top_iff.2 (le_of_lt (h ▸ hK)),
          hM.2⟩⟩,
      fun h =>
      let ⟨M, hM⟩ := h
      ⟨M,
        ⟨fun J hJ =>
          Or.recOn (Classical.em (J = ⊤)) (fun h => Or.inr h) fun h => Or.inl ⟨⟨h, hM.1 J hJ⟩⟩,
          hM.2⟩⟩⟩

/-- An ideal `I` equals its Jacobson radical if and only if every element outside `I`
also lies outside of a maximal ideal containing `I`. -/
```

-- snippet 25
```lean
-- Mathlib.RingTheory.Jacobson.Ideal.isRadical_jacobson (L279-L281)
lemma isRadical_jacobson (I : Ideal R) : I.jacobson.IsRadical :=
isRadical_of_eq_jacobson jacobson_idem
```

-- snippet 26
```lean
-- Mathlib.RingTheory.Jacobson.Ideal.isUnit_of_sub_one_mem_jacobson_bot (L282-L287)
theorem isUnit_of_sub_one_mem_jacobson_bot (r : R) (h : r - 1 ∈ jacobson (⊥ : Ideal R)) :
    IsUnit r := by
obtain ⟨s, hs⟩ := exists_mul_sub_mem_of_sub_one_mem_jacobson r h
  rw [mem_bot, sub_eq_zero, mul_comm] at hs
  exact .of_mul_eq_one _ hs
```

-- snippet 27
```lean
-- Mathlib.RingTheory.Jacobson.Ideal.mem_jacobson_iff (L99-L120)
theorem mem_jacobson_iff {x : R} : x ∈ jacobson I ↔ ∀ y, ∃ z, z * y * x + z - 1 ∈ I :=
⟨fun hx y =>
    by_cases
      (fun hxy : I ⊔ span {y * x + 1} = ⊤ =>
        let ⟨p, hpi, q, hq, hpq⟩ := Submodule.mem_sup.1 ((eq_top_iff_one _).1 hxy)
        let ⟨r, hr⟩ := mem_span_singleton'.1 hq
        ⟨r, by
          rw [mul_assoc, ← mul_add_one, hr, ← hpq, ← neg_sub, add_sub_cancel_right]
          exact I.neg_mem hpi⟩)
      fun hxy : I ⊔ span {y * x + 1} ≠ ⊤ => let ⟨M, hm1, hm2⟩ := exists_le_maximal _ hxy
      suffices x ∉ M from (this <| mem_sInf.1 hx ⟨le_trans le_sup_left hm2, hm1⟩).elim
      fun hxm => hm1.1.1 <| (eq_top_iff_one _).2 <| add_sub_cancel_left (y * x) 1 ▸
        M.sub_mem (le_sup_right.trans hm2 <| subset_span rfl) (M.mul_mem_left _ hxm),
    fun hx => mem_sInf.2 fun M ⟨him, hm⟩ => by_contradiction fun hxm =>
      let ⟨y, i, hi, df⟩ := hm.exists_inv hxm
      let ⟨z, hz⟩ := hx (-y)
      hm.1.1 <| (eq_top_iff_one _).2 <| sub_sub_cancel (z * -y * x + z) 1 ▸
        M.sub_mem (by
          rw [mul_assoc, ← mul_add_one, neg_mul, ← sub_eq_iff_eq_add.mpr df.symm, neg_sub,
            sub_add_cancel]
          exact M.mul_mem_left _ hi) <| him hz⟩
```

-- snippet 28
```lean
-- Mathlib.RingTheory.Jacobson.Ideal.comap_jacobson_of_surjective (L205-L223)
theorem comap_jacobson_of_surjective {f : R →+* S} (hf : Function.Surjective f) {K : Ideal S} :
    comap f K.jacobson = (comap f K).jacobson := by
unfold Ideal.jacobson
  refine le_antisymm ?_ ?_
  · rw [← top_inf_eq (sInf _), ← sInf_insert, comap_sInf', sInf_eq_iInf]
    refine iInf_le_iInf_of_subset fun J hJ => ?_
    have : comap f (map f J) = J :=
      Trans.trans (comap_map_of_surjective f hf J)
        (le_antisymm (sup_le_iff.2 ⟨le_of_eq rfl, le_trans (comap_mono bot_le) hJ.left⟩)
          le_sup_left)
    rcases map_eq_top_or_isMaximal_of_surjective _ hf hJ.right with htop | hmax
    · exact ⟨⊤, Set.mem_insert ⊤ _, htop ▸ this⟩
    · exact ⟨map f J, Set.mem_insert_of_mem _ ⟨le_map_of_comap_le_of_surjective f hf hJ.1, hmax⟩,
        this⟩
  · simp_rw [comap_sInf, le_iInf_iff]
    intro J hJ
    haveI : J.IsMaximal := hJ.right
    exact sInf_le ⟨comap_mono hJ.left, comap_isMaximal_of_surjective _ hf⟩
```

-- snippet 29
```lean
-- Mathlib.RingTheory.Jacobson.Artinian.Module (L25-L34)
lemma Module.finite_of_isSemisimpleRing [IsJacobsonRing R] [IsSemisimpleRing A] :
    Module.Finite R A :=
have (I : MaximalSpectrum A) := finite_of_finite_type_of_isJacobsonRing R (A ⧸ I.asIdeal)
  .equiv ((IsArtinianRing.equivPi A).restrictScalars R).toLinearEquiv.symm

/-- If `A` is a finite type algebra over `R`, then `A` is an Artinian ring and `R` is Jacobson
implies `A` is finite over `R`. -/
/- If made an instance, causes timeouts synthesizing `FaithfulSMul R I.ResidueField` at
`Ideal.algebraMap_residueField_eq_zero` and `Ideal.ker_algebraMap_residueField` during
simpNF linting. -/
```

-- snippet 30
```lean
-- Mathlib.RingTheory.Jacobson.Ideal.jacobson_bot (L78-L80)
theorem jacobson_bot : jacobson (⊥ : Ideal R) = Ring.jacobson R := by
simp_rw [jacobson, Ring.jacobson, Module.jacobson, bot_le, true_and, isMaximal_def]
```

-- snippet 31
```lean
-- Mathlib.RingTheory.Jacobson.Ideal.jacobson_eq_self_of_isMaximal (L92-L94)
theorem jacobson_eq_self_of_isMaximal [H : IsMaximal I] : I.jacobson = I :=
le_antisymm (sInf_le ⟨le_of_eq rfl, H⟩) le_jacobson
```

-- snippet 32
```lean
-- Mathlib.RingTheory.Jacobson.Ideal.jacobson_mono (L225-L229)
theorem jacobson_mono {I J : Ideal R} : I ≤ J → I.jacobson ≤ J.jacobson := by
intro h x hx
  rw [jacobson, mem_sInf] at hx ⊢
  exact fun K ⟨hK, hK_max⟩ => hx ⟨Trans.trans h hK, hK_max⟩
```

-- snippet 33
```lean
-- Mathlib.RingTheory.Jacobson.Ideal.eq_jacobson_iff_sInf_maximal (L135-L145)
theorem eq_jacobson_iff_sInf_maximal :
    I.jacobson = I ↔ ∃ M : Set (Ideal R), (∀ J ∈ M, IsMaximal J ∨ J = ⊤) ∧ I = sInf M := by
use fun hI => ⟨{ J : Ideal R | I ≤ J ∧ J.IsMaximal }, ⟨fun _ hJ => Or.inl hJ.right, hI.symm⟩⟩
  rintro ⟨M, hM, hInf⟩
  refine le_antisymm (fun x hx => ?_) le_jacobson
  rw [hInf, mem_sInf]
  intro I hI
  rcases hM I hI with is_max | is_top
  · exact (mem_sInf.1 hx) ⟨le_sInf_iff.1 (le_of_eq hInf) I hI, is_max⟩
  · exact is_top.symm ▸ Submodule.mem_top
```

-- snippet 34
```lean
-- Mathlib.RingTheory.Jacobson.Ideal.le_jacobson (L68-L69)
theorem le_jacobson : I ≤ jacobson I := fun _ hx => mem_sInf.mpr fun _ hJ => hJ.left hx
```

-- snippet 35
```lean
-- Mathlib.RingTheory.Jacobson.Ideal.isRadical_of_eq_jacobson (L276-L278)
theorem isRadical_of_eq_jacobson (h : jacobson I = I) : I.IsRadical :=
radical_le_jacobson.trans h.le
```

-- snippet 36
```lean
-- Mathlib.RingTheory.Jacobson.Ideal.jacobson_top (L75-L77)
theorem jacobson_top : jacobson (⊤ : Ideal R) = ⊤ :=
eq_top_iff.2 le_jacobson
```

-- snippet 37
```lean
-- Mathlib.RingTheory.Jacobson.Ideal.comap_jacobson (L201-L204)
theorem comap_jacobson {f : R →+* S} {K : Ideal S} :
    comap f K.jacobson = sInf (comap f '' { J : Ideal S | K ≤ J ∧ J.IsMaximal }) :=
Trans.trans (comap_sInf' f _) sInf_eq_iInf.symm
```

-- snippet 38
```lean
-- Mathlib.RingTheory.Jacobson.Ideal.eq_jacobson_iff_notMem (L164-L176)
theorem eq_jacobson_iff_notMem :
    I.jacobson = I ↔ ∀ x ∉ I, ∃ M : Ideal R, (I ≤ M ∧ M.IsMaximal) ∧ x ∉ M := by
constructor
  · intro h x hx
    rw [← h, Ideal.jacobson, mem_sInf] at hx
    push Not at hx
    exact hx
  · refine fun h => le_antisymm (fun x hx => ?_) le_jacobson
    contrapose hx
    rw [Ideal.jacobson, mem_sInf]
    push Not
    exact h x hx
```

-- snippet 39
```lean
-- Mathlib.RingTheory.Jacobson.Ideal.exists_mul_sub_mem_of_sub_one_mem_jacobson (L128-L134)
theorem exists_mul_sub_mem_of_sub_one_mem_jacobson {I : Ideal R} (r : R) (h : r - 1 ∈ jacobson I) :
    ∃ s, s * r - 1 ∈ I := by
convert exists_mul_add_sub_mem_of_mem_jacobson _ h
  simp

/-- An ideal equals its Jacobson radical iff it is the intersection of a set of maximal ideals.
Allowing the set to include ⊤ is equivalent, and is included only to simplify some proofs. -/
```

-- snippet 40
```lean
-- Mathlib.RingTheory.Jacobson.Ideal.ringJacobson_le_jacobson (L230-L233)
theorem ringJacobson_le_jacobson {I : Ideal R} : Ring.jacobson R ≤ I.jacobson :=
jacobson_bot.symm.trans_le (jacobson_mono bot_le)

/-- The Jacobson radical of a two-sided ideal is two-sided. -/
```
[/INST]