l3lab/ntp-mathlib huggingface dataset:
@[to_additive]
theorem MulHom.cancel_left [Mul M] [Mul N] [Mul P] {g : N →ₙ* P} {f₁ f₂ : M →ₙ* N}
    (hg : Function.Injective g) : g.comp f₁ = g.comp f₂ ↔ f₁ = f₂ :=
  ⟨fun h => MulHom.ext fun x => hg <| by 

Proof state:
α : Type u_1
β : Type u_2
M : Type u_3
N : Type u_4
P : Type u_5
G : Type u_6
H : Type u_7
F : Type u_8
inst✝² : Mul M
inst✝¹ : Mul N
inst✝ : Mul P
g : N →ₙ* P
f₁ f₂ : M →ₙ* N
hg : Function.Injective ⇑g
h : comp g f₁ = comp g f₂
x : M
⊢ g (f₁ x) = g (f₂ x)

Next tactic:
rw [← MulHom.comp_apply, h, MulHom.comp_apply]
@[to_additive]
theorem MonoidHom.cancel_left [MulOneClass M] [MulOneClass N] [MulOneClass P]
    {g : N →* P} {f₁ f₂ : M →* N} (hg : Function.Injective g) : g.comp f₁ = g.comp f₂ ↔ f₁ = f₂ :=
  ⟨fun h => MonoidHom.ext fun x => hg <| by 

Proof state:
α : Type u_1
β : Type u_2
M : Type u_3
N : Type u_4
P : Type u_5
G : Type u_6
H : Type u_7
F : Type u_8
inst✝² : MulOneClass M
inst✝¹ : MulOneClass N
inst✝ : MulOneClass P
g : N →* P
f₁ f₂ : M →* N
hg : Function.Injective ⇑g
h : comp g f₁ = comp g f₂
x : M
⊢ g (f₁ x) = g (f₂ x)

Next tactic:
rw [← MonoidHom.comp_apply, h, MonoidHom.comp_apply]
theorem MonoidWithZeroHom.cancel_left [MulZeroOneClass M] [MulZeroOneClass N] [MulZeroOneClass P]
    {g : N →*₀ P} {f₁ f₂ : M →*₀ N} (hg : Function.Injective g) :
    g.comp f₁ = g.comp f₂ ↔ f₁ = f₂ :=
  ⟨fun h =>
    MonoidWithZeroHom.ext fun x => hg <| by 

Proof state:
α : Type u_1
β : Type u_2
M : Type u_3
N : Type u_4
P : Type u_5
G : Type u_6
H : Type u_7
F : Type u_8
inst✝² : MulZeroOneClass M
inst✝¹ : MulZeroOneClass N
inst✝ : MulZeroOneClass P
g : N →*₀ P
f₁ f₂ : M →*₀ N
hg : Function.Injective ⇑g
h : comp g f₁ = comp g f₂
x : M
⊢ g (f₁ x) = g (f₂ x)

Next tactic:
rw [← MonoidWithZeroHom.comp_apply, h,
    MonoidWithZeroHom.comp_apply]
@[to_additive (attr := simp)]
theorem OneHom.comp_one [One M] [One N] [One P] (f : OneHom N P) : f.comp (1 : OneHom M N) = 1 := by
  

Proof state:
α : Type u_1
β : Type u_2
M : Type u_3
N : Type u_4
P : Type u_5
G : Type u_6
H : Type u_7
F : Type u_8
inst✝² : One M
inst✝¹ : One N
inst✝ : One P
f : OneHom N P
⊢ comp f 1 = 1

Next tactic:
ext
@[to_additive (attr := simp)]
theorem OneHom.comp_one [One M] [One N] [One P] (f : OneHom N P) : f.comp (1 : OneHom M N) = 1 := by
  ext
  

Proof state:
case h
α : Type u_1
β : Type u_2
M : Type u_3
N : Type u_4
P : Type u_5
G : Type u_6
H : Type u_7
F : Type u_8
inst✝² : One M
inst✝¹ : One N
inst✝ : One P
f : OneHom N P
x✝ : M
⊢ (comp f 1) x✝ = 1 x✝

Next tactic:
simp only [OneHom.map_one, OneHom.coe_comp, Function.comp_apply, OneHom.one_apply]
@[to_additive (attr := simp)]
theorem comp_one [MulOneClass M] [MulOneClass N] [MulOneClass P] (f : N →* P) :
    f.comp (1 : M →* N) = 1 := by
  

