l3lab/ntp-mathlib huggingface dataset:
/-- If `a` is a left identity for `f : α → β → β`, then `pure a` is a left identity for
`Filter.map₂ f`. -/
theorem map₂_left_identity {f : α → β → β} {a : α} (h : ∀ b, f a b = b) (l : Filter β) :
    map₂ f (pure a) l = l := by 

Proof state:
α : Type u_1
α' : Type u_2
β : Type u_3
β' : Type u_4
γ : Type u_5
γ' : Type u_6
δ : Type u_7
δ' : Type u_8
ε : Type u_9
ε' : Type u_10
m : α → β → γ
f✝ f₁ f₂ : Filter α
g g₁ g₂ : Filter β
h✝ h₁ h₂ : Filter γ
s s₁ s₂ : Set α
t t₁ t₂ : Set β
u : Set γ
v : Set δ
a✝ : α
b : β
c : γ
f : α → β → β
a : α
h : ∀ (b : β), f a b = b
l : Filter β
⊢ map₂ f (pure a) l = l

Next tactic:
rw [map₂_pure_left, show f a = id from funext h, map_id]
/-- If `b` is a right identity for `f : α → β → α`, then `pure b` is a right identity for
`Filter.map₂ f`. -/
theorem map₂_right_identity {f : α → β → α} {b : β} (h : ∀ a, f a b = a) (l : Filter α) :
    map₂ f l (pure b) = l := by 

Proof state:
α : Type u_1
α' : Type u_2
β : Type u_3
β' : Type u_4
γ : Type u_5
γ' : Type u_6
δ : Type u_7
δ' : Type u_8
ε : Type u_9
ε' : Type u_10
m : α → β → γ
f✝ f₁ f₂ : Filter α
g g₁ g₂ : Filter β
h✝ h₁ h₂ : Filter γ
s s₁ s₂ : Set α
t t₁ t₂ : Set β
u : Set γ
v : Set δ
a : α
b✝ : β
c : γ
f : α → β → α
b : β
h : ∀ (a : α), f a b = a
l : Filter α
⊢ map₂ f l (pure b) = l

