l3lab/ntp-mathlib huggingface dataset:
theorem integrable_toReal_condexpKernel {s : Set Ω} (hs : MeasurableSet s) :
    Integrable (fun ω => (condexpKernel μ m ω s).toReal) μ := by
  rw [condexpKernel]
  

Proof state:
Ω : Type u_1
F : Type u_2
m mΩ : MeasurableSpace Ω
inst✝³ : StandardBorelSpace Ω
inst✝² : Nonempty Ω
μ : Measure Ω
inst✝¹ : IsFiniteMeasure μ
inst✝ : NormedAddCommGroup F
f : Ω → F
s : Set Ω
hs : MeasurableSet s
⊢ Integrable fun ω => ENNReal.toReal (↑↑((kernel.comap (condDistrib id id μ) id (_ : Measurable id)) ω) s)

Next tactic:
exact integrable_toReal_condDistrib (aemeasurable_id'' μ (inf_le_right : m ⊓ mΩ ≤ mΩ)) hs
lemma condexpKernel_ae_eq_condexp' [IsFiniteMeasure μ] {s : Set Ω} (hs : MeasurableSet s) :
    (fun ω ↦ (condexpKernel μ m ω s).toReal) =ᵐ[μ] μ⟦s | m ⊓ mΩ⟧ := by
  

Proof state:
Ω : Type u_1
F : Type u_2
m mΩ : MeasurableSpace Ω
inst✝³ : StandardBorelSpace Ω
inst✝² : Nonempty Ω
μ : Measure Ω
inst✝¹ inst✝ : IsFiniteMeasure μ
s : Set Ω
hs : MeasurableSet s
⊢ (fun ω => ENNReal.toReal (↑↑((condexpKernel μ m) ω) s)) =ᵐ[μ] μ[indicator s fun ω => 1|m ⊓ mΩ]

Next tactic:
have h := condDistrib_ae_eq_condexp (μ := μ)
    (measurable_id'' (inf_le_right : m ⊓ mΩ ≤ mΩ)) measurable_id hs
lemma condexpKernel_ae_eq_condexp' [IsFiniteMeasure μ] {s : Set Ω} (hs : MeasurableSet s) :
    (fun ω ↦ (condexpKernel μ m ω s).toReal) =ᵐ[μ] μ⟦s | m ⊓ mΩ⟧ := by
  have h := condDistrib_ae_eq_condexp (μ := μ)
    (measurable_id'' (inf_le_right : m ⊓ mΩ ≤ mΩ)) measurable_id hs
  