Proof state:
α : Type u_1
β : Type u_2
M : Type u_3
N : Type u_4
P : Type u_5
G : Type u_6
H : Type u_7
F : Type u_8
inst✝⁴ : Group G
inst✝³ : CommGroup H
inst✝² : MulOneClass M
inst✝¹ : MulOneClass N
inst✝ : MulOneClass P
f : N →* P
⊢ comp f 1 = 1

Next tactic:
ext
@[to_additive (attr := simp)]
theorem comp_one [MulOneClass M] [MulOneClass N] [MulOneClass P] (f : N →* P) :
    f.comp (1 : M →* N) = 1 := by
  ext
  

Proof state:
case h
α : Type u_1
β : Type u_2
M : Type u_3
N : Type u_4
P : Type u_5
G : Type u_6
H : Type u_7
F : Type u_8
inst✝⁴ : Group G
inst✝³ : CommGroup H
inst✝² : MulOneClass M
inst✝¹ : MulOneClass N
inst✝ : MulOneClass P
f : N →* P
x✝ : M
⊢ (comp f 1) x✝ = 1 x✝

Next tactic:
simp only [map_one, coe_comp, Function.comp_apply, one_apply]
/-- Group homomorphisms preserve division. -/
@[to_additive "Additive group homomorphisms preserve subtraction."]
protected theorem map_mul_inv [Group α] [DivisionMonoid β] (f : α →* β) (g h : α) :
    f (g * h⁻¹) = f g * (f h)⁻¹ := by 

Proof state:
α : Type u_1
β : Type u_2
M : Type u_3
N : Type u_4
P : Type u_5
G : Type u_6
H : Type u_7
F : Type u_8
inst✝³ : Group G
inst✝² : CommGroup H
inst✝¹ : Group α
inst✝ : DivisionMonoid β
f : α →* β
g h : α
⊢ f (g * h⁻¹) = f g * (f h)⁻¹

Next tactic:
simp
@[reassoc (attr := simp)]
theorem bicone_ι_π_self {F : J → C} (B : Bicone F) (j : J) : B.ι j ≫ B.π j = 𝟙 (F j) := by
  

