l3lab/ntp-mathlib huggingface dataset:
/-- Normalization as an equivalence of categories. -/
def normalizeEquiv (a b : B) : Hom a b ≌ Discrete (Path.{v + 1} a b) :=
  Equivalence.mk ((normalize _).mapFunctor a b) (inclusionPath a b) (normalizeUnitIso a b)
    (Discrete.natIso fun f => eqToIso (by
      induction' f with f
      induction' f with _ _ _ _ ih
      -- Porting note: `tidy` closes the goal in mathlib3 but `aesop` doesn't here.
      · rfl
      · ext1
        injection ih with ih
        

Proof state:
case mk.cons.as
B : Type u
inst✝ : Quiver B
a b b✝ c✝ : B
a✝¹ : Path a b✝
a✝ : b✝ ⟶ c✝
ih : normalizeAux nil ((inclusionPath a b✝).obj { as := a✝¹ }) = a✝¹
⊢ ((inclusionPath a c✝ ⋙ Pseudofunctor.mapFunctor (normalize B) a c✝).obj { as := cons a✝¹ a✝ }).as =
    ((𝟭 (Discrete (Path a c✝))).obj { as := cons a✝¹ a✝ }).as

Next tactic:
conv =>
          rhs
          rw [← ih]
/-- Normalization as an equivalence of categories. -/
def normalizeEquiv (a b : B) : Hom a b ≌ Discrete (Path.{v + 1} a b) :=
  Equivalence.mk ((normalize _).mapFunctor a b) (inclusionPath a b) (normalizeUnitIso a b)
    (Discrete.natIso fun f => eqToIso (by
      induction' f with f
      induction' f with _ _ _ _ ih
      -- Porting note: `tidy` closes the goal in mathlib3 but `aesop` doesn't here.
      · rfl
      · ext1
        injection ih with ih
        conv =>
          

Proof state:
B : Type u
inst✝ : Quiver B
a b b✝ c✝ : B
a✝¹ : Path a b✝
a✝ : b✝ ⟶ c✝
ih : normalizeAux nil ((inclusionPath a b✝).obj { as := a✝¹ }) = a✝¹
| ((inclusionPath a c✝ ⋙ Pseudofunctor.mapFunctor (normalize B) a c✝).obj { as := cons a✝¹ a✝ }).as =
    ((𝟭 (Discrete (Path a c✝))).obj { as := cons a✝¹ a✝ }).as

Next tactic:
rhs
          rw [← ih]
/-- Normalization as an equivalence of categories. -/
def normalizeEquiv (a b : B) : Hom a b ≌ Discrete (Path.{v + 1} a b) :=
  Equivalence.mk ((normalize _).mapFunctor a b) (inclusionPath a b) (normalizeUnitIso a b)
    (Discrete.natIso fun f => eqToIso (by
      induction' f with f
      induction' f with _ _ _ _ ih
      -- Porting note: `tidy` closes the goal in mathlib3 but `aesop` doesn't here.
      · rfl
      · ext1
        injection ih with ih
        conv =>
          

Proof state:
B : Type u
inst✝ : Quiver B
a b b✝ c✝ : B
a✝¹ : Path a b✝
a✝ : b✝ ⟶ c✝
ih : normalizeAux nil ((inclusionPath a b✝).obj { as := a✝¹ }) = a✝¹
| ((inclusionPath a c✝ ⋙ Pseudofunctor.mapFunctor (normalize B) a c✝).obj { as := cons a✝¹ a✝ }).as =
    ((𝟭 (Discrete (Path a c✝))).obj { as := cons a✝¹ a✝ }).as

Next tactic:
rhs
/-- Normalization as an equivalence of categories. -/
def normalizeEquiv (a b : B) : Hom a b ≌ Discrete (Path.{v + 1} a b) :=
  Equivalence.mk ((normalize _).mapFunctor a b) (inclusionPath a b) (normalizeUnitIso a b)
    (Discrete.natIso fun f => eqToIso (by
      induction' f with f
      induction' f with _ _ _ _ ih
      -- Porting note: `tidy` closes the goal in mathlib3 but `aesop` doesn't here.
      · rfl
      · ext1
        injection ih with ih
        conv =>
          rhs
          

Proof state:
B : Type u
inst✝ : Quiver B
a b b✝ c✝ : B
a✝¹ : Path a b✝
a✝ : b✝ ⟶ c✝
ih : normalizeAux nil ((inclusionPath a b✝).obj { as := a✝¹ }) = a✝¹
| ((𝟭 (Discrete (Path a c✝))).obj { as := cons a✝¹ a✝ }).as

Next tactic:
rw [← ih]
theorem isNoetherian_submodule {N : Submodule R M} :
    IsNoetherian R N ↔ ∀ s : Submodule R M, s ≤ N → s.FG := by
  

Proof state:
R : Type u_1
M : Type u_2
P : Type u_3
inst✝⁴ : Semiring R
inst✝³ : AddCommMonoid M
inst✝² : AddCommMonoid P
inst✝¹ : Module R M
inst✝ : Module R P
N : Submodule R M
⊢ IsNoetherian R ↥N ↔ ∀ s ≤ N, Submodule.FG s

Next tactic:
refine ⟨fun ⟨hn⟩ => fun s hs =>
    have : s ≤ LinearMap.range N.subtype := N.range_subtype.symm ▸ hs
    Submodule.map_comap_eq_self this ▸ (hn _).map _,
    fun h => ⟨fun s => ?_⟩⟩
theorem isNoetherian_submodule {N : Submodule R M} :
    IsNoetherian R N ↔ ∀ s : Submodule R M, s ≤ N → s.FG := by
  refine ⟨fun ⟨hn⟩ => fun s hs =>
    have : s ≤ LinearMap.range N.subtype := N.range_subtype.symm ▸ hs
    Submodule.map_comap_eq_self this ▸ (hn _).map _,
    fun h => ⟨fun s => ?_⟩⟩
  

Proof state:
R : Type u_1
M : Type u_2
P : Type u_3
inst✝⁴ : Semiring R
inst✝³ : AddCommMonoid M
inst✝² : AddCommMonoid P
inst✝¹ : Module R M
inst✝ : Module R P
N : Submodule R M
h : ∀ s ≤ N, Submodule.FG s
s : Submodule R ↥N
⊢ Submodule.FG s

Next tactic:
have f := (Submodule.equivMapOfInjective N.subtype Subtype.val_injective s).symm
theorem isNoetherian_submodule {N : Submodule R M} :
    IsNoetherian R N ↔ ∀ s : Submodule R M, s ≤ N → s.FG := by
  refine ⟨fun ⟨hn⟩ => fun s hs =>
    have : s ≤ LinearMap.range N.subtype := N.range_subtype.symm ▸ hs
    Submodule.map_comap_eq_self this ▸ (hn _).map _,
    fun h => ⟨fun s => ?_⟩⟩
  have f := (Submodule.equivMapOfInjective N.subtype Subtype.val_injective s).symm
  

Proof state:
R : Type u_1
M : Type u_2
P : Type u_3
inst✝⁴ : Semiring R
inst✝³ : AddCommMonoid M
inst✝² : AddCommMonoid P
inst✝¹ : Module R M
inst✝ : Module R P
N : Submodule R M
h : ∀ s ≤ N, Submodule.FG s
s : Submodule R ↥N
f : ↥(Submodule.map (Submodule.subtype N) s) ≃ₗ[R] ↥s
⊢ Submodule.FG s

Next tactic:
have h₁ := h (s.map N.subtype) (Submodule.map_subtype_le N s)
theorem isNoetherian_submodule {N : Submodule R M} :
    IsNoetherian R N ↔ ∀ s : Submodule R M, s ≤ N → s.FG := by
  refine ⟨fun ⟨hn⟩ => fun s hs =>
    have : s ≤ LinearMap.range N.subtype := N.range_subtype.symm ▸ hs
    Submodule.map_comap_eq_self this ▸ (hn _).map _,
    fun h => ⟨fun s => ?_⟩⟩
  have f := (Submodule.equivMapOfInjective N.subtype Subtype.val_injective s).symm
  have h₁ := h (s.map N.subtype) (Submodule.map_subtype_le N s)
  

Proof state:
R : Type u_1
M : Type u_2
P : Type u_3
inst✝⁴ : Semiring R
inst✝³ : AddCommMonoid M
inst✝² : AddCommMonoid P
inst✝¹ : Module R M
inst✝ : Module R P
N : Submodule R M
h : ∀ s ≤ N, Submodule.FG s
s : Submodule R ↥N
f : ↥(Submodule.map (Submodule.subtype N) s) ≃ₗ[R] ↥s
h₁ : Submodule.FG (Submodule.map (Submodule.subtype N) s)
⊢ Submodule.FG s

Next tactic:
have h₂ : (⊤ : Submodule R (s.map N.subtype)).map f = ⊤ := by simp
theorem isNoetherian_submodule {N : Submodule R M} :
    IsNoetherian R N ↔ ∀ s : Submodule R M, s ≤ N → s.FG := by
  refine ⟨fun ⟨hn⟩ => fun s hs =>
    have : s ≤ LinearMap.range N.subtype := N.range_subtype.symm ▸ hs
    Submodule.map_comap_eq_self this ▸ (hn _).map _,
    fun h => ⟨fun s => ?_⟩⟩
  have f := (Submodule.equivMapOfInjective N.subtype Subtype.val_injective s).symm
  have h₁ := h (s.map N.subtype) (Submodule.map_subtype_le N s)
  have h₂ : (⊤ : Submodule R (s.map N.subtype)).map f = ⊤ := by 

Proof state:
R : Type u_1
M : Type u_2
P : Type u_3
inst✝⁴ : Semiring R
inst✝³ : AddCommMonoid M
inst✝² : AddCommMonoid P
inst✝¹ : Module R M
inst✝ : Module R P
N : Submodule R M
h : ∀ s ≤ N, Submodule.FG s
s : Submodule R ↥N
f : ↥(Submodule.map (Submodule.subtype N) s) ≃ₗ[R] ↥s
h₁ : Submodule.FG (Submodule.map (Submodule.subtype N) s)
⊢ Submodule.map f ⊤ = ⊤

Next tactic:
simp
theorem isNoetherian_submodule {N : Submodule R M} :
    IsNoetherian R N ↔ ∀ s : Submodule R M, s ≤ N → s.FG := by
  refine ⟨fun ⟨hn⟩ => fun s hs =>
    have : s ≤ LinearMap.range N.subtype := N.range_subtype.symm ▸ hs
    Submodule.map_comap_eq_self this ▸ (hn _).map _,
    fun h => ⟨fun s => ?_⟩⟩
  have f := (Submodule.equivMapOfInjective N.subtype Subtype.val_injective s).symm
  have h₁ := h (s.map N.subtype) (Submodule.map_subtype_le N s)
  have h₂ : (⊤ : Submodule R (s.map N.subtype)).map f = ⊤ := by simp
  

Proof state:
R : Type u_1
M : Type u_2
P : Type u_3
inst✝⁴ : Semiring R
inst✝³ : AddCommMonoid M
inst✝² : AddCommMonoid P
inst✝¹ : Module R M
inst✝ : Module R P
N : Submodule R M
h : ∀ s ≤ N, Submodule.FG s
s : Submodule R ↥N
f : ↥(Submodule.map (Submodule.subtype N) s) ≃ₗ[R] ↥s
h₁ : Submodule.FG (Submodule.map (Submodule.subtype N) s)
h₂ : Submodule.map f ⊤ = ⊤
⊢ Submodule.FG s

Next tactic:
have h₃ := ((Submodule.fg_top _).2 h₁).map (↑f : _ →ₗ[R] s)
theorem isNoetherian_submodule {N : Submodule R M} :
    IsNoetherian R N ↔ ∀ s : Submodule R M, s ≤ N → s.FG := by
  refine ⟨fun ⟨hn⟩ => fun s hs =>
    have : s ≤ LinearMap.range N.subtype := N.range_subtype.symm ▸ hs
    Submodule.map_comap_eq_self this ▸ (hn _).map _,
    fun h => ⟨fun s => ?_⟩⟩
  have f := (Submodule.equivMapOfInjective N.subtype Subtype.val_injective s).symm
  have h₁ := h (s.map N.subtype) (Submodule.map_subtype_le N s)
  have h₂ : (⊤ : Submodule R (s.map N.subtype)).map f = ⊤ := by simp
  have h₃ := ((Submodule.fg_top _).2 h₁).map (↑f : _ →ₗ[R] s)
  

Proof state:
R : Type u_1
M : Type u_2
P : Type u_3
inst✝⁴ : Semiring R
inst✝³ : AddCommMonoid M
inst✝² : AddCommMonoid P
inst✝¹ : Module R M
inst✝ : Module R P
N : Submodule R M
h : ∀ s ≤ N, Submodule.FG s
s : Submodule R ↥N
f : ↥(Submodule.map (Submodule.subtype N) s) ≃ₗ[R] ↥s
h₁ : Submodule.FG (Submodule.map (Submodule.subtype N) s)
h₂ : Submodule.map f ⊤ = ⊤
h₃ : Submodule.FG (Submodule.map ↑f ⊤)
⊢ Submodule.FG s

Next tactic:
exact (Submodule.fg_top _).1 (h₂ ▸ h₃)
theorem isNoetherian_top_iff : IsNoetherian R (⊤ : Submodule R M) ↔ IsNoetherian R M := by
  

Proof state:
R : Type u_1
M : Type u_2
P : Type u_3
inst✝⁴ : Semiring R
inst✝³ : AddCommMonoid M
inst✝² : AddCommMonoid P
inst✝¹ : Module R M
inst✝ : Module R P
⊢ IsNoetherian R ↥⊤ ↔ IsNoetherian R M

Next tactic:
constructor
theorem isNoetherian_top_iff : IsNoetherian R (⊤ : Submodule R M) ↔ IsNoetherian R M := by
  constructor <;> 

Proof state:
case mp
R : Type u_1
M : Type u_2
P : Type u_3
inst✝⁴ : Semiring R
inst✝³ : AddCommMonoid M
inst✝² : AddCommMonoid P
inst✝¹ : Module R M
inst✝ : Module R P
⊢ IsNoetherian R ↥⊤ → IsNoetherian R M

Next tactic:
intro h
theorem isNoetherian_top_iff : IsNoetherian R (⊤ : Submodule R M) ↔ IsNoetherian R M := by
  constructor <;> 

Proof state:
case mpr
R : Type u_1
M : Type u_2
P : Type u_3
inst✝⁴ : Semiring R
inst✝³ : AddCommMonoid M
inst✝² : AddCommMonoid P
inst✝¹ : Module R M
inst✝ : Module R P
⊢ IsNoetherian R M → IsNoetherian R ↥⊤

Next tactic:
intro h
theorem isNoetherian_top_iff : IsNoetherian R (⊤ : Submodule R M) ↔ IsNoetherian R M := by
  constructor <;> intro h
  · 

Proof state:
case mp
R : Type u_1
M : Type u_2
P : Type u_3
inst✝⁴ : Semiring R
inst✝³ : AddCommMonoid M
inst✝² : AddCommMonoid P
inst✝¹ : Module R M
inst✝ : Module R P
h : IsNoetherian R ↥⊤
⊢ IsNoetherian R M

Next tactic:
exact isNoetherian_of_linearEquiv (LinearEquiv.ofTop (⊤ : Submodule R M) rfl)
theorem isNoetherian_top_iff : IsNoetherian R (⊤ : Submodule R M) ↔ IsNoetherian R M := by
  constructor <;> intro h
  · exact isNoetherian_of_linearEquiv (LinearEquiv.ofTop (⊤ : Submodule R M) rfl)
  · 

Proof state:
case mpr
R : Type u_1
M : Type u_2
P : Type u_3
inst✝⁴ : Semiring R
inst✝³ : AddCommMonoid M
inst✝² : AddCommMonoid P
inst✝¹ : Module R M
inst✝ : Module R P
h : IsNoetherian R M
⊢ IsNoetherian R ↥⊤

Next tactic:
exact isNoetherian_of_linearEquiv (LinearEquiv.ofTop (⊤ : Submodule R M) rfl).symm
instance isNoetherian_pi {R ι : Type*} {M : ι → Type*}
    [Ring R] [∀ i, AddCommGroup (M i)] [∀ i, Module R (M i)] [Finite ι]
    [∀ i, IsNoetherian R (M i)] : IsNoetherian R (∀ i, M i) := by
  

Proof state:
R✝ : Type u_1
M✝ : Type u_2
P : Type u_3
inst✝⁹ : Ring R✝
inst✝⁸ : AddCommGroup M✝
inst✝⁷ : AddCommGroup P
inst✝⁶ : Module R✝ M✝
inst✝⁵ : Module R✝ P
R : Type u_4
ι : Type u_5
M : ι → Type u_6
inst✝⁴ : Ring R
inst✝³ : (i : ι) → AddCommGroup (M i)
inst✝² : (i : ι) → Module R (M i)
inst✝¹ : Finite ι
inst✝ : ∀ (i : ι), IsNoetherian R (M i)
⊢ IsNoetherian R ((i : ι) → M i)

Next tactic:
cases nonempty_fintype ι
instance isNoetherian_pi {R ι : Type*} {M : ι → Type*}
    [Ring R] [∀ i, AddCommGroup (M i)] [∀ i, Module R (M i)] [Finite ι]
    [∀ i, IsNoetherian R (M i)] : IsNoetherian R (∀ i, M i) := by
  cases nonempty_fintype ι
  

Proof state:
case intro
R✝ : Type u_1
M✝ : Type u_2
P : Type u_3
inst✝⁹ : Ring R✝
inst✝⁸ : AddCommGroup M✝
inst✝⁷ : AddCommGroup P
inst✝⁶ : Module R✝ M✝
inst✝⁵ : Module R✝ P
R : Type u_4
ι : Type u_5
M : ι → Type u_6
inst✝⁴ : Ring R
inst✝³ : (i : ι) → AddCommGroup (M i)
inst✝² : (i : ι) → Module R (M i)
inst✝¹ : Finite ι
inst✝ : ∀ (i : ι), IsNoetherian R (M i)
val✝ : Fintype ι
⊢ IsNoetherian R ((i : ι) → M i)

Next tactic:
haveI := Classical.decEq ι
instance isNoetherian_pi {R ι : Type*} {M : ι → Type*}
    [Ring R] [∀ i, AddCommGroup (M i)] [∀ i, Module R (M i)] [Finite ι]
    [∀ i, IsNoetherian R (M i)] : IsNoetherian R (∀ i, M i) := by
  cases nonempty_fintype ι
  haveI := Classical.decEq ι
  

Proof state:
case intro
R✝ : Type u_1
M✝ : Type u_2
P : Type u_3
inst✝⁹ : Ring R✝
inst✝⁸ : AddCommGroup M✝
inst✝⁷ : AddCommGroup P
inst✝⁶ : Module R✝ M✝
inst✝⁵ : Module R✝ P
R : Type u_4
ι : Type u_5
M : ι → Type u_6
inst✝⁴ : Ring R
inst✝³ : (i : ι) → AddCommGroup (M i)
inst✝² : (i : ι) → Module R (M i)
inst✝¹ : Finite ι
inst✝ : ∀ (i : ι), IsNoetherian R (M i)
val✝ : Fintype ι
this : DecidableEq ι
⊢ IsNoetherian R ((i : ι) → M i)

Next tactic:
suffices on_finset : ∀ s : Finset ι, IsNoetherian R (∀ i : s, M i)
instance isNoetherian_pi {R ι : Type*} {M : ι → Type*}
    [Ring R] [∀ i, AddCommGroup (M i)] [∀ i, Module R (M i)] [Finite ι]
    [∀ i, IsNoetherian R (M i)] : IsNoetherian R (∀ i, M i) := by
  cases nonempty_fintype ι
  haveI := Classical.decEq ι
  suffices on_finset : ∀ s : Finset ι, IsNoetherian R (∀ i : s, M i)
  · 

Proof state:
case intro
R✝ : Type u_1
M✝ : Type u_2
P : Type u_3
inst✝⁹ : Ring R✝
inst✝⁸ : AddCommGroup M✝
inst✝⁷ : AddCommGroup P
inst✝⁶ : Module R✝ M✝
inst✝⁵ : Module R✝ P
R : Type u_4
ι : Type u_5
M : ι → Type u_6
inst✝⁴ : Ring R
inst✝³ : (i : ι) → AddCommGroup (M i)
inst✝² : (i : ι) → Module R (M i)
inst✝¹ : Finite ι
inst✝ : ∀ (i : ι), IsNoetherian R (M i)
val✝ : Fintype ι
this : DecidableEq ι
on_finset : ∀ (s : Finset ι), IsNoetherian R ((i : { x // x ∈ s }) → M ↑i)
⊢ IsNoetherian R ((i : ι) → M i)

Next tactic:
let coe_e := Equiv.subtypeUnivEquiv <| @Finset.mem_univ ι _
instance isNoetherian_pi {R ι : Type*} {M : ι → Type*}
    [Ring R] [∀ i, AddCommGroup (M i)] [∀ i, Module R (M i)] [Finite ι]
    [∀ i, IsNoetherian R (M i)] : IsNoetherian R (∀ i, M i) := by
  cases nonempty_fintype ι
  haveI := Classical.decEq ι
  suffices on_finset : ∀ s : Finset ι, IsNoetherian R (∀ i : s, M i)
  · let coe_e := Equiv.subtypeUnivEquiv <| @Finset.mem_univ ι _
    

Proof state:
case intro
R✝ : Type u_1
M✝ : Type u_2
P : Type u_3
inst✝⁹ : Ring R✝
inst✝⁸ : AddCommGroup M✝
inst✝⁷ : AddCommGroup P
inst✝⁶ : Module R✝ M✝
inst✝⁵ : Module R✝ P
R : Type u_4
ι : Type u_5
M : ι → Type u_6
inst✝⁴ : Ring R
inst✝³ : (i : ι) → AddCommGroup (M i)
inst✝² : (i : ι) → Module R (M i)
inst✝¹ : Finite ι
inst✝ : ∀ (i : ι), IsNoetherian R (M i)
val✝ : Fintype ι
this : DecidableEq ι
on_finset : ∀ (s : Finset ι), IsNoetherian R ((i : { x // x ∈ s }) → M ↑i)
coe_e : { x // x ∈ Finset.univ } ≃ ι := Equiv.subtypeUnivEquiv (_ : ∀ (x : ι), x ∈ Finset.univ)
⊢ IsNoetherian R ((i : ι) → M i)

Next tactic:
letI : IsNoetherian R (∀ i : Finset.univ, M (coe_e i)) := on_finset Finset.univ
instance isNoetherian_pi {R ι : Type*} {M : ι → Type*}
    [Ring R] [∀ i, AddCommGroup (M i)] [∀ i, Module R (M i)] [Finite ι]
    [∀ i, IsNoetherian R (M i)] : IsNoetherian R (∀ i, M i) := by
  cases nonempty_fintype ι
  haveI := Classical.decEq ι
  suffices on_finset : ∀ s : Finset ι, IsNoetherian R (∀ i : s, M i)
  · let coe_e := Equiv.subtypeUnivEquiv <| @Finset.mem_univ ι _
    letI : IsNoetherian R (∀ i : Finset.univ, M (coe_e i)) := on_finset Finset.univ
    

Proof state:
case intro
R✝ : Type u_1
M✝ : Type u_2
P : Type u_3
inst✝⁹ : Ring R✝
inst✝⁸ : AddCommGroup M✝
inst✝⁷ : AddCommGroup P
inst✝⁶ : Module R✝ M✝
inst✝⁵ : Module R✝ P
R : Type u_4
ι : Type u_5
M : ι → Type u_6
inst✝⁴ : Ring R
inst✝³ : (i : ι) → AddCommGroup (M i)
inst✝² : (i : ι) → Module R (M i)
inst✝¹ : Finite ι
inst✝ : ∀ (i : ι), IsNoetherian R (M i)
val✝ : Fintype ι
this✝ : DecidableEq ι
on_finset : ∀ (s : Finset ι), IsNoetherian R ((i : { x // x ∈ s }) → M ↑i)
coe_e : { x // x ∈ Finset.univ } ≃ ι := Equiv.subtypeUnivEquiv (_ : ∀ (x : ι), x ∈ Finset.univ)
this : IsNoetherian R ((i : { x // x ∈ Finset.univ }) → M (coe_e i)) := on_finset Finset.univ
⊢ IsNoetherian R ((i : ι) → M i)

Next tactic:
exact isNoetherian_of_linearEquiv (LinearEquiv.piCongrLeft R M coe_e)
instance isNoetherian_pi {R ι : Type*} {M : ι → Type*}
    [Ring R] [∀ i, AddCommGroup (M i)] [∀ i, Module R (M i)] [Finite ι]
    [∀ i, IsNoetherian R (M i)] : IsNoetherian R (∀ i, M i) := by
  cases nonempty_fintype ι
  haveI := Classical.decEq ι
  suffices on_finset : ∀ s : Finset ι, IsNoetherian R (∀ i : s, M i)
  · let coe_e := Equiv.subtypeUnivEquiv <| @Finset.mem_univ ι _
    letI : IsNoetherian R (∀ i : Finset.univ, M (coe_e i)) := on_finset Finset.univ
    exact isNoetherian_of_linearEquiv (LinearEquiv.piCongrLeft R M coe_e)
  

Proof state:
case on_finset
R✝ : Type u_1
M✝ : Type u_2
P : Type u_3
inst✝⁹ : Ring R✝
inst✝⁸ : AddCommGroup M✝
inst✝⁷ : AddCommGroup P
inst✝⁶ : Module R✝ M✝
inst✝⁵ : Module R✝ P
R : Type u_4
ι : Type u_5
M : ι → Type u_6
inst✝⁴ : Ring R
inst✝³ : (i : ι) → AddCommGroup (M i)
inst✝² : (i : ι) → Module R (M i)
inst✝¹ : Finite ι
inst✝ : ∀ (i : ι), IsNoetherian R (M i)
val✝ : Fintype ι
this : DecidableEq ι
⊢ ∀ (s : Finset ι), IsNoetherian R ((i : { x // x ∈ s }) → M ↑i)

Next tactic:
intro s
instance isNoetherian_pi {R ι : Type*} {M : ι → Type*}
    [Ring R] [∀ i, AddCommGroup (M i)] [∀ i, Module R (M i)] [Finite ι]
    [∀ i, IsNoetherian R (M i)] : IsNoetherian R (∀ i, M i) := by
  cases nonempty_fintype ι
  haveI := Classical.decEq ι
  suffices on_finset : ∀ s : Finset ι, IsNoetherian R (∀ i : s, M i)
  · let coe_e := Equiv.subtypeUnivEquiv <| @Finset.mem_univ ι _
    letI : IsNoetherian R (∀ i : Finset.univ, M (coe_e i)) := on_finset Finset.univ
    exact isNoetherian_of_linearEquiv (LinearEquiv.piCongrLeft R M coe_e)
  intro s
  

Proof state:
case on_finset
R✝ : Type u_1
M✝ : Type u_2
P : Type u_3
inst✝⁹ : Ring R✝
inst✝⁸ : AddCommGroup M✝
inst✝⁷ : AddCommGroup P
inst✝⁶ : Module R✝ M✝
inst✝⁵ : Module R✝ P
R : Type u_4
ι : Type u_5
M : ι → Type u_6
inst✝⁴ : Ring R
inst✝³ : (i : ι) → AddCommGroup (M i)
inst✝² : (i : ι) → Module R (M i)
inst✝¹ : Finite ι
inst✝ : ∀ (i : ι), IsNoetherian R (M i)
val✝ : Fintype ι
this : DecidableEq ι
s : Finset ι
⊢ IsNoetherian R ((i : { x // x ∈ s }) → M ↑i)

Next tactic:
induction' s using Finset.induction with a s has ih
instance isNoetherian_pi {R ι : Type*} {M : ι → Type*}
    [Ring R] [∀ i, AddCommGroup (M i)] [∀ i, Module R (M i)] [Finite ι]
    [∀ i, IsNoetherian R (M i)] : IsNoetherian R (∀ i, M i) := by
  cases nonempty_fintype ι
  haveI := Classical.decEq ι
  suffices on_finset : ∀ s : Finset ι, IsNoetherian R (∀ i : s, M i)
  · let coe_e := Equiv.subtypeUnivEquiv <| @Finset.mem_univ ι _
    letI : IsNoetherian R (∀ i : Finset.univ, M (coe_e i)) := on_finset Finset.univ
    exact isNoetherian_of_linearEquiv (LinearEquiv.piCongrLeft R M coe_e)
  intro s
  induction' s using Finset.induction with a s has ih
  · 

Proof state:
case on_finset.empty
R✝ : Type u_1
M✝ : Type u_2
P : Type u_3
inst✝⁹ : Ring R✝
inst✝⁸ : AddCommGroup M✝
inst✝⁷ : AddCommGroup P
inst✝⁶ : Module R✝ M✝
inst✝⁵ : Module R✝ P
R : Type u_4
ι : Type u_5
M : ι → Type u_6
inst✝⁴ : Ring R
inst✝³ : (i : ι) → AddCommGroup (M i)
inst✝² : (i : ι) → Module R (M i)
inst✝¹ : Finite ι
inst✝ : ∀ (i : ι), IsNoetherian R (M i)
val✝ : Fintype ι
this : DecidableEq ι
⊢ IsNoetherian R ((i : { x // x ∈ ∅ }) → M ↑i)

Next tactic:
exact ⟨fun s => by
      have : s = ⊥ := by simp only [eq_iff_true_of_subsingleton]
      rw [this]
      apply Submodule.fg_bot⟩
instance isNoetherian_pi {R ι : Type*} {M : ι → Type*}
    [Ring R] [∀ i, AddCommGroup (M i)] [∀ i, Module R (M i)] [Finite ι]
    [∀ i, IsNoetherian R (M i)] : IsNoetherian R (∀ i, M i) := by
  cases nonempty_fintype ι
  haveI := Classical.decEq ι
  suffices on_finset : ∀ s : Finset ι, IsNoetherian R (∀ i : s, M i)
  · let coe_e := Equiv.subtypeUnivEquiv <| @Finset.mem_univ ι _
    letI : IsNoetherian R (∀ i : Finset.univ, M (coe_e i)) := on_finset Finset.univ
    exact isNoetherian_of_linearEquiv (LinearEquiv.piCongrLeft R M coe_e)
  intro s
  induction' s using Finset.induction with a s has ih
  · exact ⟨fun s => by
      

Proof state:
R✝ : Type u_1
M✝ : Type u_2
P : Type u_3
inst✝⁹ : Ring R✝
inst✝⁸ : AddCommGroup M✝
inst✝⁷ : AddCommGroup P
inst✝⁶ : Module R✝ M✝
inst✝⁵ : Module R✝ P
R : Type u_4
ι : Type u_5
M : ι → Type u_6
inst✝⁴ : Ring R
inst✝³ : (i : ι) → AddCommGroup (M i)
inst✝² : (i : ι) → Module R (M i)
inst✝¹ : Finite ι
inst✝ : ∀ (i : ι), IsNoetherian R (M i)
val✝ : Fintype ι
this : DecidableEq ι
s : Submodule R ((i : { x // x ∈ ∅ }) → M ↑i)
⊢ Submodule.FG s

Next tactic:
have : s = ⊥ := by simp only [eq_iff_true_of_subsingleton]
instance isNoetherian_pi {R ι : Type*} {M : ι → Type*}
    [Ring R] [∀ i, AddCommGroup (M i)] [∀ i, Module R (M i)] [Finite ι]
    [∀ i, IsNoetherian R (M i)] : IsNoetherian R (∀ i, M i) := by
  cases nonempty_fintype ι
  haveI := Classical.decEq ι
  suffices on_finset : ∀ s : Finset ι, IsNoetherian R (∀ i : s, M i)
  · let coe_e := Equiv.subtypeUnivEquiv <| @Finset.mem_univ ι _
    letI : IsNoetherian R (∀ i : Finset.univ, M (coe_e i)) := on_finset Finset.univ
    exact isNoetherian_of_linearEquiv (LinearEquiv.piCongrLeft R M coe_e)
  intro s
  induction' s using Finset.induction with a s has ih
  · exact ⟨fun s => by
      have : s = ⊥ := by 

Proof state:
R✝ : Type u_1
M✝ : Type u_2
P : Type u_3
inst✝⁹ : Ring R✝
inst✝⁸ : AddCommGroup M✝
inst✝⁷ : AddCommGroup P
inst✝⁶ : Module R✝ M✝
inst✝⁵ : Module R✝ P
R : Type u_4
ι : Type u_5
M : ι → Type u_6
inst✝⁴ : Ring R
inst✝³ : (i : ι) → AddCommGroup (M i)
inst✝² : (i : ι) → Module R (M i)
inst✝¹ : Finite ι
inst✝ : ∀ (i : ι), IsNoetherian R (M i)
val✝ : Fintype ι
this : DecidableEq ι
s : Submodule R ((i : { x // x ∈ ∅ }) → M ↑i)
⊢ s = ⊥

Next tactic:
simp only [eq_iff_true_of_subsingleton]
instance isNoetherian_pi {R ι : Type*} {M : ι → Type*}
    [Ring R] [∀ i, AddCommGroup (M i)] [∀ i, Module R (M i)] [Finite ι]
    [∀ i, IsNoetherian R (M i)] : IsNoetherian R (∀ i, M i) := by
  cases nonempty_fintype ι
  haveI := Classical.decEq ι
  suffices on_finset : ∀ s : Finset ι, IsNoetherian R (∀ i : s, M i)
  · let coe_e := Equiv.subtypeUnivEquiv <| @Finset.mem_univ ι _
    letI : IsNoetherian R (∀ i : Finset.univ, M (coe_e i)) := on_finset Finset.univ
    exact isNoetherian_of_linearEquiv (LinearEquiv.piCongrLeft R M coe_e)
  intro s
  induction' s using Finset.induction with a s has ih
  · exact ⟨fun s => by
      have : s = ⊥ := by simp only [eq_iff_true_of_subsingleton]
      

Proof state:
R✝ : Type u_1
M✝ : Type u_2
P : Type u_3
inst✝⁹ : Ring R✝
inst✝⁸ : AddCommGroup M✝
inst✝⁷ : AddCommGroup P
inst✝⁶ : Module R✝ M✝
inst✝⁵ : Module R✝ P
R : Type u_4
ι : Type u_5
M : ι → Type u_6
inst✝⁴ : Ring R
inst✝³ : (i : ι) → AddCommGroup (M i)
inst✝² : (i : ι) → Module R (M i)
inst✝¹ : Finite ι
inst✝ : ∀ (i : ι), IsNoetherian R (M i)
val✝ : Fintype ι
this✝ : DecidableEq ι
s : Submodule R ((i : { x // x ∈ ∅ }) → M ↑i)
this : s = ⊥
⊢ Submodule.FG s

Next tactic:
rw [this]
instance isNoetherian_pi {R ι : Type*} {M : ι → Type*}
    [Ring R] [∀ i, AddCommGroup (M i)] [∀ i, Module R (M i)] [Finite ι]
    [∀ i, IsNoetherian R (M i)] : IsNoetherian R (∀ i, M i) := by
  cases nonempty_fintype ι
  haveI := Classical.decEq ι
  suffices on_finset : ∀ s : Finset ι, IsNoetherian R (∀ i : s, M i)
  · let coe_e := Equiv.subtypeUnivEquiv <| @Finset.mem_univ ι _
    letI : IsNoetherian R (∀ i : Finset.univ, M (coe_e i)) := on_finset Finset.univ
    exact isNoetherian_of_linearEquiv (LinearEquiv.piCongrLeft R M coe_e)
  intro s
  induction' s using Finset.induction with a s has ih
  · exact ⟨fun s => by
      have : s = ⊥ := by simp only [eq_iff_true_of_subsingleton]
      rw [this]
      

Proof state:
R✝ : Type u_1
M✝ : Type u_2
P : Type u_3
inst✝⁹ : Ring R✝
inst✝⁸ : AddCommGroup M✝
inst✝⁷ : AddCommGroup P
inst✝⁶ : Module R✝ M✝
inst✝⁵ : Module R✝ P
R : Type u_4
ι : Type u_5
M : ι → Type u_6
inst✝⁴ : Ring R
inst✝³ : (i : ι) → AddCommGroup (M i)
inst✝² : (i : ι) → Module R (M i)
inst✝¹ : Finite ι
inst✝ : ∀ (i : ι), IsNoetherian R (M i)
val✝ : Fintype ι
this✝ : DecidableEq ι
s : Submodule R ((i : { x // x ∈ ∅ }) → M ↑i)
this : s = ⊥
⊢ Submodule.FG ⊥

Next tactic:
apply Submodule.fg_bot