l3lab/ntp-mathlib huggingface dataset:
/-- If a set of ae strongly measurable functions is stable under addition and approximates
characteristic functions in `ℒp`, then it is dense in `ℒp`. -/
theorem Memℒp.induction_dense (hp_ne_top : p ≠ ∞) (P : (α → E) → Prop)
    (h0P :
      ∀ (c : E) ⦃s : Set α⦄,
        MeasurableSet s →
          μ s < ∞ →
            ∀ {ε : ℝ≥0∞}, ε ≠ 0 → ∃ g : α → E, snorm (g - s.indicator fun _ => c) p μ ≤ ε ∧ P g)
    (h1P : ∀ f g, P f → P g → P (f + g)) (h2P : ∀ f, P f → AEStronglyMeasurable f μ) {f : α → E}
    (hf : Memℒp f p μ) {ε : ℝ≥0∞} (hε : ε ≠ 0) : ∃ g : α → E, snorm (f - g) p μ ≤ ε ∧ P g := by
  rcases eq_or_ne p 0 with (rfl | hp_pos)
  · rcases h0P (0 : E) MeasurableSet.empty (by simp only [measure_empty, zero_lt_top])
        hε with ⟨g, _, Pg⟩
    exact ⟨g, by simp only [snorm_exponent_zero, zero_le'], Pg⟩
  suffices H :
    ∀ (f' : α →ₛ E) (δ : ℝ≥0∞) (hδ : δ ≠ 0), Memℒp f' p μ → ∃ g, snorm (⇑f' - g) p μ ≤ δ ∧ P g
  · obtain ⟨η, ηpos, hη⟩ := exists_Lp_half E μ p hε
    rcases hf.exists_simpleFunc_snorm_sub_lt hp_ne_top ηpos.ne' with ⟨f', hf', f'_mem⟩
    rcases H f' η ηpos.ne' f'_mem with ⟨g, hg, Pg⟩
    refine' ⟨g, _, Pg⟩
    convert (hη _ _ (hf.aestronglyMeasurable.sub f'.aestronglyMeasurable)
          (f'.aestronglyMeasurable.sub (h2P g Pg)) hf'.le hg).le using 2
    simp only [sub_add_sub_cancel]
  apply SimpleFunc.induction
  · intro c s hs ε εpos Hs
    rcases eq_or_ne c 0 with (rfl | hc)
    · rcases h0P (0 : E) MeasurableSet.empty (by simp only [measure_empty, zero_lt_top])
          εpos with ⟨g, hg, Pg⟩
      rw [← snorm_neg, neg_sub] at hg
      refine' ⟨g, _, Pg⟩
      convert hg
      ext x
      simp only [SimpleFunc.const_zero, SimpleFunc.coe_piecewise, SimpleFunc.coe_zero,
        piecewise_eq_indicator, indicator_zero', Pi.zero_apply, indicator_zero]
    · have : μ s < ∞ := SimpleFunc.measure_lt_top_of_memℒp_indicator hp_pos hp_ne_top hc hs Hs
      rcases h0P c hs this εpos with ⟨g, hg, Pg⟩
      rw [← snorm_neg, neg_sub] at hg
      exact ⟨g, hg, Pg⟩
  · 

Proof state:
case H.h_add
α : Type u_1
β : Type u_2
ι : Type u_3
E : Type u_4
F : Type u_5
𝕜 : Type u_6
inst✝¹ : MeasurableSpace α
inst✝ : NormedAddCommGroup E
f✝ : α → E
p : ℝ≥0∞
μ : Measure α
hp_ne_top : p ≠ ⊤
P : (α → E) → Prop
h0P :
  ∀ (c : E) ⦃s : Set α⦄,
    MeasurableSet s → ↑↑μ s < ⊤ → ∀ {ε : ℝ≥0∞}, ε ≠ 0 → ∃ g, snorm (g - Set.indicator s fun x => c) p μ ≤ ε ∧ P g
h1P : ∀ (f g : α → E), P f → P g → P (f + g)
h2P : ∀ (f : α → E), P f → AEStronglyMeasurable f μ
f : α → E
hf : Memℒp f p
ε : ℝ≥0∞
hε : ε ≠ 0
hp_pos : p ≠ 0
⊢ ∀ ⦃f g : α →ₛ E⦄,
    Disjoint (support ↑f) (support ↑g) →
      (∀ (δ : ℝ≥0∞), δ ≠ 0 → Memℒp (↑f) p → ∃ g, snorm (↑f - g) p μ ≤ δ ∧ P g) →
        (∀ (δ : ℝ≥0∞), δ ≠ 0 → Memℒp (↑g) p → ∃ g_1, snorm (↑g - g_1) p μ ≤ δ ∧ P g_1) →
          ∀ (δ : ℝ≥0∞), δ ≠ 0 → Memℒp (↑(f + g)) p → ∃ g_1, snorm (↑(f + g) - g_1) p μ ≤ δ ∧ P g_1

Next tactic:
intro f f' hff' hf hf' δ δpos int_ff'
/-- If a set of ae strongly measurable functions is stable under addition and approximates
characteristic functions in `ℒp`, then it is dense in `ℒp`. -/
theorem Memℒp.induction_dense (hp_ne_top : p ≠ ∞) (P : (α → E) → Prop)
    (h0P :
      ∀ (c : E) ⦃s : Set α⦄,
        MeasurableSet s →
          μ s < ∞ →
            ∀ {ε : ℝ≥0∞}, ε ≠ 0 → ∃ g : α → E, snorm (g - s.indicator fun _ => c) p μ ≤ ε ∧ P g)
    (h1P : ∀ f g, P f → P g → P (f + g)) (h2P : ∀ f, P f → AEStronglyMeasurable f μ) {f : α → E}
    (hf : Memℒp f p μ) {ε : ℝ≥0∞} (hε : ε ≠ 0) : ∃ g : α → E, snorm (f - g) p μ ≤ ε ∧ P g := by
  rcases eq_or_ne p 0 with (rfl | hp_pos)
  · rcases h0P (0 : E) MeasurableSet.empty (by simp only [measure_empty, zero_lt_top])
        hε with ⟨g, _, Pg⟩
    exact ⟨g, by simp only [snorm_exponent_zero, zero_le'], Pg⟩
  suffices H :
    ∀ (f' : α →ₛ E) (δ : ℝ≥0∞) (hδ : δ ≠ 0), Memℒp f' p μ → ∃ g, snorm (⇑f' - g) p μ ≤ δ ∧ P g
  · obtain ⟨η, ηpos, hη⟩ := exists_Lp_half E μ p hε
    rcases hf.exists_simpleFunc_snorm_sub_lt hp_ne_top ηpos.ne' with ⟨f', hf', f'_mem⟩
    rcases H f' η ηpos.ne' f'_mem with ⟨g, hg, Pg⟩
    refine' ⟨g, _, Pg⟩
    convert (hη _ _ (hf.aestronglyMeasurable.sub f'.aestronglyMeasurable)
          (f'.aestronglyMeasurable.sub (h2P g Pg)) hf'.le hg).le using 2
    simp only [sub_add_sub_cancel]
  apply SimpleFunc.induction
  · intro c s hs ε εpos Hs
    rcases eq_or_ne c 0 with (rfl | hc)
    · rcases h0P (0 : E) MeasurableSet.empty (by simp only [measure_empty, zero_lt_top])
          εpos with ⟨g, hg, Pg⟩
      rw [← snorm_neg, neg_sub] at hg
      refine' ⟨g, _, Pg⟩
      convert hg
      ext x
      simp only [SimpleFunc.const_zero, SimpleFunc.coe_piecewise, SimpleFunc.coe_zero,
        piecewise_eq_indicator, indicator_zero', Pi.zero_apply, indicator_zero]
    · have : μ s < ∞ := SimpleFunc.measure_lt_top_of_memℒp_indicator hp_pos hp_ne_top hc hs Hs
      rcases h0P c hs this εpos with ⟨g, hg, Pg⟩
      rw [← snorm_neg, neg_sub] at hg
      exact ⟨g, hg, Pg⟩
  · intro f f' hff' hf hf' δ δpos int_ff'
    

Proof state:
case H.h_add
α : Type u_1
β : Type u_2
ι : Type u_3
E : Type u_4
F : Type u_5
𝕜 : Type u_6
inst✝¹ : MeasurableSpace α
inst✝ : NormedAddCommGroup E
f✝¹ : α → E
p : ℝ≥0∞
μ : Measure α
hp_ne_top : p ≠ ⊤
P : (α → E) → Prop
h0P :
  ∀ (c : E) ⦃s : Set α⦄,
    MeasurableSet s → ↑↑μ s < ⊤ → ∀ {ε : ℝ≥0∞}, ε ≠ 0 → ∃ g, snorm (g - Set.indicator s fun x => c) p μ ≤ ε ∧ P g
h1P : ∀ (f g : α → E), P f → P g → P (f + g)
h2P : ∀ (f : α → E), P f → AEStronglyMeasurable f μ
f✝ : α → E
hf✝ : Memℒp f✝ p
ε : ℝ≥0∞
hε : ε ≠ 0
hp_pos : p ≠ 0
f f' : α →ₛ E
hff' : Disjoint (support ↑f) (support ↑f')
hf : ∀ (δ : ℝ≥0∞), δ ≠ 0 → Memℒp (↑f) p → ∃ g, snorm (↑f - g) p μ ≤ δ ∧ P g
hf' : ∀ (δ : ℝ≥0∞), δ ≠ 0 → Memℒp (↑f') p → ∃ g, snorm (↑f' - g) p μ ≤ δ ∧ P g
δ : ℝ≥0∞
δpos : δ ≠ 0
int_ff' : Memℒp (↑(f + f')) p
⊢ ∃ g, snorm (↑(f + f') - g) p μ ≤ δ ∧ P g

Next tactic:
obtain ⟨η, ηpos, hη⟩ := exists_Lp_half E μ p δpos
protected theorem L1.SimpleFunc.integrable (f : α →₁ₛ[μ] E) :
    Integrable (Lp.simpleFunc.toSimpleFunc f) μ := by
  

Proof state:
α : Type u_1
β : Type u_2
ι : Type u_3
E : Type u_4
F : Type u_5
𝕜 : Type u_6
inst✝¹ : MeasurableSpace α
inst✝ : NormedAddCommGroup E
f✝ : α → E
p : ℝ≥0∞
μ : Measure α
f : ↥(Lp.simpleFunc E 1 μ)
⊢ Integrable ↑(Lp.simpleFunc.toSimpleFunc f)

Next tactic:
rw [← memℒp_one_iff_integrable]
protected theorem L1.SimpleFunc.integrable (f : α →₁ₛ[μ] E) :
    Integrable (Lp.simpleFunc.toSimpleFunc f) μ := by
  rw [← memℒp_one_iff_integrable]; 

Proof state:
α : Type u_1
β : Type u_2
ι : Type u_3
E : Type u_4
F : Type u_5
𝕜 : Type u_6
inst✝¹ : MeasurableSpace α
inst✝ : NormedAddCommGroup E
f✝ : α → E
p : ℝ≥0∞
μ : Measure α
f : ↥(Lp.simpleFunc E 1 μ)
⊢ Memℒp (↑(Lp.simpleFunc.toSimpleFunc f)) 1

Next tactic:
exact Lp.simpleFunc.memℒp f
/-- To prove something for an arbitrary integrable function in a normed group,
it suffices to show that
* the property holds for (multiples of) characteristic functions;
* is closed under addition;
* the set of functions in the `L¹` space for which the property holds is closed.
* the property is closed under the almost-everywhere equal relation.

It is possible to make the hypotheses in the induction steps a bit stronger, and such conditions
can be added once we need them (for example in `h_add` it is only necessary to consider the sum of
a simple function with a multiple of a characteristic function and that the intersection
of their images is a subset of `{0}`).
-/
@[elab_as_elim]
theorem Integrable.induction (P : (α → E) → Prop)
    (h_ind : ∀ (c : E) ⦃s⦄, MeasurableSet s → μ s < ∞ → P (s.indicator fun _ => c))
    (h_add :
      ∀ ⦃f g : α → E⦄,
        Disjoint (support f) (support g) → Integrable f μ → Integrable g μ → P f → P g → P (f + g))
    (h_closed : IsClosed { f : α →₁[μ] E | P f })
    (h_ae : ∀ ⦃f g⦄, f =ᵐ[μ] g → Integrable f μ → P f → P g) :
    ∀ ⦃f : α → E⦄, Integrable f μ → P f := by
  

Proof state:
α : Type u_1
β : Type u_2
ι : Type u_3
E : Type u_4
F : Type u_5
𝕜 : Type u_6
inst✝¹ : MeasurableSpace α
inst✝ : NormedAddCommGroup E
f : α → E
p : ℝ≥0∞
μ : Measure α
P : (α → E) → Prop
h_ind : ∀ (c : E) ⦃s : Set α⦄, MeasurableSet s → ↑↑μ s < ⊤ → P (indicator s fun x => c)
h_add : ∀ ⦃f g : α → E⦄, Disjoint (support f) (support g) → Integrable f → Integrable g → P f → P g → P (f + g)
h_closed : IsClosed {f | P ↑↑f}
h_ae : ∀ ⦃f g : α → E⦄, f =ᵐ[μ] g → Integrable f → P f → P g
⊢ ∀ ⦃f : α → E⦄, Integrable f → P f

Next tactic:
simp only [← memℒp_one_iff_integrable] at *
/-- To prove something for an arbitrary integrable function in a normed group,
it suffices to show that
* the property holds for (multiples of) characteristic functions;
* is closed under addition;
* the set of functions in the `L¹` space for which the property holds is closed.
* the property is closed under the almost-everywhere equal relation.

It is possible to make the hypotheses in the induction steps a bit stronger, and such conditions
can be added once we need them (for example in `h_add` it is only necessary to consider the sum of
a simple function with a multiple of a characteristic function and that the intersection
of their images is a subset of `{0}`).
-/
@[elab_as_elim]
theorem Integrable.induction (P : (α → E) → Prop)
    (h_ind : ∀ (c : E) ⦃s⦄, MeasurableSet s → μ s < ∞ → P (s.indicator fun _ => c))
    (h_add :
      ∀ ⦃f g : α → E⦄,
        Disjoint (support f) (support g) → Integrable f μ → Integrable g μ → P f → P g → P (f + g))
    (h_closed : IsClosed { f : α →₁[μ] E | P f })
    (h_ae : ∀ ⦃f g⦄, f =ᵐ[μ] g → Integrable f μ → P f → P g) :
    ∀ ⦃f : α → E⦄, Integrable f μ → P f := by
  simp only [← memℒp_one_iff_integrable] at *
  

Proof state:
α : Type u_1
β : Type u_2
ι : Type u_3
E : Type u_4
F : Type u_5
𝕜 : Type u_6
inst✝¹ : MeasurableSpace α
inst✝ : NormedAddCommGroup E
f : α → E
p : ℝ≥0∞
μ : Measure α
P : (α → E) → Prop
h_ind : ∀ (c : E) ⦃s : Set α⦄, MeasurableSet s → ↑↑μ s < ⊤ → P (indicator s fun x => c)
h_closed : IsClosed {f | P ↑↑f}
h_add : ∀ ⦃f g : α → E⦄, Disjoint (support f) (support g) → Memℒp f 1 → Memℒp g 1 → P f → P g → P (f + g)
h_ae : ∀ ⦃f g : α → E⦄, f =ᵐ[μ] g → Memℒp f 1 → P f → P g
⊢ ∀ ⦃f : α → E⦄, Memℒp f 1 → P f

Next tactic:
exact Memℒp.induction one_ne_top (P := P) h_ind h_add h_closed h_ae
/-- Construct limit data for a binary product in `ModuleCat R`, using `ModuleCat.of R (M × N)`.
-/
@[simps cone_pt isLimit_lift]
def binaryProductLimitCone (M N : ModuleCat.{v} R) : Limits.LimitCone (pair M N) where
  cone :=
    { pt := ModuleCat.of R (M × N)
      π :=
        { app := fun j =>
            Discrete.casesOn j fun j =>
              WalkingPair.casesOn j (LinearMap.fst R M N) (LinearMap.snd R M N)
          naturality := by 

Proof state:
R : Type u
inst✝ : Ring R
M N : ModuleCat R
⊢ ∀ ⦃X Y : Discrete WalkingPair⦄ (f : X ⟶ Y),
    ((Functor.const (Discrete WalkingPair)).obj (of R (↑M × ↑N))).map f ≫
        (fun j => Discrete.casesOn j fun j => WalkingPair.casesOn j (LinearMap.fst R ↑M ↑N) (LinearMap.snd R ↑M ↑N)) Y =
      (fun j => Discrete.casesOn j fun j => WalkingPair.casesOn j (LinearMap.fst R ↑M ↑N) (LinearMap.snd R ↑M ↑N)) X ≫
        (pair M N).map f

Next tactic:
rintro ⟨⟨⟩⟩ ⟨⟨⟩⟩ ⟨⟨⟨⟩⟩⟩
/-- Construct limit data for a binary product in `ModuleCat R`, using `ModuleCat.of R (M × N)`.
-/
@[simps cone_pt isLimit_lift]
def binaryProductLimitCone (M N : ModuleCat.{v} R) : Limits.LimitCone (pair M N) where
  cone :=
    { pt := ModuleCat.of R (M × N)
      π :=
        { app := fun j =>
            Discrete.casesOn j fun j =>
              WalkingPair.casesOn j (LinearMap.fst R M N) (LinearMap.snd R M N)
          naturality := by rintro ⟨⟨⟩⟩ ⟨⟨⟩⟩ ⟨⟨⟨⟩⟩⟩ <;> 

Proof state:
case mk.left.mk.left.up.up.refl
R : Type u
inst✝ : Ring R
M N : ModuleCat R
⊢ ((Functor.const (Discrete WalkingPair)).obj (of R (↑M × ↑N))).map
        { down := { down := (_ : { as := WalkingPair.left }.as = { as := WalkingPair.left }.as) } } ≫
      (fun j => Discrete.casesOn j fun j => WalkingPair.casesOn j (LinearMap.fst R ↑M ↑N) (LinearMap.snd R ↑M ↑N))
        { as := WalkingPair.left } =
    (fun j => Discrete.casesOn j fun j => WalkingPair.casesOn j (LinearMap.fst R ↑M ↑N) (LinearMap.snd R ↑M ↑N))
        { as := WalkingPair.left } ≫
      (pair M N).map { down := { down := (_ : { as := WalkingPair.left }.as = { as := WalkingPair.left }.as) } }

Next tactic:
rfl
/-- Construct limit data for a binary product in `ModuleCat R`, using `ModuleCat.of R (M × N)`.
-/
@[simps cone_pt isLimit_lift]
def binaryProductLimitCone (M N : ModuleCat.{v} R) : Limits.LimitCone (pair M N) where
  cone :=
    { pt := ModuleCat.of R (M × N)
      π :=
        { app := fun j =>
            Discrete.casesOn j fun j =>
              WalkingPair.casesOn j (LinearMap.fst R M N) (LinearMap.snd R M N)
          naturality := by rintro ⟨⟨⟩⟩ ⟨⟨⟩⟩ ⟨⟨⟨⟩⟩⟩ <;> 

Proof state:
case mk.right.mk.right.up.up.refl
R : Type u
inst✝ : Ring R
M N : ModuleCat R
⊢ ((Functor.const (Discrete WalkingPair)).obj (of R (↑M × ↑N))).map
        { down := { down := (_ : { as := WalkingPair.right }.as = { as := WalkingPair.right }.as) } } ≫
      (fun j => Discrete.casesOn j fun j => WalkingPair.casesOn j (LinearMap.fst R ↑M ↑N) (LinearMap.snd R ↑M ↑N))
        { as := WalkingPair.right } =
    (fun j => Discrete.casesOn j fun j => WalkingPair.casesOn j (LinearMap.fst R ↑M ↑N) (LinearMap.snd R ↑M ↑N))
        { as := WalkingPair.right } ≫
      (pair M N).map { down := { down := (_ : { as := WalkingPair.right }.as = { as := WalkingPair.right }.as) } }

Next tactic:
rfl
/-- Construct limit data for a binary product in `ModuleCat R`, using `ModuleCat.of R (M × N)`.
-/
@[simps cone_pt isLimit_lift]
def binaryProductLimitCone (M N : ModuleCat.{v} R) : Limits.LimitCone (pair M N) where
  cone :=
    { pt := ModuleCat.of R (M × N)
      π :=
        { app := fun j =>
            Discrete.casesOn j fun j =>
              WalkingPair.casesOn j (LinearMap.fst R M N) (LinearMap.snd R M N)
          naturality := by rintro ⟨⟨⟩⟩ ⟨⟨⟩⟩ ⟨⟨⟨⟩⟩⟩ <;> rfl } }
  isLimit :=
    { lift := fun s => LinearMap.prod (s.π.app ⟨WalkingPair.left⟩) (s.π.app ⟨WalkingPair.right⟩)
      fac := by 

Proof state:
R : Type u
inst✝ : Ring R
M N : ModuleCat R
⊢ ∀ (s : Cone (pair M N)) (j : Discrete WalkingPair),
    (fun s => LinearMap.prod (s.π.app { as := WalkingPair.left }) (s.π.app { as := WalkingPair.right })) s ≫
        { pt := of R (↑M × ↑N),
                π :=
                  NatTrans.mk fun j =>
                    Discrete.casesOn j fun j =>
                      WalkingPair.casesOn j (LinearMap.fst R ↑M ↑N) (LinearMap.snd R ↑M ↑N) }.π.app
          j =
      s.π.app j

Next tactic:
rintro s (⟨⟩ | ⟨⟩)
/-- Construct limit data for a binary product in `ModuleCat R`, using `ModuleCat.of R (M × N)`.
-/
@[simps cone_pt isLimit_lift]
def binaryProductLimitCone (M N : ModuleCat.{v} R) : Limits.LimitCone (pair M N) where
  cone :=
    { pt := ModuleCat.of R (M × N)
      π :=
        { app := fun j =>
            Discrete.casesOn j fun j =>
              WalkingPair.casesOn j (LinearMap.fst R M N) (LinearMap.snd R M N)
          naturality := by rintro ⟨⟨⟩⟩ ⟨⟨⟩⟩ ⟨⟨⟨⟩⟩⟩ <;> rfl } }
  isLimit :=
    { lift := fun s => LinearMap.prod (s.π.app ⟨WalkingPair.left⟩) (s.π.app ⟨WalkingPair.right⟩)
      fac := by rintro s (⟨⟩ | ⟨⟩) <;> 

Proof state:
case mk.left
R : Type u
inst✝ : Ring R
M N : ModuleCat R
s : Cone (pair M N)
⊢ (fun s => LinearMap.prod (s.π.app { as := WalkingPair.left }) (s.π.app { as := WalkingPair.right })) s ≫
      { pt := of R (↑M × ↑N),
              π :=
                NatTrans.mk fun j =>
                  Discrete.casesOn j fun j =>
                    WalkingPair.casesOn j (LinearMap.fst R ↑M ↑N) (LinearMap.snd R ↑M ↑N) }.π.app
        { as := WalkingPair.left } =
    s.π.app { as := WalkingPair.left }

Next tactic:
rfl
/-- Construct limit data for a binary product in `ModuleCat R`, using `ModuleCat.of R (M × N)`.
-/
@[simps cone_pt isLimit_lift]
def binaryProductLimitCone (M N : ModuleCat.{v} R) : Limits.LimitCone (pair M N) where
  cone :=
    { pt := ModuleCat.of R (M × N)
      π :=
        { app := fun j =>
            Discrete.casesOn j fun j =>
              WalkingPair.casesOn j (LinearMap.fst R M N) (LinearMap.snd R M N)
          naturality := by rintro ⟨⟨⟩⟩ ⟨⟨⟩⟩ ⟨⟨⟨⟩⟩⟩ <;> rfl } }
  isLimit :=
    { lift := fun s => LinearMap.prod (s.π.app ⟨WalkingPair.left⟩) (s.π.app ⟨WalkingPair.right⟩)
      fac := by rintro s (⟨⟩ | ⟨⟩) <;> 

Proof state:
case mk.right
R : Type u
inst✝ : Ring R
M N : ModuleCat R
s : Cone (pair M N)
⊢ (fun s => LinearMap.prod (s.π.app { as := WalkingPair.left }) (s.π.app { as := WalkingPair.right })) s ≫
      { pt := of R (↑M × ↑N),
              π :=
                NatTrans.mk fun j =>
                  Discrete.casesOn j fun j =>
                    WalkingPair.casesOn j (LinearMap.fst R ↑M ↑N) (LinearMap.snd R ↑M ↑N) }.π.app
        { as := WalkingPair.right } =
    s.π.app { as := WalkingPair.right }

Next tactic:
rfl
/-- Construct limit data for a binary product in `ModuleCat R`, using `ModuleCat.of R (M × N)`.
-/
@[simps cone_pt isLimit_lift]
def binaryProductLimitCone (M N : ModuleCat.{v} R) : Limits.LimitCone (pair M N) where
  cone :=
    { pt := ModuleCat.of R (M × N)
      π :=
        { app := fun j =>
            Discrete.casesOn j fun j =>
              WalkingPair.casesOn j (LinearMap.fst R M N) (LinearMap.snd R M N)
          naturality := by rintro ⟨⟨⟩⟩ ⟨⟨⟩⟩ ⟨⟨⟨⟩⟩⟩ <;> rfl } }
  isLimit :=
    { lift := fun s => LinearMap.prod (s.π.app ⟨WalkingPair.left⟩) (s.π.app ⟨WalkingPair.right⟩)
      fac := by rintro s (⟨⟩ | ⟨⟩) <;> rfl
      uniq := fun s m w => by
        

Proof state:
R : Type u
inst✝ : Ring R
M N : ModuleCat R
s : Cone (pair M N)
m :
  s.pt ⟶
    { pt := of R (↑M × ↑N),
        π :=
          NatTrans.mk fun j =>
            Discrete.casesOn j fun j => WalkingPair.casesOn j (LinearMap.fst R ↑M ↑N) (LinearMap.snd R ↑M ↑N) }.pt
w :
  ∀ (j : Discrete WalkingPair),
    m ≫
        { pt := of R (↑M × ↑N),
                π :=
                  NatTrans.mk fun j =>
                    Discrete.casesOn j fun j =>
                      WalkingPair.casesOn j (LinearMap.fst R ↑M ↑N) (LinearMap.snd R ↑M ↑N) }.π.app
          j =
      s.π.app j
⊢ m = (fun s => LinearMap.prod (s.π.app { as := WalkingPair.left }) (s.π.app { as := WalkingPair.right })) s

Next tactic:
simp_rw [← w ⟨WalkingPair.left⟩, ← w ⟨WalkingPair.right⟩]
/-- Construct limit data for a binary product in `ModuleCat R`, using `ModuleCat.of R (M × N)`.
-/
@[simps cone_pt isLimit_lift]
def binaryProductLimitCone (M N : ModuleCat.{v} R) : Limits.LimitCone (pair M N) where
  cone :=
    { pt := ModuleCat.of R (M × N)
      π :=
        { app := fun j =>
            Discrete.casesOn j fun j =>
              WalkingPair.casesOn j (LinearMap.fst R M N) (LinearMap.snd R M N)
          naturality := by rintro ⟨⟨⟩⟩ ⟨⟨⟩⟩ ⟨⟨⟨⟩⟩⟩ <;> rfl } }
  isLimit :=
    { lift := fun s => LinearMap.prod (s.π.app ⟨WalkingPair.left⟩) (s.π.app ⟨WalkingPair.right⟩)
      fac := by rintro s (⟨⟩ | ⟨⟩) <;> rfl
      uniq := fun s m w => by
        simp_rw [← w ⟨WalkingPair.left⟩, ← w ⟨WalkingPair.right⟩]
        

Proof state:
R : Type u
inst✝ : Ring R
M N : ModuleCat R
s : Cone (pair M N)
m :
  s.pt ⟶
    { pt := of R (↑M × ↑N),
        π :=
          NatTrans.mk fun j =>
            Discrete.casesOn j fun j => WalkingPair.casesOn j (LinearMap.fst R ↑M ↑N) (LinearMap.snd R ↑M ↑N) }.pt
w :
  ∀ (j : Discrete WalkingPair),
    m ≫
        { pt := of R (↑M × ↑N),
                π :=
                  NatTrans.mk fun j =>
                    Discrete.casesOn j fun j =>
                      WalkingPair.casesOn j (LinearMap.fst R ↑M ↑N) (LinearMap.snd R ↑M ↑N) }.π.app
          j =
      s.π.app j
⊢ m = LinearMap.prod (m ≫ LinearMap.fst R ↑M ↑N) (m ≫ LinearMap.snd R ↑M ↑N)

Next tactic:
rfl
/-- The map from an arbitrary cone over an indexed family of abelian groups
to the cartesian product of those groups.
-/
@[simps]
def lift (s : Fan f) : s.pt ⟶ ModuleCat.of R (∀ j, f j) where
  toFun x j := s.π.app ⟨j⟩ x
  map_add' x y := by
    

Proof state:
R : Type u
inst✝ : Ring R
J : Type w
f : J → ModuleCat R
s : Fan f
x y : ↑s.pt
⊢ (fun x j => (s.π.app { as := j }) x) (x + y) =
    (fun x j => (s.π.app { as := j }) x) x + (fun x j => (s.π.app { as := j }) x) y

Next tactic:
simp only [Functor.const_obj_obj, map_add]
/-- The map from an arbitrary cone over an indexed family of abelian groups
to the cartesian product of those groups.
-/
@[simps]
def lift (s : Fan f) : s.pt ⟶ ModuleCat.of R (∀ j, f j) where
  toFun x j := s.π.app ⟨j⟩ x
  map_add' x y := by
    simp only [Functor.const_obj_obj, map_add]
    

Proof state:
R : Type u
inst✝ : Ring R
J : Type w
f : J → ModuleCat R
s : Fan f
x y : ↑s.pt
⊢ (fun j => (s.π.app { as := j }) x + (s.π.app { as := j }) y) =
    (fun j => (s.π.app { as := j }) x) + fun j => (s.π.app { as := j }) y

Next tactic:
rfl
/-- The map from an arbitrary cone over an indexed family of abelian groups
to the cartesian product of those groups.
-/
@[simps]
def lift (s : Fan f) : s.pt ⟶ ModuleCat.of R (∀ j, f j) where
  toFun x j := s.π.app ⟨j⟩ x
  map_add' x y := by
    simp only [Functor.const_obj_obj, map_add]
    rfl
  map_smul' r x := by
    

Proof state:
R : Type u
inst✝ : Ring R
J : Type w
f : J → ModuleCat R
s : Fan f
r : R
x : ↑s.pt
⊢ AddHom.toFun
      { toFun := fun x j => (s.π.app { as := j }) x,
        map_add' :=
          (_ :
            ∀ (x y : ↑s.pt),
              (fun x j => (s.π.app { as := j }) x) (x + y) =
                (fun x j => (s.π.app { as := j }) x) x + (fun x j => (s.π.app { as := j }) x) y) }
      (r • x) =
    (RingHom.id R) r •
      AddHom.toFun
        { toFun := fun x j => (s.π.app { as := j }) x,
          map_add' :=
            (_ :
              ∀ (x y : ↑s.pt),
                (fun x j => (s.π.app { as := j }) x) (x + y) =
                  (fun x j => (s.π.app { as := j }) x) x + (fun x j => (s.π.app { as := j }) x) y) }
        x

Next tactic:
simp only [Functor.const_obj_obj, map_smul]
/-- The map from an arbitrary cone over an indexed family of abelian groups
to the cartesian product of those groups.
-/
@[simps]
def lift (s : Fan f) : s.pt ⟶ ModuleCat.of R (∀ j, f j) where
  toFun x j := s.π.app ⟨j⟩ x
  map_add' x y := by
    simp only [Functor.const_obj_obj, map_add]
    rfl
  map_smul' r x := by
    simp only [Functor.const_obj_obj, map_smul]
    

Proof state:
R : Type u
inst✝ : Ring R
J : Type w
f : J → ModuleCat R
s : Fan f
r : R
x : ↑s.pt
⊢ (fun j => r • (s.π.app { as := j }) x) = (RingHom.id R) r • fun j => (s.π.app { as := j }) x

Next tactic:
rfl
/-- Construct limit data for a product in `ModuleCat R`, using `ModuleCat.of R (∀ j, F.obj j)`.
-/
@[simps]
def productLimitCone : Limits.LimitCone (Discrete.functor f) where
  cone :=
    { pt := ModuleCat.of R (∀ j, f j)
      π := Discrete.natTrans fun j => (LinearMap.proj j.as : (∀ j, f j) →ₗ[R] f j.as) }
  isLimit :=
    { lift := lift.{_, v} f
      fac := fun s j => rfl
      uniq := fun s m w => by
        

Proof state:
R : Type u
inst✝ : Ring R
J : Type w
f : J → ModuleCat R
s : Cone (Discrete.functor f)
m : s.pt ⟶ { pt := of R ((j : J) → ↑(f j)), π := Discrete.natTrans fun j => LinearMap.proj j.as }.pt
w :
  ∀ (j : Discrete J),
    m ≫ { pt := of R ((j : J) → ↑(f j)), π := Discrete.natTrans fun j => LinearMap.proj j.as }.π.app j = s.π.app j
⊢ m = lift f s

Next tactic:
ext x
/-- Construct limit data for a product in `ModuleCat R`, using `ModuleCat.of R (∀ j, F.obj j)`.
-/
@[simps]
def productLimitCone : Limits.LimitCone (Discrete.functor f) where
  cone :=
    { pt := ModuleCat.of R (∀ j, f j)
      π := Discrete.natTrans fun j => (LinearMap.proj j.as : (∀ j, f j) →ₗ[R] f j.as) }
  isLimit :=
    { lift := lift.{_, v} f
      fac := fun s j => rfl
      uniq := fun s m w => by
        ext x
        

Proof state:
case h
R : Type u
inst✝ : Ring R
J : Type w
f : J → ModuleCat R
s : Cone (Discrete.functor f)
m : s.pt ⟶ { pt := of R ((j : J) → ↑(f j)), π := Discrete.natTrans fun j => LinearMap.proj j.as }.pt
w :
  ∀ (j : Discrete J),
    m ≫ { pt := of R ((j : J) → ↑(f j)), π := Discrete.natTrans fun j => LinearMap.proj j.as }.π.app j = s.π.app j
x : ↑s.pt
⊢ m x = (lift f s) x

Next tactic:
funext j