Proof state:
J : Type w
C : Type uC
inst✝³ : Category.{uC', uC} C
inst✝² : HasZeroMorphisms C
D : Type uD
inst✝¹ : Category.{uD', uD} D
inst✝ : HasZeroMorphisms D
F : J → C
B : Bicone F
j : J
⊢ Bicone.ι B j ≫ Bicone.π B j = 𝟙 (F j)

Next tactic:
simpa using B.ι_π j j
@[reassoc (attr := simp)]
theorem bicone_ι_π_ne {F : J → C} (B : Bicone F) {j j' : J} (h : j ≠ j') : B.ι j ≫ B.π j' = 0 := by
  

Proof state:
J : Type w
C : Type uC
inst✝³ : Category.{uC', uC} C
inst✝² : HasZeroMorphisms C
D : Type uD
inst✝¹ : Category.{uD', uD} D
inst✝ : HasZeroMorphisms D
F : J → C
B : Bicone F
j j' : J
h : j ≠ j'
⊢ Bicone.ι B j ≫ Bicone.π B j' = 0

Next tactic:
simpa [h] using B.ι_π j j'
@[ext]
theorem BiconeMorphism.ext {c c' : Bicone F} (f g : c ⟶ c') (w : f.hom = g.hom) : f = g := by
  

Proof state:
J : Type w
C : Type uC
inst✝³ : Category.{uC', uC} C
inst✝² : HasZeroMorphisms C
D : Type uD
inst✝¹ : Category.{uD', uD} D
inst✝ : HasZeroMorphisms D
F : J → C
c c' : Bicone F
f g : c ⟶ c'
w : f.hom = g.hom
⊢ f = g

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

Proof state:
case mk
J : Type w
C : Type uC
inst✝³ : Category.{uC', uC} C
inst✝² : HasZeroMorphisms C
D : Type uD
inst✝¹ : Category.{uD', uD} D
inst✝ : HasZeroMorphisms D
F : J → C
c c' : Bicone F
g : c ⟶ c'
hom✝ : c.pt ⟶ c'.pt
wπ✝ : ∀ (j : J), hom✝ ≫ Bicone.π c' j = Bicone.π c j
wι✝ : ∀ (j : J), Bicone.ι c j ≫ hom✝ = Bicone.ι c' j
w : (mk hom✝).hom = g.hom
⊢ mk hom✝ = g

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

Proof state:
case mk.mk
J : Type w
C : Type uC
inst✝³ : Category.{uC', uC} C
inst✝² : HasZeroMorphisms C
D : Type uD
inst✝¹ : Category.{uD', uD} D
inst✝ : HasZeroMorphisms D
F : J → C
c c' : Bicone F
hom✝¹ : c.pt ⟶ c'.pt
wπ✝¹ : ∀ (j : J), hom✝¹ ≫ Bicone.π c' j = Bicone.π c j
wι✝¹ : ∀ (j : J), Bicone.ι c j ≫ hom✝¹ = Bicone.ι c' j
hom✝ : c.pt ⟶ c'.pt
wπ✝ : ∀ (j : J), hom✝ ≫ Bicone.π c' j = Bicone.π c j
wι✝ : ∀ (j : J), Bicone.ι c j ≫ hom✝ = Bicone.ι c' j
w : (mk hom✝¹).hom = (mk hom✝).hom
⊢ mk hom✝¹ = mk hom✝

Next tactic:
congr
variable (F) in
/-- A functor `G : C ⥤ D` sends bicones over `F` to bicones over `G.obj ∘ F` functorially. -/
@[simps]
def functoriality (G : C ⥤ D) [Functor.PreservesZeroMorphisms G] :
    Bicone F ⥤ Bicone (G.obj ∘ F) where
  obj A :=
    { pt := G.obj A.pt
      π := fun j => G.map (A.π j)
      ι := fun j => G.map (A.ι j)
      ι_π := fun i j => (Functor.map_comp _ _ _).symm.trans <| by
        

Proof state:
J : Type w
C : Type uC
inst✝⁴ : Category.{uC', uC} C
inst✝³ : HasZeroMorphisms C
D : Type uD
inst✝² : Category.{uD', uD} D
inst✝¹ : HasZeroMorphisms D
F : J → C
G : C ⥤ D
inst✝ : PreservesZeroMorphisms G
A : Bicone F
i j : J
⊢ G.map (Bicone.ι A i ≫ Bicone.π A j) = if h : i = j then eqToHom (_ : (G.obj ∘ F) i = (G.obj ∘ F) j) else 0

Next tactic:
rw [A.ι_π]
variable (F) in
/-- A functor `G : C ⥤ D` sends bicones over `F` to bicones over `G.obj ∘ F` functorially. -/
@[simps]
def functoriality (G : C ⥤ D) [Functor.PreservesZeroMorphisms G] :
    Bicone F ⥤ Bicone (G.obj ∘ F) where
  obj A :=
    { pt := G.obj A.pt
      π := fun j => G.map (A.π j)
      ι := fun j => G.map (A.ι j)
      ι_π := fun i j => (Functor.map_comp _ _ _).symm.trans <| by
        rw [A.ι_π]
        

Proof state:
J : Type w
C : Type uC
inst✝⁴ : Category.{uC', uC} C
inst✝³ : HasZeroMorphisms C
D : Type uD
inst✝² : Category.{uD', uD} D
inst✝¹ : HasZeroMorphisms D
F : J → C
G : C ⥤ D
inst✝ : PreservesZeroMorphisms G
A : Bicone F
i j : J
⊢ G.map (if h : i = j then eqToHom (_ : F i = F j) else 0) =
    if h : i = j then eqToHom (_ : (G.obj ∘ F) i = (G.obj ∘ F) j) else 0

Next tactic:
aesop_cat
variable (F) in
/-- A functor `G : C ⥤ D` sends bicones over `F` to bicones over `G.obj ∘ F` functorially. -/
@[simps]
def functoriality (G : C ⥤ D) [Functor.PreservesZeroMorphisms G] :
    Bicone F ⥤ Bicone (G.obj ∘ F) where
  obj A :=
    { pt := G.obj A.pt
      π := fun j => G.map (A.π j)
      ι := fun j => G.map (A.ι j)
      ι_π := fun i j => (Functor.map_comp _ _ _).symm.trans <| by
        rw [A.ι_π]
        aesop_cat }
  map f :=
    { hom := G.map f.hom
      wπ := fun j => by 

Proof state:
J : Type w
C : Type uC
inst✝⁴ : Category.{uC', uC} C
inst✝³ : HasZeroMorphisms C
D : Type uD
inst✝² : Category.{uD', uD} D
inst✝¹ : HasZeroMorphisms D
F : J → C
G : C ⥤ D
inst✝ : PreservesZeroMorphisms G
X✝ Y✝ : Bicone F
f : X✝ ⟶ Y✝
j : J
⊢ G.map f.hom ≫
      Bicone.π ((fun A => Bicone.mk (G.obj A.pt) (fun j => G.map (Bicone.π A j)) fun j => G.map (Bicone.ι A j)) Y✝) j =
    Bicone.π ((fun A => Bicone.mk (G.obj A.pt) (fun j => G.map (Bicone.π A j)) fun j => G.map (Bicone.ι A j)) X✝) j

Next tactic:
simp [-BiconeMorphism.wπ, ← f.wπ j]
variable (F) in
/-- A functor `G : C ⥤ D` sends bicones over `F` to bicones over `G.obj ∘ F` functorially. -/
@[simps]
def functoriality (G : C ⥤ D) [Functor.PreservesZeroMorphisms G] :
    Bicone F ⥤ Bicone (G.obj ∘ F) where
  obj A :=
    { pt := G.obj A.pt
      π := fun j => G.map (A.π j)
      ι := fun j => G.map (A.ι j)
      ι_π := fun i j => (Functor.map_comp _ _ _).symm.trans <| by
        rw [A.ι_π]
        aesop_cat }
  map f :=
    { hom := G.map f.hom
      wπ := fun j => by simp [-BiconeMorphism.wπ, ← f.wπ j]
      wι := fun j => by 

Proof state:
J : Type w
C : Type uC
inst✝⁴ : Category.{uC', uC} C
inst✝³ : HasZeroMorphisms C
D : Type uD
inst✝² : Category.{uD', uD} D
inst✝¹ : HasZeroMorphisms D
F : J → C
G : C ⥤ D
inst✝ : PreservesZeroMorphisms G
X✝ Y✝ : Bicone F
f : X✝ ⟶ Y✝
j : J
⊢ Bicone.ι ((fun A => Bicone.mk (G.obj A.pt) (fun j => G.map (Bicone.π A j)) fun j => G.map (Bicone.ι A j)) X✝) j ≫
      G.map f.hom =
    Bicone.ι ((fun A => Bicone.mk (G.obj A.pt) (fun j => G.map (Bicone.π A j)) fun j => G.map (Bicone.ι A j)) Y✝) j

Next tactic:
simp [-BiconeMorphism.wι, ← f.wι j]
/-- We can turn any limit cone over a discrete collection of objects into a bicone. -/
@[simps]
def ofLimitCone {f : J → C} {t : Cone (Discrete.functor f)} (ht : IsLimit t) : Bicone f where
  pt := t.pt
  π j := t.π.app ⟨j⟩
  ι j := ht.lift (Fan.mk _ fun j' => if h : j = j' then eqToHom (congr_arg f h) else 0)
  ι_π j j' := by 

Proof state:
J : Type w
C : Type uC
inst✝³ : Category.{uC', uC} C
inst✝² : HasZeroMorphisms C
D : Type uD
inst✝¹ : Category.{uD', uD} D
inst✝ : HasZeroMorphisms D
F f : J → C
t : Cone (Discrete.functor f)
ht : IsLimit t
j j' : J
⊢ (fun j => IsLimit.lift ht (Fan.mk (f j) fun j' => if h : j = j' then eqToHom (_ : f j = f j') else 0)) j ≫
      (fun j => t.π.app { as := j }) j' =
    if h : j = j' then eqToHom (_ : f j = f j') else 0

Next tactic:
simp
theorem ι_of_isLimit {f : J → C} {t : Bicone f} (ht : IsLimit t.toCone) (j : J) :
    t.ι j = ht.lift (Fan.mk _ fun j' => if h : j = j' then eqToHom (congr_arg f h) else 0) :=
  ht.hom_ext fun j' => by
    

Proof state:
J : Type w
C : Type uC
inst✝³ : Category.{uC', uC} C
inst✝² : HasZeroMorphisms C
D : Type uD
inst✝¹ : Category.{uD', uD} D
inst✝ : HasZeroMorphisms D
F f : J → C
t : Bicone f
ht : IsLimit (toCone t)
j : J
j' : Discrete J
⊢ ι t j ≫ (toCone t).π.app j' =
    IsLimit.lift ht (Fan.mk (f j) fun j' => if h : j = j' then eqToHom (_ : f j = f j') else 0) ≫ (toCone t).π.app j'

Next tactic:
rw [ht.fac]
theorem ι_of_isLimit {f : J → C} {t : Bicone f} (ht : IsLimit t.toCone) (j : J) :
    t.ι j = ht.lift (Fan.mk _ fun j' => if h : j = j' then eqToHom (congr_arg f h) else 0) :=
  ht.hom_ext fun j' => by
    rw [ht.fac]
    

Proof state:
J : Type w
C : Type uC
inst✝³ : Category.{uC', uC} C
inst✝² : HasZeroMorphisms C
D : Type uD
inst✝¹ : Category.{uD', uD} D
inst✝ : HasZeroMorphisms D
F f : J → C
t : Bicone f
ht : IsLimit (toCone t)
j : J
j' : Discrete J
⊢ ι t j ≫ (toCone t).π.app j' = (Fan.mk (f j) fun j' => if h : j = j' then eqToHom (_ : f j = f j') else 0).π.app j'

Next tactic:
simp [t.ι_π]
/-- We can turn any colimit cocone over a discrete collection of objects into a bicone. -/
@[simps]
def ofColimitCocone {f : J → C} {t : Cocone (Discrete.functor f)} (ht : IsColimit t) : Bicone f
    where
  pt := t.pt
  π j := ht.desc (Cofan.mk _ fun j' => if h : j' = j then eqToHom (congr_arg f h) else 0)
  ι j := t.ι.app ⟨j⟩
  ι_π j j' := by 

Proof state:
J : Type w
C : Type uC
inst✝³ : Category.{uC', uC} C
inst✝² : HasZeroMorphisms C
D : Type uD
inst✝¹ : Category.{uD', uD} D
inst✝ : HasZeroMorphisms D
F f : J → C
t : Cocone (Discrete.functor f)
ht : IsColimit t
j j' : J
⊢ (fun j => t.ι.app { as := j }) j ≫
      (fun j => IsColimit.desc ht (Cofan.mk (f j) fun j' => if h : j' = j then eqToHom (_ : f j' = f j) else 0)) j' =
    if h : j = j' then eqToHom (_ : f j = f j') else 0

Next tactic:
simp
theorem π_of_isColimit {f : J → C} {t : Bicone f} (ht : IsColimit t.toCocone) (j : J) :
    t.π j = ht.desc (Cofan.mk _ fun j' => if h : j' = j then eqToHom (congr_arg f h) else 0) :=
  ht.hom_ext fun j' => by
    

Proof state:
J : Type w
C : Type uC
inst✝³ : Category.{uC', uC} C
inst✝² : HasZeroMorphisms C
D : Type uD
inst✝¹ : Category.{uD', uD} D
inst✝ : HasZeroMorphisms D
F f : J → C
t : Bicone f
ht : IsColimit (toCocone t)
j : J
j' : Discrete J
⊢ (toCocone t).ι.app j' ≫ π t j =
    (toCocone t).ι.app j' ≫
      IsColimit.desc ht (Cofan.mk (f j) fun j' => if h : j' = j then eqToHom (_ : f j' = f j) else 0)

Next tactic:
rw [ht.fac]
theorem π_of_isColimit {f : J → C} {t : Bicone f} (ht : IsColimit t.toCocone) (j : J) :
    t.π j = ht.desc (Cofan.mk _ fun j' => if h : j' = j then eqToHom (congr_arg f h) else 0) :=
  ht.hom_ext fun j' => by
    rw [ht.fac]
    

Proof state:
J : Type w
C : Type uC
inst✝³ : Category.{uC', uC} C
inst✝² : HasZeroMorphisms C
D : Type uD
inst✝¹ : Category.{uD', uD} D
inst✝ : HasZeroMorphisms D
F f : J → C
t : Bicone f
ht : IsColimit (toCocone t)
j : J
j' : Discrete J
⊢ (toCocone t).ι.app j' ≫ π t j = (Cofan.mk (f j) fun j' => if h : j' = j then eqToHom (_ : f j' = f j) else 0).ι.app j'

Next tactic:
simp [t.ι_π]
/-- Whisker a bicone with an equivalence between the indexing types. -/
@[simps]
def whisker {f : J → C} (c : Bicone f) (g : K ≃ J) : Bicone (f ∘ g) where
  pt := c.pt
  π k := c.π (g k)
  ι k := c.ι (g k)
  ι_π k k' := by
    

Proof state:
J : Type w
C : Type uC
inst✝³ : Category.{uC', uC} C
inst✝² : HasZeroMorphisms C
D : Type uD
inst✝¹ : Category.{uD', uD} D
inst✝ : HasZeroMorphisms D
F : J → C
K : Type w'
f : J → C
c : Bicone f
g : K ≃ J
k k' : K
⊢ (fun k => ι c (g k)) k ≫ (fun k => π c (g k)) k' = if h : k = k' then eqToHom (_ : (f ∘ ⇑g) k = (f ∘ ⇑g) k') else 0

Next tactic:
simp only [c.ι_π]
/-- Whisker a bicone with an equivalence between the indexing types. -/
@[simps]
def whisker {f : J → C} (c : Bicone f) (g : K ≃ J) : Bicone (f ∘ g) where
  pt := c.pt
  π k := c.π (g k)
  ι k := c.ι (g k)
  ι_π k k' := by
    simp only [c.ι_π]
    

Proof state:
J : Type w
C : Type uC
inst✝³ : Category.{uC', uC} C
inst✝² : HasZeroMorphisms C
D : Type uD
inst✝¹ : Category.{uD', uD} D
inst✝ : HasZeroMorphisms D
F : J → C
K : Type w'
f : J → C
c : Bicone f
g : K ≃ J
k k' : K
⊢ (if h : g k = g k' then eqToHom (_ : f (g k) = f (g k')) else 0) =
    if h : k = k' then eqToHom (_ : (f ∘ ⇑g) k = (f ∘ ⇑g) k') else 0

Next tactic:
split_ifs with h h' h'
/-- Whisker a bicone with an equivalence between the indexing types. -/
@[simps]
def whisker {f : J → C} (c : Bicone f) (g : K ≃ J) : Bicone (f ∘ g) where
  pt := c.pt
  π k := c.π (g k)
  ι k := c.ι (g k)
  ι_π k k' := by
    simp only [c.ι_π]
    split_ifs with h h' h' <;> 

Proof state:
case pos
J : Type w
C : Type uC
inst✝³ : Category.{uC', uC} C
inst✝² : HasZeroMorphisms C
D : Type uD
inst✝¹ : Category.{uD', uD} D
inst✝ : HasZeroMorphisms D
F : J → C
K : Type w'
f : J → C
c : Bicone f
g : K ≃ J
k k' : K
h : g k = g k'
h' : k = k'
⊢ eqToHom (_ : f (g k) = f (g k')) = eqToHom (_ : (f ∘ ⇑g) k = (f ∘ ⇑g) k')

Next tactic:
simp [Equiv.apply_eq_iff_eq g] at h h'
/-- Whisker a bicone with an equivalence between the indexing types. -/
@[simps]
def whisker {f : J → C} (c : Bicone f) (g : K ≃ J) : Bicone (f ∘ g) where
  pt := c.pt
  π k := c.π (g k)
  ι k := c.ι (g k)
  ι_π k k' := by
    simp only [c.ι_π]
    split_ifs with h h' h' <;> 

Proof state:
case neg
J : Type w
C : Type uC
inst✝³ : Category.{uC', uC} C
inst✝² : HasZeroMorphisms C
D : Type uD
inst✝¹ : Category.{uD', uD} D
inst✝ : HasZeroMorphisms D
F : J → C
K : Type w'
f : J → C
c : Bicone f
g : K ≃ J
k k' : K
h : g k = g k'
h' : ¬k = k'
⊢ eqToHom (_ : f (g k) = f (g k')) = 0

Next tactic:
simp [Equiv.apply_eq_iff_eq g] at h h'
/-- Whisker a bicone with an equivalence between the indexing types. -/
@[simps]
def whisker {f : J → C} (c : Bicone f) (g : K ≃ J) : Bicone (f ∘ g) where
  pt := c.pt
  π k := c.π (g k)
  ι k := c.ι (g k)
  ι_π k k' := by
    simp only [c.ι_π]
    split_ifs with h h' h' <;> 

Proof state:
case pos
J : Type w
C : Type uC
inst✝³ : Category.{uC', uC} C
inst✝² : HasZeroMorphisms C
D : Type uD
inst✝¹ : Category.{uD', uD} D
inst✝ : HasZeroMorphisms D
F : J → C
K : Type w'
f : J → C
c : Bicone f
g : K ≃ J
k k' : K
h : ¬g k = g k'
h' : k = k'
⊢ 0 = eqToHom (_ : (f ∘ ⇑g) k = (f ∘ ⇑g) k')

Next tactic:
simp [Equiv.apply_eq_iff_eq g] at h h'
/-- Whisker a bicone with an equivalence between the indexing types. -/
@[simps]
def whisker {f : J → C} (c : Bicone f) (g : K ≃ J) : Bicone (f ∘ g) where
  pt := c.pt
  π k := c.π (g k)
  ι k := c.ι (g k)
  ι_π k k' := by
    simp only [c.ι_π]
    split_ifs with h h' h' <;> 

Proof state:
case neg
J : Type w
C : Type uC
inst✝³ : Category.{uC', uC} C
inst✝² : HasZeroMorphisms C
D : Type uD
inst✝¹ : Category.{uD', uD} D
inst✝ : HasZeroMorphisms D
F : J → C
K : Type w'
f : J → C
c : Bicone f
g : K ≃ J
k k' : K
h : ¬g k = g k'
h' : ¬k = k'
⊢ 0 = 0

Next tactic:
simp [Equiv.apply_eq_iff_eq g] at h h'
/-- Whisker a bicone with an equivalence between the indexing types. -/
@[simps]
def whisker {f : J → C} (c : Bicone f) (g : K ≃ J) : Bicone (f ∘ g) where
  pt := c.pt
  π k := c.π (g k)
  ι k := c.ι (g k)
  ι_π k k' := by
    simp only [c.ι_π]
    split_ifs with h h' h' <;> simp [Equiv.apply_eq_iff_eq g] at h h' <;> 

Proof state:
case pos
J : Type w
C : Type uC
inst✝³ : Category.{uC', uC} C
inst✝² : HasZeroMorphisms C
D : Type uD
inst✝¹ : Category.{uD', uD} D
inst✝ : HasZeroMorphisms D
F : J → C
K : Type w'
f : J → C
c : Bicone f
g : K ≃ J
k k' : K
h✝ : g k = g k'
h' h : k = k'
⊢ eqToHom (_ : f (g k) = f (g k')) = eqToHom (_ : (f ∘ ⇑g) k = (f ∘ ⇑g) k')

Next tactic:
tauto
/-- Whisker a bicone with an equivalence between the indexing types. -/
@[simps]
def whisker {f : J → C} (c : Bicone f) (g : K ≃ J) : Bicone (f ∘ g) where
  pt := c.pt
  π k := c.π (g k)
  ι k := c.ι (g k)
  ι_π k k' := by
    simp only [c.ι_π]
    split_ifs with h h' h' <;> simp [Equiv.apply_eq_iff_eq g] at h h' <;> 

Proof state:
case neg
J : Type w
C : Type uC
inst✝³ : Category.{uC', uC} C
inst✝² : HasZeroMorphisms C
D : Type uD
inst✝¹ : Category.{uD', uD} D
inst✝ : HasZeroMorphisms D
F : J → C
K : Type w'
f : J → C
c : Bicone f
g : K ≃ J
k k' : K
h✝ : g k = g k'
h' : ¬k = k'
h : k = k'
⊢ eqToHom (_ : f (g k) = f (g k')) = 0

Next tactic:
tauto
/-- Whisker a bicone with an equivalence between the indexing types. -/
@[simps]
def whisker {f : J → C} (c : Bicone f) (g : K ≃ J) : Bicone (f ∘ g) where
  pt := c.pt
  π k := c.π (g k)
  ι k := c.ι (g k)
  ι_π k k' := by
    simp only [c.ι_π]
    split_ifs with h h' h' <;> simp [Equiv.apply_eq_iff_eq g] at h h' <;> 

Proof state:
case pos
J : Type w
C : Type uC
inst✝³ : Category.{uC', uC} C
inst✝² : HasZeroMorphisms C
D : Type uD
inst✝¹ : Category.{uD', uD} D
inst✝ : HasZeroMorphisms D
F : J → C
K : Type w'
f : J → C
c : Bicone f
g : K ≃ J
k k' : K
h' : k = k'
h : ¬k = k'
⊢ 0 = eqToHom (_ : (f ∘ ⇑g) k = (f ∘ ⇑g) k')

Next tactic:
tauto
/-- Whisker a bicone with an equivalence between the indexing types. -/
@[simps]
def whisker {f : J → C} (c : Bicone f) (g : K ≃ J) : Bicone (f ∘ g) where
  pt := c.pt
  π k := c.π (g k)
  ι k := c.ι (g k)
  ι_π k k' := by
    simp only [c.ι_π]
    split_ifs with h h' h' <;> simp [Equiv.apply_eq_iff_eq g] at h h' <;> 

Proof state:
case neg
J : Type w
C : Type uC
inst✝³ : Category.{uC', uC} C
inst✝² : HasZeroMorphisms C
D : Type uD
inst✝¹ : Category.{uD', uD} D
inst✝ : HasZeroMorphisms D
F : J → C
K : Type w'
f : J → C
c : Bicone f
g : K ≃ J
k k' : K
h' h : ¬k = k'
⊢ 0 = 0

Next tactic:
tauto
/-- Taking the cone of a whiskered bicone results in a cone isomorphic to one gained
by whiskering the cone and postcomposing with a suitable isomorphism. -/
def whiskerToCone {f : J → C} (c : Bicone f) (g : K ≃ J) :
    (c.whisker g).toCone ≅
      (Cones.postcompose (Discrete.functorComp f g).inv).obj
        (c.toCone.whisker (Discrete.functor (Discrete.mk ∘ g))) :=
  Cones.ext (Iso.refl _) (by 

Proof state:
J : Type w
C : Type uC
inst✝³ : Category.{uC', uC} C
inst✝² : HasZeroMorphisms C
D : Type uD
inst✝¹ : Category.{uD', uD} D
inst✝ : HasZeroMorphisms D
F : J → C
K : Type w'
f : J → C
c : Bicone f
g : K ≃ J
⊢ ∀ (j : Discrete K),
    (toCone (whisker c g)).π.app j =
      (Iso.refl (toCone (whisker c g)).pt).hom ≫
        ((Cones.postcompose (Discrete.functorComp f ⇑g).inv).obj
                (Cone.whisker (Discrete.functor (Discrete.mk ∘ ⇑g)) (toCone c))).π.app
          j

Next tactic:
aesop_cat
/-- Taking the cocone of a whiskered bicone results in a cone isomorphic to one gained
by whiskering the cocone and precomposing with a suitable isomorphism. -/
def whiskerToCocone {f : J → C} (c : Bicone f) (g : K ≃ J) :
    (c.whisker g).toCocone ≅
      (Cocones.precompose (Discrete.functorComp f g).hom).obj
        (c.toCocone.whisker (Discrete.functor (Discrete.mk ∘ g))) :=
  Cocones.ext (Iso.refl _) (by 

Proof state:
J : Type w
C : Type uC
inst✝³ : Category.{uC', uC} C
inst✝² : HasZeroMorphisms C
D : Type uD
inst✝¹ : Category.{uD', uD} D
inst✝ : HasZeroMorphisms D
F : J → C
K : Type w'
f : J → C
c : Bicone f
g : K ≃ J
⊢ ∀ (j : Discrete K),
    (toCocone (whisker c g)).ι.app j ≫ (Iso.refl (toCocone (whisker c g)).pt).hom =
      ((Cocones.precompose (Discrete.functorComp f ⇑g).hom).obj
              (Cocone.whisker (Discrete.functor (Discrete.mk ∘ ⇑g)) (toCocone c))).ι.app
        j

Next tactic:
aesop_cat
/-- Whiskering a bicone with an equivalence between types preserves being a bilimit bicone. -/
def whiskerIsBilimitIff {f : J → C} (c : Bicone f) (g : K ≃ J) :
    (c.whisker g).IsBilimit ≃ c.IsBilimit := by
  

Proof state:
J : Type w
C : Type uC
inst✝³ : Category.{uC', uC} C
inst✝² : HasZeroMorphisms C
D : Type uD
inst✝¹ : Category.{uD', uD} D
inst✝ : HasZeroMorphisms D
F : J → C
K : Type w'
f : J → C
c : Bicone f
g : K ≃ J
⊢ IsBilimit (whisker c g) ≃ IsBilimit c

Next tactic:
refine' equivOfSubsingletonOfSubsingleton (fun hc => ⟨_, _⟩) fun hc => ⟨_, _⟩
/-- Whiskering a bicone with an equivalence between types preserves being a bilimit bicone. -/
def whiskerIsBilimitIff {f : J → C} (c : Bicone f) (g : K ≃ J) :
    (c.whisker g).IsBilimit ≃ c.IsBilimit := by
  refine' equivOfSubsingletonOfSubsingleton (fun hc => ⟨_, _⟩) fun hc => ⟨_, _⟩
  · 

Proof state:
case refine'_1
J : Type w
C : Type uC
inst✝³ : Category.{uC', uC} C
inst✝² : HasZeroMorphisms C
D : Type uD
inst✝¹ : Category.{uD', uD} D
inst✝ : HasZeroMorphisms D
F : J → C
K : Type w'
f : J → C
c : Bicone f
g : K ≃ J
hc : IsBilimit (whisker c g)
⊢ IsLimit (toCone c)

Next tactic:
let this := IsLimit.ofIsoLimit hc.isLimit (Bicone.whiskerToCone c g)