Next tactic:
rw [map₂_pure_right, funext h, map_id']
instance [RepresentablyFlat G] : PreservesFiniteLimits (G.sheafPullback A J K) := by
  

Proof state:
C : Type v₁
inst✝⁹ : SmallCategory C
D : Type v₁
inst✝⁸ : SmallCategory D
G : C ⥤ D
A : Type u₁
inst✝⁷ : Category.{v₁, u₁} A
J : GrothendieckTopology C
K : GrothendieckTopology D
inst✝⁶ : ConcreteCategory A
inst✝⁵ : PreservesLimits (forget A)
inst✝⁴ : HasColimits A
inst✝³ : HasLimits A
inst✝² : PreservesFilteredColimits (forget A)
inst✝¹ : ReflectsIsomorphisms (forget A)
inst✝ : RepresentablyFlat G
⊢ PreservesFiniteLimits (Functor.sheafPullback G A J K)

Next tactic:
have : PreservesFiniteLimits (lan (Functor.op G) ⋙ presheafToSheaf K A) :=
    compPreservesFiniteLimits _ _
instance [RepresentablyFlat G] : PreservesFiniteLimits (G.sheafPullback A J K) := by
  have : PreservesFiniteLimits (lan (Functor.op G) ⋙ presheafToSheaf K A) :=
    compPreservesFiniteLimits _ _
  

Proof state:
C : Type v₁
inst✝⁹ : SmallCategory C
D : Type v₁
inst✝⁸ : SmallCategory D
G : C ⥤ D
A : Type u₁
inst✝⁷ : Category.{v₁, u₁} A
J : GrothendieckTopology C
K : GrothendieckTopology D
inst✝⁶ : ConcreteCategory A
inst✝⁵ : PreservesLimits (forget A)
inst✝⁴ : HasColimits A
inst✝³ : HasLimits A
inst✝² : PreservesFilteredColimits (forget A)
inst✝¹ : ReflectsIsomorphisms (forget A)
inst✝ : RepresentablyFlat G
this : PreservesFiniteLimits (lan G.op ⋙ presheafToSheaf K A)
⊢ PreservesFiniteLimits (Functor.sheafPullback G A J K)

Next tactic:
apply compPreservesFiniteLimits
/-- The concrete product cone is limiting. -/
def productConeIsLimit : IsLimit (productCone Z) where
  lift s := (LinearMap.pi fun j => s.π.app ⟨j⟩ : s.pt →ₗ[R] ∀ i : ι, Z i)
  fac s j := by
    

Proof state:
R : Type u
inst✝ : Ring R
ι : Type v
Z : ι → ModuleCatMax R
s : Cone (Discrete.functor Z)
j : Discrete ι
⊢ (fun s => LinearMap.pi fun j => s.π.app { as := j }) s ≫ (productCone Z).π.app j = s.π.app j

Next tactic:
cases j
/-- The concrete product cone is limiting. -/
def productConeIsLimit : IsLimit (productCone Z) where
  lift s := (LinearMap.pi fun j => s.π.app ⟨j⟩ : s.pt →ₗ[R] ∀ i : ι, Z i)
  fac s j := by
    cases j
    

Proof state:
case mk
R : Type u
inst✝ : Ring R
ι : Type v
Z : ι → ModuleCatMax R
s : Cone (Discrete.functor Z)
as✝ : ι
⊢ (fun s => LinearMap.pi fun j => s.π.app { as := j }) s ≫ (productCone Z).π.app { as := as✝ } = s.π.app { as := as✝ }

Next tactic:
aesop
/-- The concrete product cone is limiting. -/
def productConeIsLimit : IsLimit (productCone Z) where
  lift s := (LinearMap.pi fun j => s.π.app ⟨j⟩ : s.pt →ₗ[R] ∀ i : ι, Z i)
  fac s j := by
    cases j
    aesop
  uniq s m w := by
    

Proof state:
R : Type u
inst✝ : Ring R
ι : Type v
Z : ι → ModuleCatMax R
s : Cone (Discrete.functor Z)
m : s.pt ⟶ (productCone Z).pt
w : ∀ (j : Discrete ι), m ≫ (productCone Z).π.app j = s.π.app j
⊢ m = (fun s => LinearMap.pi fun j => s.π.app { as := j }) s

Next tactic:
ext x
/-- The concrete product cone is limiting. -/
def productConeIsLimit : IsLimit (productCone Z) where
  lift s := (LinearMap.pi fun j => s.π.app ⟨j⟩ : s.pt →ₗ[R] ∀ i : ι, Z i)
  fac s j := by
    cases j
    aesop
  uniq s m w := by
    ext x
    

Proof state:
case h
R : Type u
inst✝ : Ring R
ι : Type v
Z : ι → ModuleCatMax R
s : Cone (Discrete.functor Z)
m : s.pt ⟶ (productCone Z).pt
w : ∀ (j : Discrete ι), m ≫ (productCone Z).π.app j = s.π.app j
x : ↑s.pt
⊢ m x = ((fun s => LinearMap.pi fun j => s.π.app { as := j }) s) x

Next tactic:
funext i
/-- The concrete product cone is limiting. -/
def productConeIsLimit : IsLimit (productCone Z) where
  lift s := (LinearMap.pi fun j => s.π.app ⟨j⟩ : s.pt →ₗ[R] ∀ i : ι, Z i)
  fac s j := by
    cases j
    aesop
  uniq s m w := by
    ext x
    funext i
    

Proof state:
case h.h
R : Type u
inst✝ : Ring R
ι : Type v
Z : ι → ModuleCatMax R
s : Cone (Discrete.functor Z)
m : s.pt ⟶ (productCone Z).pt
w : ∀ (j : Discrete ι), m ≫ (productCone Z).π.app j = s.π.app j
x : ↑s.pt
i : ι
⊢ m x i = ((fun s => LinearMap.pi fun j => s.π.app { as := j }) s) x i

Next tactic:
exact LinearMap.congr_fun (w ⟨i⟩) x
protected nonrec theorem HasDerivAtFilter.star (h : HasDerivAtFilter f f' x L) :
    HasDerivAtFilter (fun x => star (f x)) (star f') x L := by
  

Proof state:
𝕜 : Type u
inst✝⁷ : NontriviallyNormedField 𝕜
F : Type v
inst✝⁶ : NormedAddCommGroup F
inst✝⁵ : NormedSpace 𝕜 F
f : 𝕜 → F
inst✝⁴ : StarRing 𝕜
inst✝³ : TrivialStar 𝕜
inst✝² : StarAddMonoid F
inst✝¹ : ContinuousStar F
inst✝ : StarModule 𝕜 F
f' : F
x : 𝕜
L : Filter 𝕜
h : HasDerivAtFilter f f' x L
⊢ HasDerivAtFilter (fun x => star (f x)) (star f') x L

Next tactic:
simpa using h.star.hasDerivAtFilter
protected nonrec theorem HasStrictDerivAt.star (h : HasStrictDerivAt f f' x) :
    HasStrictDerivAt (fun x => star (f x)) (star f') x := by 

Proof state:
𝕜 : Type u
inst✝⁷ : NontriviallyNormedField 𝕜
F : Type v
inst✝⁶ : NormedAddCommGroup F
inst✝⁵ : NormedSpace 𝕜 F
f : 𝕜 → F
inst✝⁴ : StarRing 𝕜
inst✝³ : TrivialStar 𝕜
inst✝² : StarAddMonoid F
inst✝¹ : ContinuousStar F
inst✝ : StarModule 𝕜 F
f' : F
x : 𝕜
h : HasStrictDerivAt f f' x
⊢ HasStrictDerivAt (fun x => star (f x)) (star f') x

Next tactic:
simpa using h.star.hasStrictDerivAt
instance inhabitedCone (F : Discrete PUnit ⥤ C) : Inhabited (Cone F) :=
  ⟨{  pt := F.obj ⟨⟨⟩⟩
      π := { app := fun ⟨⟨⟩⟩ => 𝟙 _
             naturality := by
              

Proof state:
J : Type u₁
inst✝³ : Category.{v₁, u₁} J
K : Type u₂
inst✝² : Category.{v₂, u₂} K
C : Type u₃
inst✝¹ : Category.{v₃, u₃} C
D : Type u₄
inst✝ : Category.{v₄, u₄} D
F : Discrete PUnit.{?u.11220 + 1} ⥤ C
⊢ ∀ ⦃X Y : Discrete PUnit.{?u.11220 + 1}⦄ (f : X ⟶ Y),
    ((const (Discrete PUnit.{?u.11220 + 1})).obj (F.obj { as := PUnit.unit })).map f ≫
        (fun x =>
            match x with
            | { as := PUnit.unit } =>
              𝟙 (((const (Discrete PUnit.{?u.11220 + 1})).obj (F.obj { as := PUnit.unit })).obj { as := PUnit.unit }))
          Y =
      (fun x =>
            match x with
            | { as := PUnit.unit } =>
              𝟙 (((const (Discrete PUnit.{?u.11220 + 1})).obj (F.obj { as := PUnit.unit })).obj { as := PUnit.unit }))
          X ≫
        F.map f

Next tactic:
intro X Y f
instance inhabitedCone (F : Discrete PUnit ⥤ C) : Inhabited (Cone F) :=
  ⟨{  pt := F.obj ⟨⟨⟩⟩
      π := { app := fun ⟨⟨⟩⟩ => 𝟙 _
             naturality := by
              intro X Y f
              

Proof state:
J : Type u₁
inst✝³ : Category.{v₁, u₁} J
K : Type u₂
inst✝² : Category.{v₂, u₂} K
C : Type u₃
inst✝¹ : Category.{v₃, u₃} C
D : Type u₄
inst✝ : Category.{v₄, u₄} D
F : Discrete PUnit.{?u.11220 + 1} ⥤ C
X Y : Discrete PUnit.{?u.11220 + 1}
f : X ⟶ Y
⊢ ((const (Discrete PUnit.{?u.11220 + 1})).obj (F.obj { as := PUnit.unit })).map f ≫
      (fun x =>
          match x with
          | { as := PUnit.unit } =>
            𝟙 (((const (Discrete PUnit.{?u.11220 + 1})).obj (F.obj { as := PUnit.unit })).obj { as := PUnit.unit }))
        Y =
    (fun x =>
          match x with
          | { as := PUnit.unit } =>
            𝟙 (((const (Discrete PUnit.{?u.11220 + 1})).obj (F.obj { as := PUnit.unit })).obj { as := PUnit.unit }))
        X ≫
      F.map f

Next tactic:
match X, Y, f with
              | .mk A, .mk B, .up g =>
                aesop_cat
instance inhabitedCone (F : Discrete PUnit ⥤ C) : Inhabited (Cone F) :=
  ⟨{  pt := F.obj ⟨⟨⟩⟩
      π := { app := fun ⟨⟨⟩⟩ => 𝟙 _
             naturality := by
              intro X Y f
              match X, Y, f with
              | .mk A, .mk B, .up g =>
                

Proof state:
J : Type u₁
inst✝³ : Category.{v₁, u₁} J
K : Type u₂
inst✝² : Category.{v₂, u₂} K
C : Type u₃
inst✝¹ : Category.{v₃, u₃} C
D : Type u₄
inst✝ : Category.{v₄, u₄} D
F : Discrete PUnit.{?u.11685 + 1} ⥤ C
X Y : Discrete PUnit.{?u.11685 + 1}
f : X ⟶ Y
A B : PUnit.{?u.11685 + 1}
g : PLift ({ as := A }.as = { as := B }.as)
⊢ ((const (Discrete PUnit.{?u.11685 + 1})).obj (F.obj { as := PUnit.unit })).map { down := g } ≫
      (fun x =>
          match x with
          | { as := PUnit.unit } =>
            𝟙 (((const (Discrete PUnit.{?u.11685 + 1})).obj (F.obj { as := PUnit.unit })).obj { as := PUnit.unit }))
        { as := B } =
    (fun x =>
          match x with
          | { as := PUnit.unit } =>
            𝟙 (((const (Discrete PUnit.{?u.11685 + 1})).obj (F.obj { as := PUnit.unit })).obj { as := PUnit.unit }))
        { as := A } ≫
      F.map { down := g }

Next tactic:
aesop_cat
@[reassoc (attr := simp)]
theorem Cone.w {F : J ⥤ C} (c : Cone F) {j j' : J} (f : j ⟶ j') :
    c.π.app j ≫ F.map f = c.π.app j' := by
  

Proof state:
J : Type u₁
inst✝³ : Category.{v₁, u₁} J
K : Type u₂
inst✝² : Category.{v₂, u₂} K
C : Type u₃
inst✝¹ : Category.{v₃, u₃} C
D : Type u₄
inst✝ : Category.{v₄, u₄} D
F : J ⥤ C
c : Cone F
j j' : J
f : j ⟶ j'
⊢ c.π.app j ≫ F.map f = c.π.app j'

Next tactic:
rw [← c.π.naturality f]
@[reassoc (attr := simp)]
theorem Cone.w {F : J ⥤ C} (c : Cone F) {j j' : J} (f : j ⟶ j') :
    c.π.app j ≫ F.map f = c.π.app j' := by
  rw [← c.π.naturality f]
  

Proof state:
J : Type u₁
inst✝³ : Category.{v₁, u₁} J
K : Type u₂
inst✝² : Category.{v₂, u₂} K
C : Type u₃
inst✝¹ : Category.{v₃, u₃} C
D : Type u₄
inst✝ : Category.{v₄, u₄} D
F : J ⥤ C
c : Cone F
j j' : J
f : j ⟶ j'
⊢ ((const J).obj c.pt).map f ≫ c.π.app j' = c.π.app j'

Next tactic:
apply id_comp
instance inhabitedCocone (F : Discrete PUnit ⥤ C) : Inhabited (Cocone F) :=
  ⟨{  pt := F.obj ⟨⟨⟩⟩
      ι := { app := fun ⟨⟨⟩⟩ => 𝟙 _
             naturality := by
              

Proof state:
J : Type u₁
inst✝³ : Category.{v₁, u₁} J
K : Type u₂
inst✝² : Category.{v₂, u₂} K
C : Type u₃
inst✝¹ : Category.{v₃, u₃} C
D : Type u₄
inst✝ : Category.{v₄, u₄} D
F : Discrete PUnit.{?u.14910 + 1} ⥤ C
⊢ ∀ ⦃X Y : Discrete PUnit.{?u.14910 + 1}⦄ (f : X ⟶ Y),
    F.map f ≫
        (fun x =>
            match x with
            | { as := PUnit.unit } => 𝟙 (F.obj { as := PUnit.unit }))
          Y =
      (fun x =>
            match x with
            | { as := PUnit.unit } => 𝟙 (F.obj { as := PUnit.unit }))
          X ≫
        ((const (Discrete PUnit.{?u.14910 + 1})).obj (F.obj { as := PUnit.unit })).map f

Next tactic:
intro X Y f
instance inhabitedCocone (F : Discrete PUnit ⥤ C) : Inhabited (Cocone F) :=
  ⟨{  pt := F.obj ⟨⟨⟩⟩
      ι := { app := fun ⟨⟨⟩⟩ => 𝟙 _
             naturality := by
              intro X Y f
              

Proof state:
J : Type u₁
inst✝³ : Category.{v₁, u₁} J
K : Type u₂
inst✝² : Category.{v₂, u₂} K
C : Type u₃
inst✝¹ : Category.{v₃, u₃} C
D : Type u₄
inst✝ : Category.{v₄, u₄} D
F : Discrete PUnit.{?u.14910 + 1} ⥤ C
X Y : Discrete PUnit.{?u.14910 + 1}
f : X ⟶ Y
⊢ F.map f ≫
      (fun x =>
          match x with
          | { as := PUnit.unit } => 𝟙 (F.obj { as := PUnit.unit }))
        Y =
    (fun x =>
          match x with
          | { as := PUnit.unit } => 𝟙 (F.obj { as := PUnit.unit }))
        X ≫
      ((const (Discrete PUnit.{?u.14910 + 1})).obj (F.obj { as := PUnit.unit })).map f

Next tactic:
match X, Y, f with
              | .mk A, .mk B, .up g =>
                aesop_cat
instance inhabitedCocone (F : Discrete PUnit ⥤ C) : Inhabited (Cocone F) :=
  ⟨{  pt := F.obj ⟨⟨⟩⟩
      ι := { app := fun ⟨⟨⟩⟩ => 𝟙 _
             naturality := by
              intro X Y f
              match X, Y, f with
              | .mk A, .mk B, .up g =>
                

Proof state:
J : Type u₁
inst✝³ : Category.{v₁, u₁} J
K : Type u₂
inst✝² : Category.{v₂, u₂} K
C : Type u₃
inst✝¹ : Category.{v₃, u₃} C
D : Type u₄
inst✝ : Category.{v₄, u₄} D
F : Discrete PUnit.{?u.15360 + 1} ⥤ C
X Y : Discrete PUnit.{?u.15360 + 1}
f : X ⟶ Y
A B : PUnit.{?u.15360 + 1}
g : PLift ({ as := A }.as = { as := B }.as)
⊢ F.map { down := g } ≫
      (fun x =>
          match x with
          | { as := PUnit.unit } => 𝟙 (F.obj { as := PUnit.unit }))
        { as := B } =
    (fun x =>
          match x with
          | { as := PUnit.unit } => 𝟙 (F.obj { as := PUnit.unit }))
        { as := A } ≫
      ((const (Discrete PUnit.{?u.15360 + 1})).obj (F.obj { as := PUnit.unit })).map { down := g }

Next tactic:
aesop_cat
@[reassoc] -- @[simp] -- Porting note: simp can prove this
theorem Cocone.w {F : J ⥤ C} (c : Cocone F) {j j' : J} (f : j ⟶ j') :
    F.map f ≫ c.ι.app j' = c.ι.app j := by
  

Proof state:
J : Type u₁
inst✝³ : Category.{v₁, u₁} J
K : Type u₂
inst✝² : Category.{v₂, u₂} K
C : Type u₃
inst✝¹ : Category.{v₃, u₃} C
D : Type u₄
inst✝ : Category.{v₄, u₄} D
F : J ⥤ C
c : Cocone F
j j' : J
f : j ⟶ j'
⊢ F.map f ≫ c.ι.app j' = c.ι.app j

Next tactic:
rw [c.ι.naturality f]
@[reassoc] -- @[simp] -- Porting note: simp can prove this
theorem Cocone.w {F : J ⥤ C} (c : Cocone F) {j j' : J} (f : j ⟶ j') :
    F.map f ≫ c.ι.app j' = c.ι.app j := by
  rw [c.ι.naturality f]
  

Proof state:
J : Type u₁
inst✝³ : Category.{v₁, u₁} J
K : Type u₂
inst✝² : Category.{v₂, u₂} K
C : Type u₃
inst✝¹ : Category.{v₃, u₃} C
D : Type u₄
inst✝ : Category.{v₄, u₄} D
F : J ⥤ C
c : Cocone F
j j' : J
f : j ⟶ j'
⊢ c.ι.app j ≫ ((const J).obj c.pt).map f = c.ι.app j

Next tactic:
apply comp_id
/-- The isomorphism between a cone on `F` and an element of the functor `F.cones`. -/
@[simps!]
def equiv (F : J ⥤ C) : Cone F ≅ ΣX, F.cones.obj X where
  hom c := ⟨op c.pt, c.π⟩
  inv c :=
    { pt := c.1.unop
      π := c.2 }
  hom_inv_id := by
    

Proof state:
J : Type u₁
inst✝³ : Category.{v₁, u₁} J
K : Type u₂
inst✝² : Category.{v₂, u₂} K
C : Type u₃
inst✝¹ : Category.{v₃, u₃} C
D : Type u₄
inst✝ : Category.{v₄, u₄} D
F✝ F : J ⥤ C
⊢ ((fun c => { fst := op c.pt, snd := c.π }) ≫ fun c => { pt := c.fst.unop, π := c.snd }) = 𝟙 (Cone F)

Next tactic:
funext X
/-- The isomorphism between a cone on `F` and an element of the functor `F.cones`. -/
@[simps!]
def equiv (F : J ⥤ C) : Cone F ≅ ΣX, F.cones.obj X where
  hom c := ⟨op c.pt, c.π⟩
  inv c :=
    { pt := c.1.unop
      π := c.2 }
  hom_inv_id := by
    funext X
    

Proof state:
case h
J : Type u₁
inst✝³ : Category.{v₁, u₁} J
K : Type u₂
inst✝² : Category.{v₂, u₂} K
C : Type u₃
inst✝¹ : Category.{v₃, u₃} C
D : Type u₄
inst✝ : Category.{v₄, u₄} D
F✝ F : J ⥤ C
X : Cone F
⊢ ((fun c => { fst := op c.pt, snd := c.π }) ≫ fun c => { pt := c.fst.unop, π := c.snd }) X = 𝟙 (Cone F) X

Next tactic:
cases X
/-- The isomorphism between a cone on `F` and an element of the functor `F.cones`. -/
@[simps!]
def equiv (F : J ⥤ C) : Cone F ≅ ΣX, F.cones.obj X where
  hom c := ⟨op c.pt, c.π⟩
  inv c :=
    { pt := c.1.unop
      π := c.2 }
  hom_inv_id := by
    funext X
    cases X
    

Proof state:
case h.mk
J : Type u₁
inst✝³ : Category.{v₁, u₁} J
K : Type u₂
inst✝² : Category.{v₂, u₂} K
C : Type u₃
inst✝¹ : Category.{v₃, u₃} C
D : Type u₄
inst✝ : Category.{v₄, u₄} D
F✝ F : J ⥤ C
pt✝ : C
π✝ : (const J).obj pt✝ ⟶ F
⊢ ((fun c => { fst := op c.pt, snd := c.π }) ≫ fun c => { pt := c.fst.unop, π := c.snd }) { pt := pt✝, π := π✝ } =
    𝟙 (Cone F) { pt := pt✝, π := π✝ }

Next tactic:
rfl
/-- The isomorphism between a cone on `F` and an element of the functor `F.cones`. -/
@[simps!]
def equiv (F : J ⥤ C) : Cone F ≅ ΣX, F.cones.obj X where
  hom c := ⟨op c.pt, c.π⟩
  inv c :=
    { pt := c.1.unop
      π := c.2 }
  hom_inv_id := by
    funext X
    cases X
    rfl
  inv_hom_id := by
    

Proof state:
J : Type u₁
inst✝³ : Category.{v₁, u₁} J
K : Type u₂
inst✝² : Category.{v₂, u₂} K
C : Type u₃
inst✝¹ : Category.{v₃, u₃} C
D : Type u₄
inst✝ : Category.{v₄, u₄} D
F✝ F : J ⥤ C
⊢ ((fun c => { pt := c.fst.unop, π := c.snd }) ≫ fun c => { fst := op c.pt, snd := c.π }) =
    𝟙 ((X : Cᵒᵖ) × (Functor.cones F).obj X)

Next tactic:
funext X
/-- The isomorphism between a cone on `F` and an element of the functor `F.cones`. -/
@[simps!]
def equiv (F : J ⥤ C) : Cone F ≅ ΣX, F.cones.obj X where
  hom c := ⟨op c.pt, c.π⟩
  inv c :=
    { pt := c.1.unop
      π := c.2 }
  hom_inv_id := by
    funext X
    cases X
    rfl
  inv_hom_id := by
    funext X
    

Proof state:
case h
J : Type u₁
inst✝³ : Category.{v₁, u₁} J
K : Type u₂
inst✝² : Category.{v₂, u₂} K
C : Type u₃
inst✝¹ : Category.{v₃, u₃} C
D : Type u₄
inst✝ : Category.{v₄, u₄} D
F✝ F : J ⥤ C
X : (X : Cᵒᵖ) × (Functor.cones F).obj X
⊢ ((fun c => { pt := c.fst.unop, π := c.snd }) ≫ fun c => { fst := op c.pt, snd := c.π }) X =
    𝟙 ((X : Cᵒᵖ) × (Functor.cones F).obj X) X

Next tactic:
cases X
/-- The isomorphism between a cone on `F` and an element of the functor `F.cones`. -/
@[simps!]
def equiv (F : J ⥤ C) : Cone F ≅ ΣX, F.cones.obj X where
  hom c := ⟨op c.pt, c.π⟩
  inv c :=
    { pt := c.1.unop
      π := c.2 }
  hom_inv_id := by
    funext X
    cases X
    rfl
  inv_hom_id := by
    funext X
    cases X
    

Proof state:
case h.mk
J : Type u₁
inst✝³ : Category.{v₁, u₁} J
K : Type u₂
inst✝² : Category.{v₂, u₂} K
C : Type u₃
inst✝¹ : Category.{v₃, u₃} C
D : Type u₄
inst✝ : Category.{v₄, u₄} D
F✝ F : J ⥤ C
fst✝ : Cᵒᵖ
snd✝ : (Functor.cones F).obj fst✝
⊢ ((fun c => { pt := c.fst.unop, π := c.snd }) ≫ fun c => { fst := op c.pt, snd := c.π }) { fst := fst✝, snd := snd✝ } =
    𝟙 ((X : Cᵒᵖ) × (Functor.cones F).obj X) { fst := fst✝, snd := snd✝ }

Next tactic:
rfl
/-- The isomorphism between a cocone on `F` and an element of the functor `F.cocones`. -/
def equiv (F : J ⥤ C) : Cocone F ≅ ΣX, F.cocones.obj X where
  hom c := ⟨c.pt, c.ι⟩
  inv c :=
    { pt := c.1
      ι := c.2 }
  hom_inv_id := by
    

Proof state:
J : Type u₁
inst✝³ : Category.{v₁, u₁} J
K : Type u₂
inst✝² : Category.{v₂, u₂} K
C : Type u₃
inst✝¹ : Category.{v₃, u₃} C
D : Type u₄
inst✝ : Category.{v₄, u₄} D
F✝ F : J ⥤ C
⊢ ((fun c => { fst := c.pt, snd := c.ι }) ≫ fun c => { pt := c.fst, ι := c.snd }) = 𝟙 (Cocone F)

Next tactic:
funext X
/-- The isomorphism between a cocone on `F` and an element of the functor `F.cocones`. -/
def equiv (F : J ⥤ C) : Cocone F ≅ ΣX, F.cocones.obj X where
  hom c := ⟨c.pt, c.ι⟩
  inv c :=
    { pt := c.1
      ι := c.2 }
  hom_inv_id := by
    funext X
    

Proof state:
case h
J : Type u₁
inst✝³ : Category.{v₁, u₁} J
K : Type u₂
inst✝² : Category.{v₂, u₂} K
C : Type u₃
inst✝¹ : Category.{v₃, u₃} C
D : Type u₄
inst✝ : Category.{v₄, u₄} D
F✝ F : J ⥤ C
X : Cocone F
⊢ ((fun c => { fst := c.pt, snd := c.ι }) ≫ fun c => { pt := c.fst, ι := c.snd }) X = 𝟙 (Cocone F) X

Next tactic:
cases X
/-- The isomorphism between a cocone on `F` and an element of the functor `F.cocones`. -/
def equiv (F : J ⥤ C) : Cocone F ≅ ΣX, F.cocones.obj X where
  hom c := ⟨c.pt, c.ι⟩
  inv c :=
    { pt := c.1
      ι := c.2 }
  hom_inv_id := by
    funext X
    cases X
    

Proof state:
case h.mk
J : Type u₁
inst✝³ : Category.{v₁, u₁} J
K : Type u₂
inst✝² : Category.{v₂, u₂} K
C : Type u₃
inst✝¹ : Category.{v₃, u₃} C
D : Type u₄
inst✝ : Category.{v₄, u₄} D
F✝ F : J ⥤ C
pt✝ : C
ι✝ : F ⟶ (const J).obj pt✝
⊢ ((fun c => { fst := c.pt, snd := c.ι }) ≫ fun c => { pt := c.fst, ι := c.snd }) { pt := pt✝, ι := ι✝ } =
    𝟙 (Cocone F) { pt := pt✝, ι := ι✝ }

Next tactic:
rfl
/-- The isomorphism between a cocone on `F` and an element of the functor `F.cocones`. -/
def equiv (F : J ⥤ C) : Cocone F ≅ ΣX, F.cocones.obj X where
  hom c := ⟨c.pt, c.ι⟩
  inv c :=
    { pt := c.1
      ι := c.2 }
  hom_inv_id := by
    funext X
    cases X
    rfl
  inv_hom_id := by
    

Proof state:
J : Type u₁
inst✝³ : Category.{v₁, u₁} J
K : Type u₂
inst✝² : Category.{v₂, u₂} K
C : Type u₃
inst✝¹ : Category.{v₃, u₃} C
D : Type u₄
inst✝ : Category.{v₄, u₄} D
F✝ F : J ⥤ C
⊢ ((fun c => { pt := c.fst, ι := c.snd }) ≫ fun c => { fst := c.pt, snd := c.ι }) =
    𝟙 ((X : C) × (Functor.cocones F).obj X)

Next tactic:
funext X
/-- The isomorphism between a cocone on `F` and an element of the functor `F.cocones`. -/
def equiv (F : J ⥤ C) : Cocone F ≅ ΣX, F.cocones.obj X where
  hom c := ⟨c.pt, c.ι⟩
  inv c :=
    { pt := c.1
      ι := c.2 }
  hom_inv_id := by
    funext X
    cases X
    rfl
  inv_hom_id := by
    funext X
    

Proof state:
case h
J : Type u₁
inst✝³ : Category.{v₁, u₁} J
K : Type u₂
inst✝² : Category.{v₂, u₂} K
C : Type u₃
inst✝¹ : Category.{v₃, u₃} C
D : Type u₄
inst✝ : Category.{v₄, u₄} D
F✝ F : J ⥤ C
X : (X : C) × (Functor.cocones F).obj X
⊢ ((fun c => { pt := c.fst, ι := c.snd }) ≫ fun c => { fst := c.pt, snd := c.ι }) X =
    𝟙 ((X : C) × (Functor.cocones F).obj X) X

Next tactic:
cases X
/-- The isomorphism between a cocone on `F` and an element of the functor `F.cocones`. -/
def equiv (F : J ⥤ C) : Cocone F ≅ ΣX, F.cocones.obj X where
  hom c := ⟨c.pt, c.ι⟩
  inv c :=
    { pt := c.1
      ι := c.2 }
  hom_inv_id := by
    funext X
    cases X
    rfl
  inv_hom_id := by
    funext X
    cases X
    

Proof state:
case h.mk
J : Type u₁
inst✝³ : Category.{v₁, u₁} J
K : Type u₂
inst✝² : Category.{v₂, u₂} K
C : Type u₃
inst✝¹ : Category.{v₃, u₃} C
D : Type u₄
inst✝ : Category.{v₄, u₄} D
F✝ F : J ⥤ C
fst✝ : C
snd✝ : (Functor.cocones F).obj fst✝
⊢ ((fun c => { pt := c.fst, ι := c.snd }) ≫ fun c => { fst := c.pt, snd := c.ι }) { fst := fst✝, snd := snd✝ } =
    𝟙 ((X : C) × (Functor.cocones F).obj X) { fst := fst✝, snd := snd✝ }

Next tactic:
rfl
@[ext]
theorem ConeMorphism.ext {c c' : Cone F} (f g : c ⟶ c') (w : f.hom = g.hom) : f = g := by
  

Proof state:
J : Type u₁
inst✝³ : Category.{v₁, u₁} J
K : Type u₂
inst✝² : Category.{v₂, u₂} K
C : Type u₃
inst✝¹ : Category.{v₃, u₃} C
D : Type u₄
inst✝ : Category.{v₄, u₄} D
F : J ⥤ C
c c' : Cone F
f g : c ⟶ c'
w : f.hom = g.hom
⊢ f = g

Next tactic:
cases f
@[ext]
theorem ConeMorphism.ext {c c' : Cone F} (f g : c ⟶ c') (w : f.hom = g.hom) : f = g := by
  cases f
  

Proof state:
case mk
J : Type u₁
inst✝³ : Category.{v₁, u₁} J
K : Type u₂
inst✝² : Category.{v₂, u₂} K
C : Type u₃
inst✝¹ : Category.{v₃, u₃} C
D : Type u₄
inst✝ : Category.{v₄, u₄} D
F : J ⥤ C
c c' : Cone F
g : c ⟶ c'
hom✝ : c.pt ⟶ c'.pt
w✝ : ∀ (j : J), hom✝ ≫ c'.π.app j = c.π.app j
w : (mk hom✝).hom = g.hom
⊢ mk hom✝ = g

Next tactic:
cases g
@[ext]
theorem ConeMorphism.ext {c c' : Cone F} (f g : c ⟶ c') (w : f.hom = g.hom) : f = g := by
  cases f
  cases g
  

Proof state:
case mk.mk
J : Type u₁
inst✝³ : Category.{v₁, u₁} J
K : Type u₂
inst✝² : Category.{v₂, u₂} K
C : Type u₃
inst✝¹ : Category.{v₃, u₃} C
D : Type u₄
inst✝ : Category.{v₄, u₄} D
F : J ⥤ C
c c' : Cone F
hom✝¹ : c.pt ⟶ c'.pt
w✝¹ : ∀ (j : J), hom✝¹ ≫ c'.π.app j = c.π.app j
hom✝ : c.pt ⟶ c'.pt
w✝ : ∀ (j : J), hom✝ ≫ c'.π.app j = c.π.app j
w : (mk hom✝¹).hom = (mk hom✝).hom
⊢ mk hom✝¹ = mk hom✝

Next tactic:
congr
/-- Given a cone morphism whose object part is an isomorphism, produce an
isomorphism of cones.
-/
theorem cone_iso_of_hom_iso {K : J ⥤ C} {c d : Cone K} (f : c ⟶ d) [i : IsIso f.hom] : IsIso f :=
  ⟨⟨{   hom := inv f.hom
        w := fun j => (asIso f.hom).inv_comp_eq.2 (f.w j).symm }, by 

Proof state:
J : Type u₁
inst✝³ : Category.{v₁, u₁} J
K✝ : Type u₂
inst✝² : Category.{v₂, u₂} K✝
C : Type u₃
inst✝¹ : Category.{v₃, u₃} C
D : Type u₄
inst✝ : Category.{v₄, u₄} D
F K : J ⥤ C
c d : Cone K
f : c ⟶ d
i : IsIso f.hom
⊢ f ≫ ConeMorphism.mk (inv f.hom) = 𝟙 c ∧ ConeMorphism.mk (inv f.hom) ≫ f = 𝟙 d

Next tactic:
aesop_cat