Proof state:
Ω : Type u_1
F : Type u_2
m mΩ : MeasurableSpace Ω
inst✝³ : StandardBorelSpace Ω
inst✝² : Nonempty Ω
μ : Measure Ω
inst✝¹ inst✝ : IsFiniteMeasure μ
s : Set Ω
hs : MeasurableSet s
h :
  (fun a => ENNReal.toReal (↑↑((condDistrib id id μ) (id a)) s)) =ᵐ[μ]
    μ[indicator (id ⁻¹' s) fun ω => 1|MeasurableSpace.comap id (m ⊓ mΩ)]
⊢ (fun ω => ENNReal.toReal (↑↑((condexpKernel μ m) ω) s)) =ᵐ[μ] μ[indicator s fun ω => 1|m ⊓ mΩ]

Next tactic:
simp only [id_eq, ge_iff_le, MeasurableSpace.comap_id, preimage_id_eq] at h
lemma condexpKernel_ae_eq_condexp' [IsFiniteMeasure μ] {s : Set Ω} (hs : MeasurableSet s) :
    (fun ω ↦ (condexpKernel μ m ω s).toReal) =ᵐ[μ] μ⟦s | m ⊓ mΩ⟧ := by
  have h := condDistrib_ae_eq_condexp (μ := μ)
    (measurable_id'' (inf_le_right : m ⊓ mΩ ≤ mΩ)) measurable_id hs
  simp only [id_eq, ge_iff_le, MeasurableSpace.comap_id, preimage_id_eq] at h
  

Proof state:
Ω : Type u_1
F : Type u_2
m mΩ : MeasurableSpace Ω
inst✝³ : StandardBorelSpace Ω
inst✝² : Nonempty Ω
μ : Measure Ω
inst✝¹ inst✝ : IsFiniteMeasure μ
s : Set Ω
hs : MeasurableSet s
h : (fun a => ENNReal.toReal (↑↑((condDistrib id id μ) a) s)) =ᵐ[μ] μ[indicator s fun ω => 1|m ⊓ mΩ]
⊢ (fun ω => ENNReal.toReal (↑↑((condexpKernel μ m) ω) s)) =ᵐ[μ] μ[indicator s fun ω => 1|m ⊓ mΩ]

Next tactic:
simp_rw [condexpKernel_apply_eq_condDistrib]
lemma condexpKernel_ae_eq_condexp' [IsFiniteMeasure μ] {s : Set Ω} (hs : MeasurableSet s) :
    (fun ω ↦ (condexpKernel μ m ω s).toReal) =ᵐ[μ] μ⟦s | m ⊓ mΩ⟧ := by
  have h := condDistrib_ae_eq_condexp (μ := μ)
    (measurable_id'' (inf_le_right : m ⊓ mΩ ≤ mΩ)) measurable_id hs
  simp only [id_eq, ge_iff_le, MeasurableSpace.comap_id, preimage_id_eq] at h
  simp_rw [condexpKernel_apply_eq_condDistrib]
  

Proof state:
Ω : Type u_1
F : Type u_2
m mΩ : MeasurableSpace Ω
inst✝³ : StandardBorelSpace Ω
inst✝² : Nonempty Ω
μ : Measure Ω
inst✝¹ inst✝ : IsFiniteMeasure μ
s : Set Ω
hs : MeasurableSet s
h : (fun a => ENNReal.toReal (↑↑((condDistrib id id μ) a) s)) =ᵐ[μ] μ[indicator s fun ω => 1|m ⊓ mΩ]
⊢ (fun ω => ENNReal.toReal (↑↑((condDistrib id id μ) (id ω)) s)) =ᵐ[μ] μ[indicator s fun ω => 1|m ⊓ mΩ]

Next tactic:
exact h
lemma condexpKernel_ae_eq_condexp [IsFiniteMeasure μ]
    (hm : m ≤ mΩ) {s : Set Ω} (hs : MeasurableSet s) :
    (fun ω ↦ (condexpKernel μ m ω s).toReal) =ᵐ[μ] μ⟦s | m⟧ :=
  (condexpKernel_ae_eq_condexp' hs).trans (by 

Proof state:
Ω : Type u_1
F : Type u_2
m mΩ : MeasurableSpace Ω
inst✝³ : StandardBorelSpace Ω
inst✝² : Nonempty Ω
μ : Measure Ω
inst✝¹ inst✝ : IsFiniteMeasure μ
hm : m ≤ mΩ
s : Set Ω
hs : MeasurableSet s
⊢ μ[indicator s fun ω => 1|m ⊓ mΩ] =ᵐ[μ] μ[indicator s fun ω => 1|m]

Next tactic:
rw [inf_of_le_left hm]
lemma condexpKernel_ae_eq_trim_condexp [IsFiniteMeasure μ]
    (hm : m ≤ mΩ) {s : Set Ω} (hs : MeasurableSet s) :
    (fun ω ↦ (condexpKernel μ m ω s).toReal) =ᵐ[μ.trim hm] μ⟦s | m⟧ := by
  

Proof state:
Ω : Type u_1
F : Type u_2
m mΩ : MeasurableSpace Ω
inst✝³ : StandardBorelSpace Ω
inst✝² : Nonempty Ω
μ : Measure Ω
inst✝¹ inst✝ : IsFiniteMeasure μ
hm : m ≤ mΩ
s : Set Ω
hs : MeasurableSet s
⊢ (fun ω => ENNReal.toReal (↑↑((condexpKernel μ m) ω) s)) =ᵐ[Measure.trim μ hm] μ[indicator s fun ω => 1|m]

Next tactic:
rw [ae_eq_trim_iff hm _ stronglyMeasurable_condexp]
lemma condexpKernel_ae_eq_trim_condexp [IsFiniteMeasure μ]
    (hm : m ≤ mΩ) {s : Set Ω} (hs : MeasurableSet s) :
    (fun ω ↦ (condexpKernel μ m ω s).toReal) =ᵐ[μ.trim hm] μ⟦s | m⟧ := by
  rw [ae_eq_trim_iff hm _ stronglyMeasurable_condexp]
  · 

Proof state:
Ω : Type u_1
F : Type u_2
m mΩ : MeasurableSpace Ω
inst✝³ : StandardBorelSpace Ω
inst✝² : Nonempty Ω
μ : Measure Ω
inst✝¹ inst✝ : IsFiniteMeasure μ
hm : m ≤ mΩ
s : Set Ω
hs : MeasurableSet s
⊢ (fun ω => ENNReal.toReal (↑↑((condexpKernel μ m) ω) s)) =ᵐ[μ] μ[indicator s fun ω => 1|m]

Next tactic:
exact condexpKernel_ae_eq_condexp hm hs
lemma condexpKernel_ae_eq_trim_condexp [IsFiniteMeasure μ]
    (hm : m ≤ mΩ) {s : Set Ω} (hs : MeasurableSet s) :
    (fun ω ↦ (condexpKernel μ m ω s).toReal) =ᵐ[μ.trim hm] μ⟦s | m⟧ := by
  rw [ae_eq_trim_iff hm _ stronglyMeasurable_condexp]
  · exact condexpKernel_ae_eq_condexp hm hs
  · 

Proof state:
Ω : Type u_1
F : Type u_2
m mΩ : MeasurableSpace Ω
inst✝³ : StandardBorelSpace Ω
inst✝² : Nonempty Ω
μ : Measure Ω
inst✝¹ inst✝ : IsFiniteMeasure μ
hm : m ≤ mΩ
s : Set Ω
hs : MeasurableSet s
⊢ StronglyMeasurable fun ω => ENNReal.toReal (↑↑((condexpKernel μ m) ω) s)

Next tactic:
refine Measurable.stronglyMeasurable ?_
lemma condexpKernel_ae_eq_trim_condexp [IsFiniteMeasure μ]
    (hm : m ≤ mΩ) {s : Set Ω} (hs : MeasurableSet s) :
    (fun ω ↦ (condexpKernel μ m ω s).toReal) =ᵐ[μ.trim hm] μ⟦s | m⟧ := by
  rw [ae_eq_trim_iff hm _ stronglyMeasurable_condexp]
  · exact condexpKernel_ae_eq_condexp hm hs
  · refine Measurable.stronglyMeasurable ?_
    

Proof state:
Ω : Type u_1
F : Type u_2
m mΩ : MeasurableSpace Ω
inst✝³ : StandardBorelSpace Ω
inst✝² : Nonempty Ω
μ : Measure Ω
inst✝¹ inst✝ : IsFiniteMeasure μ
hm : m ≤ mΩ
s : Set Ω
hs : MeasurableSet s
⊢ Measurable fun ω => ENNReal.toReal (↑↑((condexpKernel μ m) ω) s)

Next tactic:
exact @Measurable.ennreal_toReal _ m _ (measurable_condexpKernel hs)
theorem condexp_ae_eq_integral_condexpKernel' [NormedAddCommGroup F] {f : Ω → F}
    [NormedSpace ℝ F] [CompleteSpace F] (hf_int : Integrable f μ) :
    μ[f|m ⊓ mΩ] =ᵐ[μ] fun ω => ∫ y, f y ∂condexpKernel μ m ω := by
  

Proof state:
Ω : Type u_1
F : Type u_2
m mΩ : MeasurableSpace Ω
inst✝⁵ : StandardBorelSpace Ω
inst✝⁴ : Nonempty Ω
μ : Measure Ω
inst✝³ : IsFiniteMeasure μ
inst✝² : NormedAddCommGroup F
f : Ω → F
inst✝¹ : NormedSpace ℝ F
inst✝ : CompleteSpace F
hf_int : Integrable f
⊢ μ[f|m ⊓ mΩ] =ᵐ[μ] fun ω => ∫ (y : Ω), f y ∂(condexpKernel μ m) ω

Next tactic:
have hX : @Measurable Ω Ω mΩ (m ⊓ mΩ) id := measurable_id.mono le_rfl (inf_le_right : m ⊓ mΩ ≤ mΩ)
theorem condexp_ae_eq_integral_condexpKernel' [NormedAddCommGroup F] {f : Ω → F}
    [NormedSpace ℝ F] [CompleteSpace F] (hf_int : Integrable f μ) :
    μ[f|m ⊓ mΩ] =ᵐ[μ] fun ω => ∫ y, f y ∂condexpKernel μ m ω := by
  have hX : @Measurable Ω Ω mΩ (m ⊓ mΩ) id := measurable_id.mono le_rfl (inf_le_right : m ⊓ mΩ ≤ mΩ)
  

Proof state:
Ω : Type u_1
F : Type u_2
m mΩ : MeasurableSpace Ω
inst✝⁵ : StandardBorelSpace Ω
inst✝⁴ : Nonempty Ω
μ : Measure Ω
inst✝³ : IsFiniteMeasure μ
inst✝² : NormedAddCommGroup F
f : Ω → F
inst✝¹ : NormedSpace ℝ F
inst✝ : CompleteSpace F
hf_int : Integrable f
hX : Measurable id
⊢ μ[f|m ⊓ mΩ] =ᵐ[μ] fun ω => ∫ (y : Ω), f y ∂(condexpKernel μ m) ω

Next tactic:
simp_rw [condexpKernel_apply_eq_condDistrib]
theorem condexp_ae_eq_integral_condexpKernel' [NormedAddCommGroup F] {f : Ω → F}
    [NormedSpace ℝ F] [CompleteSpace F] (hf_int : Integrable f μ) :
    μ[f|m ⊓ mΩ] =ᵐ[μ] fun ω => ∫ y, f y ∂condexpKernel μ m ω := by
  have hX : @Measurable Ω Ω mΩ (m ⊓ mΩ) id := measurable_id.mono le_rfl (inf_le_right : m ⊓ mΩ ≤ mΩ)
  simp_rw [condexpKernel_apply_eq_condDistrib]
  

Proof state:
Ω : Type u_1
F : Type u_2
m mΩ : MeasurableSpace Ω
inst✝⁵ : StandardBorelSpace Ω
inst✝⁴ : Nonempty Ω
μ : Measure Ω
inst✝³ : IsFiniteMeasure μ
inst✝² : NormedAddCommGroup F
f : Ω → F
inst✝¹ : NormedSpace ℝ F
inst✝ : CompleteSpace F
hf_int : Integrable f
hX : Measurable id
⊢ μ[f|m ⊓ mΩ] =ᵐ[μ] fun ω => ∫ (y : Ω), f y ∂(condDistrib id id μ) (id ω)

Next tactic:
have h := condexp_ae_eq_integral_condDistrib_id hX hf_int
theorem condexp_ae_eq_integral_condexpKernel' [NormedAddCommGroup F] {f : Ω → F}
    [NormedSpace ℝ F] [CompleteSpace F] (hf_int : Integrable f μ) :
    μ[f|m ⊓ mΩ] =ᵐ[μ] fun ω => ∫ y, f y ∂condexpKernel μ m ω := by
  have hX : @Measurable Ω Ω mΩ (m ⊓ mΩ) id := measurable_id.mono le_rfl (inf_le_right : m ⊓ mΩ ≤ mΩ)
  simp_rw [condexpKernel_apply_eq_condDistrib]
  have h := condexp_ae_eq_integral_condDistrib_id hX hf_int
  

Proof state:
Ω : Type u_1
F : Type u_2
m mΩ : MeasurableSpace Ω
inst✝⁵ : StandardBorelSpace Ω
inst✝⁴ : Nonempty Ω
μ : Measure Ω
inst✝³ : IsFiniteMeasure μ
inst✝² : NormedAddCommGroup F
f : Ω → F
inst✝¹ : NormedSpace ℝ F
inst✝ : CompleteSpace F
hf_int : Integrable f
hX : Measurable id
h : μ[f|MeasurableSpace.comap id (m ⊓ mΩ)] =ᵐ[μ] fun a => ∫ (y : Ω), f y ∂(condDistrib id id μ) (id a)
⊢ μ[f|m ⊓ mΩ] =ᵐ[μ] fun ω => ∫ (y : Ω), f y ∂(condDistrib id id μ) (id ω)

Next tactic:
simpa only [MeasurableSpace.comap_id, id_eq] using h
/-- The conditional expectation of `f` with respect to a σ-algebra `m` is almost everywhere equal to
the integral `∫ y, f y ∂(condexpKernel μ m ω)`. -/
theorem condexp_ae_eq_integral_condexpKernel [NormedAddCommGroup F] {f : Ω → F}
    [NormedSpace ℝ F] [CompleteSpace F] (hm : m ≤ mΩ) (hf_int : Integrable f μ) :
    μ[f|m] =ᵐ[μ] fun ω => ∫ y, f y ∂condexpKernel μ m ω :=
  ((condexp_ae_eq_integral_condexpKernel' hf_int).symm.trans (by 

Proof state:
Ω : Type u_1
F : Type u_2
m mΩ : MeasurableSpace Ω
inst✝⁵ : StandardBorelSpace Ω
inst✝⁴ : Nonempty Ω
μ : Measure Ω
inst✝³ : IsFiniteMeasure μ
inst✝² : NormedAddCommGroup F
f : Ω → F
inst✝¹ : NormedSpace ℝ F
inst✝ : CompleteSpace F
hm : m ≤ mΩ
hf_int : Integrable f
⊢ μ[f|m ⊓ mΩ] =ᵐ[μ] μ[f|m]

Next tactic:
rw [inf_of_le_left hm]
/-- Given two presheaves `F` and `G` on a category `C` with values in a category `A`,
this `presheafHom F G` is the presheaf of types which sends an object `X : C`
to the type of morphisms between the "restrictions" of `F` and `G` to the category `Over X`. -/
@[simps! obj]
def presheafHom : Cᵒᵖ ⥤ Type _ where
  obj X := (Over.forget X.unop).op ⋙ F ⟶ (Over.forget X.unop).op ⋙ G
  map f := whiskerLeft (Over.map f.unop).op
  map_id := by
    

Proof state:
C : Type u
inst✝¹ : Category.{v, u} C
J : GrothendieckTopology C
A : Type u'
inst✝ : Category.{v', u'} A
F G : Cᵒᵖ ⥤ A
⊢ ∀ (X : Cᵒᵖ),
    { obj := fun X => (Over.forget X.unop).op ⋙ F ⟶ (Over.forget X.unop).op ⋙ G,
            map := fun {X Y} f => whiskerLeft (Over.map f.unop).op }.map
        (𝟙 X) =
      𝟙
        ({ obj := fun X => (Over.forget X.unop).op ⋙ F ⟶ (Over.forget X.unop).op ⋙ G,
              map := fun {X Y} f => whiskerLeft (Over.map f.unop).op }.obj
          X)

Next tactic:
rintro ⟨X⟩
/-- Given two presheaves `F` and `G` on a category `C` with values in a category `A`,
this `presheafHom F G` is the presheaf of types which sends an object `X : C`
to the type of morphisms between the "restrictions" of `F` and `G` to the category `Over X`. -/
@[simps! obj]
def presheafHom : Cᵒᵖ ⥤ Type _ where
  obj X := (Over.forget X.unop).op ⋙ F ⟶ (Over.forget X.unop).op ⋙ G
  map f := whiskerLeft (Over.map f.unop).op
  map_id := by
    rintro ⟨X⟩
    

Proof state:
case mk
C : Type u
inst✝¹ : Category.{v, u} C
J : GrothendieckTopology C
A : Type u'
inst✝ : Category.{v', u'} A
F G : Cᵒᵖ ⥤ A
X : C
⊢ { obj := fun X => (Over.forget X.unop).op ⋙ F ⟶ (Over.forget X.unop).op ⋙ G,
          map := fun {X Y} f => whiskerLeft (Over.map f.unop).op }.map
      (𝟙 { unop := X }) =
    𝟙
      ({ obj := fun X => (Over.forget X.unop).op ⋙ F ⟶ (Over.forget X.unop).op ⋙ G,
            map := fun {X Y} f => whiskerLeft (Over.map f.unop).op }.obj
        { unop := X })

Next tactic:
ext φ ⟨Y⟩
/-- Given two presheaves `F` and `G` on a category `C` with values in a category `A`,
this `presheafHom F G` is the presheaf of types which sends an object `X : C`
to the type of morphisms between the "restrictions" of `F` and `G` to the category `Over X`. -/
@[simps! obj]
def presheafHom : Cᵒᵖ ⥤ Type _ where
  obj X := (Over.forget X.unop).op ⋙ F ⟶ (Over.forget X.unop).op ⋙ G
  map f := whiskerLeft (Over.map f.unop).op
  map_id := by
    rintro ⟨X⟩
    ext φ ⟨Y⟩
    

Proof state:
case mk.h.w.h.mk
C : Type u
inst✝¹ : Category.{v, u} C
J : GrothendieckTopology C
A : Type u'
inst✝ : Category.{v', u'} A
F G : Cᵒᵖ ⥤ A
X : C
φ :
  { obj := fun X => (Over.forget X.unop).op ⋙ F ⟶ (Over.forget X.unop).op ⋙ G,
        map := fun {X Y} f => whiskerLeft (Over.map f.unop).op }.obj
    { unop := X }
Y : Over { unop := X }.unop
⊢ ({ obj := fun X => (Over.forget X.unop).op ⋙ F ⟶ (Over.forget X.unop).op ⋙ G,
              map := fun {X Y} f => whiskerLeft (Over.map f.unop).op }.map
          (𝟙 { unop := X }) φ).app
      { unop := Y } =
    (𝟙
          ({ obj := fun X => (Over.forget X.unop).op ⋙ F ⟶ (Over.forget X.unop).op ⋙ G,
                map := fun {X Y} f => whiskerLeft (Over.map f.unop).op }.obj
            { unop := X })
          φ).app
      { unop := Y }

Next tactic:
simpa [Over.mapId] using φ.naturality ((Over.mapId X).hom.app Y).op
/-- Given two presheaves `F` and `G` on a category `C` with values in a category `A`,
this `presheafHom F G` is the presheaf of types which sends an object `X : C`
to the type of morphisms between the "restrictions" of `F` and `G` to the category `Over X`. -/
@[simps! obj]
def presheafHom : Cᵒᵖ ⥤ Type _ where
  obj X := (Over.forget X.unop).op ⋙ F ⟶ (Over.forget X.unop).op ⋙ G
  map f := whiskerLeft (Over.map f.unop).op
  map_id := by
    rintro ⟨X⟩
    ext φ ⟨Y⟩
    simpa [Over.mapId] using φ.naturality ((Over.mapId X).hom.app Y).op
  map_comp := by
    

Proof state:
C : Type u
inst✝¹ : Category.{v, u} C
J : GrothendieckTopology C
A : Type u'
inst✝ : Category.{v', u'} A
F G : Cᵒᵖ ⥤ A
⊢ ∀ {X Y Z : Cᵒᵖ} (f : X ⟶ Y) (g : Y ⟶ Z),
    { obj := fun X => (Over.forget X.unop).op ⋙ F ⟶ (Over.forget X.unop).op ⋙ G,
            map := fun {X Y} f => whiskerLeft (Over.map f.unop).op }.map
        (f ≫ g) =
      { obj := fun X => (Over.forget X.unop).op ⋙ F ⟶ (Over.forget X.unop).op ⋙ G,
              map := fun {X Y} f => whiskerLeft (Over.map f.unop).op }.map
          f ≫
        { obj := fun X => (Over.forget X.unop).op ⋙ F ⟶ (Over.forget X.unop).op ⋙ G,
              map := fun {X Y} f => whiskerLeft (Over.map f.unop).op }.map
          g

Next tactic:
rintro ⟨X⟩ ⟨Y⟩ ⟨Z⟩ ⟨f : Y ⟶ X⟩ ⟨g : Z ⟶ Y⟩
/-- Given two presheaves `F` and `G` on a category `C` with values in a category `A`,
this `presheafHom F G` is the presheaf of types which sends an object `X : C`
to the type of morphisms between the "restrictions" of `F` and `G` to the category `Over X`. -/
@[simps! obj]
def presheafHom : Cᵒᵖ ⥤ Type _ where
  obj X := (Over.forget X.unop).op ⋙ F ⟶ (Over.forget X.unop).op ⋙ G
  map f := whiskerLeft (Over.map f.unop).op
  map_id := by
    rintro ⟨X⟩
    ext φ ⟨Y⟩
    simpa [Over.mapId] using φ.naturality ((Over.mapId X).hom.app Y).op
  map_comp := by
    rintro ⟨X⟩ ⟨Y⟩ ⟨Z⟩ ⟨f : Y ⟶ X⟩ ⟨g : Z ⟶ Y⟩
    

Proof state:
case mk.mk.mk.mk.mk
C : Type u
inst✝¹ : Category.{v, u} C
J : GrothendieckTopology C
A : Type u'
inst✝ : Category.{v', u'} A
F G : Cᵒᵖ ⥤ A
X Y Z : C
f : Y ⟶ X
g : Z ⟶ Y
⊢ { obj := fun X => (Over.forget X.unop).op ⋙ F ⟶ (Over.forget X.unop).op ⋙ G,
          map := fun {X Y} f => whiskerLeft (Over.map f.unop).op }.map
      ({ unop := f } ≫ { unop := g }) =
    { obj := fun X => (Over.forget X.unop).op ⋙ F ⟶ (Over.forget X.unop).op ⋙ G,
            map := fun {X Y} f => whiskerLeft (Over.map f.unop).op }.map
        { unop := f } ≫
      { obj := fun X => (Over.forget X.unop).op ⋙ F ⟶ (Over.forget X.unop).op ⋙ G,
            map := fun {X Y} f => whiskerLeft (Over.map f.unop).op }.map
        { unop := g }

Next tactic:
ext φ ⟨W⟩
/-- Given two presheaves `F` and `G` on a category `C` with values in a category `A`,
this `presheafHom F G` is the presheaf of types which sends an object `X : C`
to the type of morphisms between the "restrictions" of `F` and `G` to the category `Over X`. -/
@[simps! obj]
def presheafHom : Cᵒᵖ ⥤ Type _ where
  obj X := (Over.forget X.unop).op ⋙ F ⟶ (Over.forget X.unop).op ⋙ G
  map f := whiskerLeft (Over.map f.unop).op
  map_id := by
    rintro ⟨X⟩
    ext φ ⟨Y⟩
    simpa [Over.mapId] using φ.naturality ((Over.mapId X).hom.app Y).op
  map_comp := by
    rintro ⟨X⟩ ⟨Y⟩ ⟨Z⟩ ⟨f : Y ⟶ X⟩ ⟨g : Z ⟶ Y⟩
    ext φ ⟨W⟩
    

Proof state:
case mk.mk.mk.mk.mk.h.w.h.mk
C : Type u
inst✝¹ : Category.{v, u} C
J : GrothendieckTopology C
A : Type u'
inst✝ : Category.{v', u'} A
F G : Cᵒᵖ ⥤ A
X Y Z : C
f : Y ⟶ X
g : Z ⟶ Y
φ :
  { obj := fun X => (Over.forget X.unop).op ⋙ F ⟶ (Over.forget X.unop).op ⋙ G,
        map := fun {X Y} f => whiskerLeft (Over.map f.unop).op }.obj
    { unop := X }
W : Over { unop := Z }.unop
⊢ ({ obj := fun X => (Over.forget X.unop).op ⋙ F ⟶ (Over.forget X.unop).op ⋙ G,
              map := fun {X Y} f => whiskerLeft (Over.map f.unop).op }.map
          ({ unop := f } ≫ { unop := g }) φ).app
      { unop := W } =
    (({ obj := fun X => (Over.forget X.unop).op ⋙ F ⟶ (Over.forget X.unop).op ⋙ G,
                  map := fun {X Y} f => whiskerLeft (Over.map f.unop).op }.map
              { unop := f } ≫
            { obj := fun X => (Over.forget X.unop).op ⋙ F ⟶ (Over.forget X.unop).op ⋙ G,
                  map := fun {X Y} f => whiskerLeft (Over.map f.unop).op }.map
              { unop := g })
          φ).app
      { unop := W }

Next tactic:
simpa [Over.mapComp] using φ.naturality ((Over.mapComp g f).hom.app W).op
/-- Equational lemma for the presheaf structure on `presheafHom`.
It is advisable to use this lemma rather than `dsimp [presheafHom]` which may result
in the need to prove equalities of objects in an `Over` category. -/
lemma presheafHom_map_app {X Y Z : C} (f : Z ⟶ Y) (g : Y ⟶ X) (h : Z ⟶ X) (w : f ≫ g = h)
    (α : (presheafHom F G).obj (op X)) :
    ((presheafHom F G).map g.op α).app (op (Over.mk f)) =
      α.app (op (Over.mk h)) := by
  

Proof state:
C : Type u
inst✝¹ : Category.{v, u} C
J : GrothendieckTopology C
A : Type u'
inst✝ : Category.{v', u'} A
F G : Cᵒᵖ ⥤ A
X Y Z : C
f : Z ⟶ Y
g : Y ⟶ X
h : Z ⟶ X
w : f ≫ g = h
α : (presheafHom F G).obj (op X)
⊢ ((presheafHom F G).map g.op α).app (op (Over.mk f)) = α.app (op (Over.mk h))

Next tactic:
subst w
/-- Equational lemma for the presheaf structure on `presheafHom`.
It is advisable to use this lemma rather than `dsimp [presheafHom]` which may result
in the need to prove equalities of objects in an `Over` category. -/
lemma presheafHom_map_app {X Y Z : C} (f : Z ⟶ Y) (g : Y ⟶ X) (h : Z ⟶ X) (w : f ≫ g = h)
    (α : (presheafHom F G).obj (op X)) :
    ((presheafHom F G).map g.op α).app (op (Over.mk f)) =
      α.app (op (Over.mk h)) := by
  subst w
  

Proof state:
C : Type u
inst✝¹ : Category.{v, u} C
J : GrothendieckTopology C
A : Type u'
inst✝ : Category.{v', u'} A
F G : Cᵒᵖ ⥤ A
X Y Z : C
f : Z ⟶ Y
g : Y ⟶ X
α : (presheafHom F G).obj (op X)
⊢ ((presheafHom F G).map g.op α).app (op (Over.mk f)) = α.app (op (Over.mk (f ≫ g)))

Next tactic:
rfl
@[simp]
lemma presheafHom_map_app_op_mk_id {X Y : C} (g : Y ⟶ X)
    (α : (presheafHom F G).obj (op X)) :
    ((presheafHom F G).map g.op α).app (op (Over.mk (𝟙 Y))) =
      α.app (op (Over.mk g)) :=
  presheafHom_map_app (𝟙 Y) g g (by 

Proof state:
C : Type u
inst✝¹ : Category.{v, u} C
J : GrothendieckTopology C
A : Type u'
inst✝ : Category.{v', u'} A
F G : Cᵒᵖ ⥤ A
X Y : C
g : Y ⟶ X
α : (presheafHom F G).obj (op X)
⊢ 𝟙 Y ≫ g = g

Next tactic:
simp
/-- The sections of the presheaf `presheafHom F G` identify to morphisms `F ⟶ G`. -/
def presheafHomSectionsEquiv : (presheafHom F G).sections ≃ (F ⟶ G) where
  toFun s :=
    { app := fun X => (s.1 X).app ⟨Over.mk (𝟙 _)⟩
      naturality := by
        

Proof state:
C : Type u
inst✝¹ : Category.{v, u} C
J : GrothendieckTopology C
A : Type u'
inst✝ : Category.{v', u'} A
F G : Cᵒᵖ ⥤ A
s : ↑(Functor.sections (presheafHom F G))
⊢ ∀ ⦃X Y : Cᵒᵖ⦄ (f : X ⟶ Y),
    F.map f ≫ (fun X => (↑s X).app { unop := Over.mk (𝟙 X.unop) }) Y =
      (fun X => (↑s X).app { unop := Over.mk (𝟙 X.unop) }) X ≫ G.map f

Next tactic:
rintro ⟨X₁⟩ ⟨X₂⟩ ⟨f : X₂ ⟶ X₁⟩
/-- The sections of the presheaf `presheafHom F G` identify to morphisms `F ⟶ G`. -/
def presheafHomSectionsEquiv : (presheafHom F G).sections ≃ (F ⟶ G) where
  toFun s :=
    { app := fun X => (s.1 X).app ⟨Over.mk (𝟙 _)⟩
      naturality := by
        rintro ⟨X₁⟩ ⟨X₂⟩ ⟨f : X₂ ⟶ X₁⟩
        

Proof state:
case mk.mk.mk
C : Type u
inst✝¹ : Category.{v, u} C
J : GrothendieckTopology C
A : Type u'
inst✝ : Category.{v', u'} A
F G : Cᵒᵖ ⥤ A
s : ↑(Functor.sections (presheafHom F G))
X₁ X₂ : C
f : X₂ ⟶ X₁
⊢ F.map { unop := f } ≫ (fun X => (↑s X).app { unop := Over.mk (𝟙 X.unop) }) { unop := X₂ } =
    (fun X => (↑s X).app { unop := Over.mk (𝟙 X.unop) }) { unop := X₁ } ≫ G.map { unop := f }

Next tactic:
dsimp
/-- The sections of the presheaf `presheafHom F G` identify to morphisms `F ⟶ G`. -/
def presheafHomSectionsEquiv : (presheafHom F G).sections ≃ (F ⟶ G) where
  toFun s :=
    { app := fun X => (s.1 X).app ⟨Over.mk (𝟙 _)⟩
      naturality := by
        rintro ⟨X₁⟩ ⟨X₂⟩ ⟨f : X₂ ⟶ X₁⟩
        dsimp
        

Proof state:
case mk.mk.mk
C : Type u
inst✝¹ : Category.{v, u} C
J : GrothendieckTopology C
A : Type u'
inst✝ : Category.{v', u'} A
F G : Cᵒᵖ ⥤ A
s : ↑(Functor.sections (presheafHom F G))
X₁ X₂ : C
f : X₂ ⟶ X₁
⊢ F.map { unop := f } ≫ (↑s { unop := X₂ }).app { unop := Over.mk (𝟙 X₂) } =
    (↑s { unop := X₁ }).app { unop := Over.mk (𝟙 X₁) } ≫ G.map { unop := f }

Next tactic:
refine' Eq.trans _ ((s.1 ⟨X₁⟩).naturality
          (Over.homMk f : Over.mk f ⟶ Over.mk (𝟙 X₁)).op)
/-- The sections of the presheaf `presheafHom F G` identify to morphisms `F ⟶ G`. -/
def presheafHomSectionsEquiv : (presheafHom F G).sections ≃ (F ⟶ G) where
  toFun s :=
    { app := fun X => (s.1 X).app ⟨Over.mk (𝟙 _)⟩
      naturality := by
        rintro ⟨X₁⟩ ⟨X₂⟩ ⟨f : X₂ ⟶ X₁⟩
        dsimp
        refine' Eq.trans _ ((s.1 ⟨X₁⟩).naturality
          (Over.homMk f : Over.mk f ⟶ Over.mk (𝟙 X₁)).op)
        

Proof state:
case mk.mk.mk
C : Type u
inst✝¹ : Category.{v, u} C
J : GrothendieckTopology C
A : Type u'
inst✝ : Category.{v', u'} A
F G : Cᵒᵖ ⥤ A
s : ↑(Functor.sections (presheafHom F G))
X₁ X₂ : C
f : X₂ ⟶ X₁
⊢ F.map { unop := f } ≫ (↑s { unop := X₂ }).app { unop := Over.mk (𝟙 X₂) } =
    ((Over.forget { unop := X₁ }.unop).op ⋙ F).map (Over.homMk f).op ≫ (↑s { unop := X₁ }).app (op (Over.mk f))

Next tactic:
erw [← s.2 f.op, presheafHom_map_app_op_mk_id]
/-- The sections of the presheaf `presheafHom F G` identify to morphisms `F ⟶ G`. -/
def presheafHomSectionsEquiv : (presheafHom F G).sections ≃ (F ⟶ G) where
  toFun s :=
    { app := fun X => (s.1 X).app ⟨Over.mk (𝟙 _)⟩
      naturality := by
        rintro ⟨X₁⟩ ⟨X₂⟩ ⟨f : X₂ ⟶ X₁⟩
        dsimp
        refine' Eq.trans _ ((s.1 ⟨X₁⟩).naturality
          (Over.homMk f : Over.mk f ⟶ Over.mk (𝟙 X₁)).op)
        erw [← s.2 f.op, presheafHom_map_app_op_mk_id]
        

Proof state:
case mk.mk.mk
C : Type u
inst✝¹ : Category.{v, u} C
J : GrothendieckTopology C
A : Type u'
inst✝ : Category.{v', u'} A
F G : Cᵒᵖ ⥤ A
s : ↑(Functor.sections (presheafHom F G))
X₁ X₂ : C
f : X₂ ⟶ X₁
⊢ F.map { unop := f } ≫ (↑s (op X₁)).app (op (Over.mk f)) =
    ((Over.forget { unop := X₁ }.unop).op ⋙ F).map (Over.homMk f).op ≫ (↑s { unop := X₁ }).app (op (Over.mk f))

Next tactic:
rfl