l3lab/ntp-mathlib huggingface dataset:
/-- This follows this proof from
* Borceux, Handbook of categorical algebra 1, Theorem 2.13.4
although with different names.
-/
theorem colimitLimitToLimitColimit_surjective :
    Function.Surjective (colimitLimitToLimitColimit F) := by
  classical
    -- We begin with some element `x` in the limit (over J) over the colimits (over K),
    intro x
    -- This consists of some coherent family of elements in the various colimits,
    -- and so our first task is to pick representatives of these elements.
    have z := fun j => jointly_surjective'.{v, v} (limit.π (curry.obj F ⋙ Limits.colim) j x)
    -- `k : J ⟶ K` records where the representative of the
    -- element in the `j`-th element of `x` lives
    let k : J → K := fun j => (z j).choose
    -- `y j : F.obj (j, k j)` is the representative
    let y : ∀ j, F.obj (j, k j) := fun j => (z j).choose_spec.choose
    -- and we record that these representatives, when mapped back into the relevant colimits,
    -- are actually the components of `x`.
    have e : ∀ j,
        colimit.ι ((curry.obj F).obj j) (k j) (y j) = limit.π (curry.obj F ⋙ Limits.colim) j x :=
      fun j => (z j).choose_spec.choose_spec
    clear_value k y
    -- A little tidying up of things we no longer need.
    clear z
    -- As a first step, we use that `K` is filtered to pick some point `k' : K` above all the `k j`
    let k' : K := IsFiltered.sup (Finset.univ.image k) ∅
    -- and name the morphisms as `g j : k j ⟶ k'`.
    have g : ∀ j, k j ⟶ k' := fun j => IsFiltered.toSup (Finset.univ.image k) ∅ (by simp)
    clear_value k'
    -- Recalling that the components of `x`, which are indexed by `j : J`, are "coherent",
    -- in other words preserved by morphisms in the `J` direction,
    -- we see that for any morphism `f : j ⟶ j'` in `J`,
    -- the images of `y j` and `y j'`, when mapped to `F.obj (j', k')` respectively by
    -- `(f, g j)` and `(𝟙 j', g j')`, both represent the same element in the colimit.
    have w :
      ∀ {j j' : J} (f : j ⟶ j'),
        colimit.ι ((curry.obj F).obj j') k' (F.map ((𝟙 j', g j') : (j', k j') ⟶ (j', k')) (y j')) =
          colimit.ι ((curry.obj F).obj j') k' (F.map ((f, g j) : (j, k j) ⟶ (j', k')) (y j)) := by
      intro j j' f
      have t : (f, g j) =
          (((f, 𝟙 (k j)) : (j, k j) ⟶ (j', k j)) ≫ (𝟙 j', g j) : (j, k j) ⟶ (j', k')) := by
        simp only [id_comp, comp_id, prod_comp]
      erw [Colimit.w_apply', t, FunctorToTypes.map_comp_apply, Colimit.w_apply', e, ←
        Limit.w_apply' f, ← e]
      

Proof state:
J K : Type v
inst✝³ : SmallCategory J
inst✝² : SmallCategory K
F : J × K ⥤ Type v
inst✝¹ : IsFiltered K
inst✝ : FinCategory J
x : limit (curry.obj F ⋙ colim)
k : J → K
y : (j : J) → F.obj (j, k j)
e : ∀ (j : J), colimit.ι ((curry.obj F).obj j) (k j) (y j) = limit.π (curry.obj F ⋙ colim) j x
k' : K
g : (j : J) → k j ⟶ k'
j j' : J
f : j ⟶ j'
t : (f, g j) = (f, 𝟙 (k j)) ≫ (𝟙 j', g j)
⊢ (curry.obj F ⋙ colim).map f (colimit.ι ((curry.obj F).obj j) (k j) (y j)) =
    colimit.ι ((curry.obj F).obj j') (k j) (F.map (f, 𝟙 (k j)) (y j))

Next tactic:
simp
instance colimitLimitToLimitColimitCone_iso (F : J ⥤ K ⥤ Type v) :
    IsIso (colimitLimitToLimitColimitCone F) := by
  

Proof state:
J K : Type v
inst✝³ : SmallCategory J
inst✝² : SmallCategory K
F✝ : J × K ⥤ Type v
inst✝¹ : IsFiltered K
inst✝ : FinCategory J
F : J ⥤ K ⥤ Type v
⊢ IsIso (colimitLimitToLimitColimitCone F)

Next tactic:
have : IsIso (colimitLimitToLimitColimitCone F).hom := by
    suffices IsIso (colimitLimitToLimitColimit (uncurry.obj F) ≫
        lim.map (whiskerRight (currying.unitIso.app F).inv colim)) by
      apply IsIso.comp_isIso
    infer_instance
instance colimitLimitToLimitColimitCone_iso (F : J ⥤ K ⥤ Type v) :
    IsIso (colimitLimitToLimitColimitCone F) := by
  have : IsIso (colimitLimitToLimitColimitCone F).hom := by
    

Proof state:
J K : Type v
inst✝³ : SmallCategory J
inst✝² : SmallCategory K
F✝ : J × K ⥤ Type v
inst✝¹ : IsFiltered K
inst✝ : FinCategory J
F : J ⥤ K ⥤ Type v
⊢ IsIso (colimitLimitToLimitColimitCone F).hom

Next tactic:
suffices IsIso (colimitLimitToLimitColimit (uncurry.obj F) ≫
        lim.map (whiskerRight (currying.unitIso.app F).inv colim)) by
      apply IsIso.comp_isIso
instance colimitLimitToLimitColimitCone_iso (F : J ⥤ K ⥤ Type v) :
    IsIso (colimitLimitToLimitColimitCone F) := by
  have : IsIso (colimitLimitToLimitColimitCone F).hom := by
    suffices IsIso (colimitLimitToLimitColimit (uncurry.obj F) ≫
        lim.map (whiskerRight (currying.unitIso.app F).inv colim)) by
      

Proof state:
J K : Type v
inst✝³ : SmallCategory J
inst✝² : SmallCategory K
F✝ : J × K ⥤ Type v
inst✝¹ : IsFiltered K
inst✝ : FinCategory J
F : J ⥤ K ⥤ Type v
this : IsIso (colimitLimitToLimitColimit (uncurry.obj F) ≫ lim.map (whiskerRight (currying.unitIso.app F).inv colim))
⊢ IsIso (colimitLimitToLimitColimitCone F).hom

Next tactic:
apply IsIso.comp_isIso
instance colimitLimitToLimitColimitCone_iso (F : J ⥤ K ⥤ Type v) :
    IsIso (colimitLimitToLimitColimitCone F) := by
  have : IsIso (colimitLimitToLimitColimitCone F).hom := by
    suffices IsIso (colimitLimitToLimitColimit (uncurry.obj F) ≫
        lim.map (whiskerRight (currying.unitIso.app F).inv colim)) by
      apply IsIso.comp_isIso
    

Proof state:
J K : Type v
inst✝³ : SmallCategory J
inst✝² : SmallCategory K
F✝ : J × K ⥤ Type v
inst✝¹ : IsFiltered K
inst✝ : FinCategory J
F : J ⥤ K ⥤ Type v
⊢ IsIso (colimitLimitToLimitColimit (uncurry.obj F) ≫ lim.map (whiskerRight (currying.unitIso.app F).inv colim))

Next tactic:
infer_instance
instance colimitLimitToLimitColimitCone_iso (F : J ⥤ K ⥤ Type v) :
    IsIso (colimitLimitToLimitColimitCone F) := by
  have : IsIso (colimitLimitToLimitColimitCone F).hom := by
    suffices IsIso (colimitLimitToLimitColimit (uncurry.obj F) ≫
        lim.map (whiskerRight (currying.unitIso.app F).inv colim)) by
      apply IsIso.comp_isIso
    infer_instance
  

Proof state:
J K : Type v
inst✝³ : SmallCategory J
inst✝² : SmallCategory K
F✝ : J × K ⥤ Type v
inst✝¹ : IsFiltered K
inst✝ : FinCategory J
F : J ⥤ K ⥤ Type v
this : IsIso (colimitLimitToLimitColimitCone F).hom
⊢ IsIso (colimitLimitToLimitColimitCone F)

Next tactic:
apply Cones.cone_iso_of_hom_iso
noncomputable instance filteredColimPreservesFiniteLimitsOfTypes :
    PreservesFiniteLimits (colim : (K ⥤ Type v) ⥤ _) := by
  

Proof state:
J K : Type v
inst✝³ : SmallCategory J
inst✝² : SmallCategory K
F : J × K ⥤ Type v
inst✝¹ : IsFiltered K
inst✝ : FinCategory J
⊢ PreservesFiniteLimits colim

Next tactic:
apply preservesFiniteLimitsOfPreservesFiniteLimitsOfSize.{v}
noncomputable instance filteredColimPreservesFiniteLimitsOfTypes :
    PreservesFiniteLimits (colim : (K ⥤ Type v) ⥤ _) := by
  apply preservesFiniteLimitsOfPreservesFiniteLimitsOfSize.{v}
  

Proof state:
case h
J K : Type v
inst✝³ : SmallCategory J
inst✝² : SmallCategory K
F : J × K ⥤ Type v
inst✝¹ : IsFiltered K
inst✝ : FinCategory J
⊢ (J : Type v) → {𝒥 : SmallCategory J} → FinCategory J → PreservesLimitsOfShape J colim

Next tactic:
intro J _ _
noncomputable instance filteredColimPreservesFiniteLimitsOfTypes :
    PreservesFiniteLimits (colim : (K ⥤ Type v) ⥤ _) := by
  apply preservesFiniteLimitsOfPreservesFiniteLimitsOfSize.{v}
  intro J _ _
  

Proof state:
case h
J✝ K : Type v
inst✝³ : SmallCategory J✝
inst✝² : SmallCategory K
F : J✝ × K ⥤ Type v
inst✝¹ : IsFiltered K
inst✝ : FinCategory J✝
J : Type v
𝒥✝ : SmallCategory J
x✝ : FinCategory J
⊢ PreservesLimitsOfShape J colim

Next tactic:
refine ⟨fun {F} => ⟨fun {c} hc => IsLimit.ofIsoLimit (limit.isLimit _) ?_⟩⟩
noncomputable instance filteredColimPreservesFiniteLimitsOfTypes :
    PreservesFiniteLimits (colim : (K ⥤ Type v) ⥤ _) := by
  apply preservesFiniteLimitsOfPreservesFiniteLimitsOfSize.{v}
  intro J _ _
  refine ⟨fun {F} => ⟨fun {c} hc => IsLimit.ofIsoLimit (limit.isLimit _) ?_⟩⟩
  

Proof state:
case h
J✝ K : Type v
inst✝³ : SmallCategory J✝
inst✝² : SmallCategory K
F✝ : J✝ × K ⥤ Type v
inst✝¹ : IsFiltered K
inst✝ : FinCategory J✝
J : Type v
𝒥✝ : SmallCategory J
x✝ : FinCategory J
F : J ⥤ K ⥤ Type v
c : Cone F
hc : IsLimit c
⊢ limit.cone (F ⋙ colim) ≅ colim.mapCone c

Next tactic:
symm
noncomputable instance filteredColimPreservesFiniteLimitsOfTypes :
    PreservesFiniteLimits (colim : (K ⥤ Type v) ⥤ _) := by
  apply preservesFiniteLimitsOfPreservesFiniteLimitsOfSize.{v}
  intro J _ _
  refine ⟨fun {F} => ⟨fun {c} hc => IsLimit.ofIsoLimit (limit.isLimit _) ?_⟩⟩
  symm
  

Proof state:
case h
J✝ K : Type v
inst✝³ : SmallCategory J✝
inst✝² : SmallCategory K
F✝ : J✝ × K ⥤ Type v
inst✝¹ : IsFiltered K
inst✝ : FinCategory J✝
J : Type v
𝒥✝ : SmallCategory J
x✝ : FinCategory J
F : J ⥤ K ⥤ Type v
c : Cone F
hc : IsLimit c
⊢ colim.mapCone c ≅ limit.cone (F ⋙ colim)

Next tactic:
trans colim.mapCone (limit.cone F)
noncomputable instance filteredColimPreservesFiniteLimitsOfTypes :
    PreservesFiniteLimits (colim : (K ⥤ Type v) ⥤ _) := by
  apply preservesFiniteLimitsOfPreservesFiniteLimitsOfSize.{v}
  intro J _ _
  refine ⟨fun {F} => ⟨fun {c} hc => IsLimit.ofIsoLimit (limit.isLimit _) ?_⟩⟩
  symm
  trans colim.mapCone (limit.cone F)
  · 

Proof state:
J✝ K : Type v
inst✝³ : SmallCategory J✝
inst✝² : SmallCategory K
F✝ : J✝ × K ⥤ Type v
inst✝¹ : IsFiltered K
inst✝ : FinCategory J✝
J : Type v
𝒥✝ : SmallCategory J
x✝ : FinCategory J
F : J ⥤ K ⥤ Type v
c : Cone F
hc : IsLimit c
⊢ colim.mapCone c ≅ colim.mapCone (limit.cone F)

Next tactic:
exact Functor.mapIso _ (hc.uniqueUpToIso (limit.isLimit F))
noncomputable instance filteredColimPreservesFiniteLimitsOfTypes :
    PreservesFiniteLimits (colim : (K ⥤ Type v) ⥤ _) := by
  apply preservesFiniteLimitsOfPreservesFiniteLimitsOfSize.{v}
  intro J _ _
  refine ⟨fun {F} => ⟨fun {c} hc => IsLimit.ofIsoLimit (limit.isLimit _) ?_⟩⟩
  symm
  trans colim.mapCone (limit.cone F)
  · exact Functor.mapIso _ (hc.uniqueUpToIso (limit.isLimit F))
  · 

Proof state:
J✝ K : Type v
inst✝³ : SmallCategory J✝
inst✝² : SmallCategory K
F✝ : J✝ × K ⥤ Type v
inst✝¹ : IsFiltered K
inst✝ : FinCategory J✝
J : Type v
𝒥✝ : SmallCategory J
x✝ : FinCategory J
F : J ⥤ K ⥤ Type v
c : Cone F
hc : IsLimit c
⊢ colim.mapCone (limit.cone F) ≅ limit.cone (F ⋙ colim)

Next tactic:
exact asIso (colimitLimitToLimitColimitCone.{v, v + 1} F)
noncomputable instance [PreservesFiniteLimits (forget C)] [PreservesFilteredColimits (forget C)]
    [HasFiniteLimits C] [HasColimitsOfShape K C] [ReflectsIsomorphisms (forget C)] :
    PreservesFiniteLimits (colim : (K ⥤ C) ⥤ _) := by
  

Proof state:
J K : Type v
inst✝¹⁰ : SmallCategory J
inst✝⁹ : SmallCategory K
F : J × K ⥤ Type v
inst✝⁸ : IsFiltered K
inst✝⁷ : FinCategory J
C : Type u
inst✝⁶ : Category.{v, u} C
inst✝⁵ : ConcreteCategory C
inst✝⁴ : PreservesFiniteLimits (forget C)
inst✝³ : PreservesFilteredColimits (forget C)
inst✝² : HasFiniteLimits C
inst✝¹ : HasColimitsOfShape K C
inst✝ : ReflectsIsomorphisms (forget C)
⊢ PreservesFiniteLimits colim

Next tactic:
apply preservesFiniteLimitsOfPreservesFiniteLimitsOfSize.{v}
noncomputable instance [PreservesFiniteLimits (forget C)] [PreservesFilteredColimits (forget C)]
    [HasFiniteLimits C] [HasColimitsOfShape K C] [ReflectsIsomorphisms (forget C)] :
    PreservesFiniteLimits (colim : (K ⥤ C) ⥤ _) := by
  apply preservesFiniteLimitsOfPreservesFiniteLimitsOfSize.{v}
  

Proof state:
case h
J K : Type v
inst✝¹⁰ : SmallCategory J
inst✝⁹ : SmallCategory K
F : J × K ⥤ Type v
inst✝⁸ : IsFiltered K
inst✝⁷ : FinCategory J
C : Type u
inst✝⁶ : Category.{v, u} C
inst✝⁵ : ConcreteCategory C
inst✝⁴ : PreservesFiniteLimits (forget C)
inst✝³ : PreservesFilteredColimits (forget C)
inst✝² : HasFiniteLimits C
inst✝¹ : HasColimitsOfShape K C
inst✝ : ReflectsIsomorphisms (forget C)
⊢ (J : Type v) → {𝒥 : SmallCategory J} → FinCategory J → PreservesLimitsOfShape J colim

Next tactic:
intro J _ _
noncomputable instance [PreservesFiniteLimits (forget C)] [PreservesFilteredColimits (forget C)]
    [HasFiniteLimits C] [HasColimitsOfShape K C] [ReflectsIsomorphisms (forget C)] :
    PreservesFiniteLimits (colim : (K ⥤ C) ⥤ _) := by
  apply preservesFiniteLimitsOfPreservesFiniteLimitsOfSize.{v}
  intro J _ _
  

Proof state:
case h
J✝ K : Type v
inst✝¹⁰ : SmallCategory J✝
inst✝⁹ : SmallCategory K
F : J✝ × K ⥤ Type v
inst✝⁸ : IsFiltered K
inst✝⁷ : FinCategory J✝
C : Type u
inst✝⁶ : Category.{v, u} C
inst✝⁵ : ConcreteCategory C
inst✝⁴ : PreservesFiniteLimits (forget C)
inst✝³ : PreservesFilteredColimits (forget C)
inst✝² : HasFiniteLimits C
inst✝¹ : HasColimitsOfShape K C
inst✝ : ReflectsIsomorphisms (forget C)
J : Type v
𝒥✝ : SmallCategory J
x✝ : FinCategory J
⊢ PreservesLimitsOfShape J colim

Next tactic:
infer_instance
@[reassoc (attr := simp)]
theorem ι_colimitLimitIso_limit_π (F : J ⥤ K ⥤ C) (a) (b) :
    colimit.ι (limit F) a ≫ (colimitLimitIso F).hom ≫ limit.π (colimit F.flip) b =
      (limit.π F b).app a ≫ (colimit.ι F.flip a).app b := by
  

Proof state:
J K : Type v
inst✝¹⁰ : SmallCategory J
inst✝⁹ : SmallCategory K
F✝ : J × K ⥤ Type v
inst✝⁸ : IsFiltered K
inst✝⁷ : FinCategory J
C : Type u
inst✝⁶ : Category.{v, u} C
inst✝⁵ : ConcreteCategory C
inst✝⁴ : HasLimitsOfShape J C
inst✝³ : HasColimitsOfShape K C
inst✝² : ReflectsLimitsOfShape J (forget C)
inst✝¹ : PreservesColimitsOfShape K (forget C)
inst✝ : PreservesLimitsOfShape J (forget C)
F : J ⥤ K ⥤ C
a : K
b : J
⊢ colimit.ι (limit F) a ≫ (colimitLimitIso F).hom ≫ limit.π (colimit (Functor.flip F)) b =
    (limit.π F b).app a ≫ (colimit.ι (Functor.flip F) a).app b

Next tactic:
dsimp [colimitLimitIso]
@[reassoc (attr := simp)]
theorem ι_colimitLimitIso_limit_π (F : J ⥤ K ⥤ C) (a) (b) :
    colimit.ι (limit F) a ≫ (colimitLimitIso F).hom ≫ limit.π (colimit F.flip) b =
      (limit.π F b).app a ≫ (colimit.ι F.flip a).app b := by
  dsimp [colimitLimitIso]
  

Proof state:
J K : Type v
inst✝¹⁰ : SmallCategory J
inst✝⁹ : SmallCategory K
F✝ : J × K ⥤ Type v
inst✝⁸ : IsFiltered K
inst✝⁷ : FinCategory J
C : Type u
inst✝⁶ : Category.{v, u} C
inst✝⁵ : ConcreteCategory C
inst✝⁴ : HasLimitsOfShape J C
inst✝³ : HasColimitsOfShape K C
inst✝² : ReflectsLimitsOfShape J (forget C)
inst✝¹ : PreservesColimitsOfShape K (forget C)
inst✝ : PreservesLimitsOfShape J (forget C)
F : J ⥤ K ⥤ C
a : K
b : J
⊢ colimit.ι (limit F) a ≫
      ((IsLimit.conePointUniqueUpToIso (isLimitOfPreserves colim (limit.isLimit F)) (limit.isLimit (F ⋙ colim))).hom ≫
          (HasLimit.isoOfNatIso (colimitFlipIsoCompColim F).symm).hom) ≫
        limit.π (colimit (Functor.flip F)) b =
    (limit.π F b).app a ≫ (colimit.ι (Functor.flip F) a).app b

Next tactic:
simp only [Functor.mapCone_π_app, Iso.symm_hom,
    Limits.limit.conePointUniqueUpToIso_hom_comp_assoc, Limits.limit.cone_π,
    Limits.colimit.ι_map_assoc, Limits.colimitFlipIsoCompColim_inv_app, assoc,
    Limits.HasLimit.isoOfNatIso_hom_π]
@[reassoc (attr := simp)]
theorem ι_colimitLimitIso_limit_π (F : J ⥤ K ⥤ C) (a) (b) :
    colimit.ι (limit F) a ≫ (colimitLimitIso F).hom ≫ limit.π (colimit F.flip) b =
      (limit.π F b).app a ≫ (colimit.ι F.flip a).app b := by
  dsimp [colimitLimitIso]
  simp only [Functor.mapCone_π_app, Iso.symm_hom,
    Limits.limit.conePointUniqueUpToIso_hom_comp_assoc, Limits.limit.cone_π,
    Limits.colimit.ι_map_assoc, Limits.colimitFlipIsoCompColim_inv_app, assoc,
    Limits.HasLimit.isoOfNatIso_hom_π]
  

Proof state:
J K : Type v
inst✝¹⁰ : SmallCategory J
inst✝⁹ : SmallCategory K
F✝ : J × K ⥤ Type v
inst✝⁸ : IsFiltered K
inst✝⁷ : FinCategory J
C : Type u
inst✝⁶ : Category.{v, u} C
inst✝⁵ : ConcreteCategory C
inst✝⁴ : HasLimitsOfShape J C
inst✝³ : HasColimitsOfShape K C
inst✝² : ReflectsLimitsOfShape J (forget C)
inst✝¹ : PreservesColimitsOfShape K (forget C)
inst✝ : PreservesLimitsOfShape J (forget C)
F : J ⥤ K ⥤ C
a : K
b : J
⊢ (limit.π F b).app a ≫
      colimit.ι (F.obj b) a ≫
        (HasColimit.isoOfNatIso (flipCompEvaluation F b)).inv ≫
          (colimitObjIsoColimitCompEvaluation (Functor.flip F) b).inv =
    (limit.π F b).app a ≫ (colimit.ι (Functor.flip F) a).app b

Next tactic:
congr 1
@[reassoc (attr := simp)]
theorem ι_colimitLimitIso_limit_π (F : J ⥤ K ⥤ C) (a) (b) :
    colimit.ι (limit F) a ≫ (colimitLimitIso F).hom ≫ limit.π (colimit F.flip) b =
      (limit.π F b).app a ≫ (colimit.ι F.flip a).app b := by
  dsimp [colimitLimitIso]
  simp only [Functor.mapCone_π_app, Iso.symm_hom,
    Limits.limit.conePointUniqueUpToIso_hom_comp_assoc, Limits.limit.cone_π,
    Limits.colimit.ι_map_assoc, Limits.colimitFlipIsoCompColim_inv_app, assoc,
    Limits.HasLimit.isoOfNatIso_hom_π]
  congr 1
  

Proof state:
case e_a
J K : Type v
inst✝¹⁰ : SmallCategory J
inst✝⁹ : SmallCategory K
F✝ : J × K ⥤ Type v
inst✝⁸ : IsFiltered K
inst✝⁷ : FinCategory J
C : Type u
inst✝⁶ : Category.{v, u} C
inst✝⁵ : ConcreteCategory C
inst✝⁴ : HasLimitsOfShape J C
inst✝³ : HasColimitsOfShape K C
inst✝² : ReflectsLimitsOfShape J (forget C)
inst✝¹ : PreservesColimitsOfShape K (forget C)
inst✝ : PreservesLimitsOfShape J (forget C)
F : J ⥤ K ⥤ C
a : K
b : J
⊢ colimit.ι (F.obj b) a ≫
      (HasColimit.isoOfNatIso (flipCompEvaluation F b)).inv ≫
        (colimitObjIsoColimitCompEvaluation (Functor.flip F) b).inv =
    (colimit.ι (Functor.flip F) a).app b

Next tactic:
simp only [← Category.assoc, Iso.comp_inv_eq,
    Limits.colimitObjIsoColimitCompEvaluation_ι_app_hom,
    Limits.HasColimit.isoOfNatIso_ι_hom, NatIso.ofComponents_hom_app]
@[reassoc (attr := simp)]
theorem ι_colimitLimitIso_limit_π (F : J ⥤ K ⥤ C) (a) (b) :
    colimit.ι (limit F) a ≫ (colimitLimitIso F).hom ≫ limit.π (colimit F.flip) b =
      (limit.π F b).app a ≫ (colimit.ι F.flip a).app b := by
  dsimp [colimitLimitIso]
  simp only [Functor.mapCone_π_app, Iso.symm_hom,
    Limits.limit.conePointUniqueUpToIso_hom_comp_assoc, Limits.limit.cone_π,
    Limits.colimit.ι_map_assoc, Limits.colimitFlipIsoCompColim_inv_app, assoc,
    Limits.HasLimit.isoOfNatIso_hom_π]
  congr 1
  simp only [← Category.assoc, Iso.comp_inv_eq,
    Limits.colimitObjIsoColimitCompEvaluation_ι_app_hom,
    Limits.HasColimit.isoOfNatIso_ι_hom, NatIso.ofComponents_hom_app]
  

Proof state:
case e_a
J K : Type v
inst✝¹⁰ : SmallCategory J
inst✝⁹ : SmallCategory K
F✝ : J × K ⥤ Type v
inst✝⁸ : IsFiltered K
inst✝⁷ : FinCategory J
C : Type u
inst✝⁶ : Category.{v, u} C
inst✝⁵ : ConcreteCategory C
inst✝⁴ : HasLimitsOfShape J C
inst✝³ : HasColimitsOfShape K C
inst✝² : ReflectsLimitsOfShape J (forget C)
inst✝¹ : PreservesColimitsOfShape K (forget C)
inst✝ : PreservesLimitsOfShape J (forget C)
F : J ⥤ K ⥤ C
a : K
b : J
⊢ colimit.ι (F.obj b) a = (flipCompEvaluation F b).hom.app a ≫ colimit.ι (F.obj b) a

Next tactic:
dsimp
@[reassoc (attr := simp)]
theorem ι_colimitLimitIso_limit_π (F : J ⥤ K ⥤ C) (a) (b) :
    colimit.ι (limit F) a ≫ (colimitLimitIso F).hom ≫ limit.π (colimit F.flip) b =
      (limit.π F b).app a ≫ (colimit.ι F.flip a).app b := by
  dsimp [colimitLimitIso]
  simp only [Functor.mapCone_π_app, Iso.symm_hom,
    Limits.limit.conePointUniqueUpToIso_hom_comp_assoc, Limits.limit.cone_π,
    Limits.colimit.ι_map_assoc, Limits.colimitFlipIsoCompColim_inv_app, assoc,
    Limits.HasLimit.isoOfNatIso_hom_π]
  congr 1
  simp only [← Category.assoc, Iso.comp_inv_eq,
    Limits.colimitObjIsoColimitCompEvaluation_ι_app_hom,
    Limits.HasColimit.isoOfNatIso_ι_hom, NatIso.ofComponents_hom_app]
  dsimp
  

Proof state:
case e_a
J K : Type v
inst✝¹⁰ : SmallCategory J
inst✝⁹ : SmallCategory K
F✝ : J × K ⥤ Type v
inst✝⁸ : IsFiltered K
inst✝⁷ : FinCategory J
C : Type u
inst✝⁶ : Category.{v, u} C
inst✝⁵ : ConcreteCategory C
inst✝⁴ : HasLimitsOfShape J C
inst✝³ : HasColimitsOfShape K C
inst✝² : ReflectsLimitsOfShape J (forget C)
inst✝¹ : PreservesColimitsOfShape K (forget C)
inst✝ : PreservesLimitsOfShape J (forget C)
F : J ⥤ K ⥤ C
a : K
b : J
⊢ colimit.ι (F.obj b) a = 𝟙 ((F.obj b).obj a) ≫ colimit.ι (F.obj b) a

Next tactic:
simp
/-- Given `M : Matroid α`, the `IndepMatroid α` whose independent sets are
  the subsets of `M.E` that are disjoint from some base of `M` -/
@[simps] def dualIndepMatroid (M : Matroid α) : IndepMatroid α where
  E := M.E
  Indep I := I ⊆ M.E ∧ ∃ B, M.Base B ∧ Disjoint I B
  indep_empty := ⟨empty_subset M.E, M.exists_base.imp (fun B hB ↦ ⟨hB, empty_disjoint _⟩)⟩
  indep_subset := by
    

Proof state:
α : Type u_1
M✝ : Matroid α
I B X : Set α
M : Matroid α
⊢ ∀ ⦃I J : Set α⦄,
    (fun I => I ⊆ M.E ∧ ∃ B, M.Base B ∧ Disjoint I B) J → I ⊆ J → (fun I => I ⊆ M.E ∧ ∃ B, M.Base B ∧ Disjoint I B) I

Next tactic:
rintro I J ⟨hJE, B, hB, hJB⟩ hIJ
/-- Given `M : Matroid α`, the `IndepMatroid α` whose independent sets are
  the subsets of `M.E` that are disjoint from some base of `M` -/
@[simps] def dualIndepMatroid (M : Matroid α) : IndepMatroid α where
  E := M.E
  Indep I := I ⊆ M.E ∧ ∃ B, M.Base B ∧ Disjoint I B
  indep_empty := ⟨empty_subset M.E, M.exists_base.imp (fun B hB ↦ ⟨hB, empty_disjoint _⟩)⟩
  indep_subset := by
    rintro I J ⟨hJE, B, hB, hJB⟩ hIJ
    

Proof state:
case intro.intro.intro
α : Type u_1
M✝ : Matroid α
I✝ B✝ X : Set α
M : Matroid α
I J : Set α
hJE : J ⊆ M.E
B : Set α
hB : M.Base B
hJB : Disjoint J B
hIJ : I ⊆ J
⊢ I ⊆ M.E ∧ ∃ B, M.Base B ∧ Disjoint I B

Next tactic:
exact ⟨hIJ.trans hJE, ⟨B, hB, disjoint_of_subset_left hIJ hJB⟩⟩
/-- Given `M : Matroid α`, the `IndepMatroid α` whose independent sets are
  the subsets of `M.E` that are disjoint from some base of `M` -/
@[simps] def dualIndepMatroid (M : Matroid α) : IndepMatroid α where
  E := M.E
  Indep I := I ⊆ M.E ∧ ∃ B, M.Base B ∧ Disjoint I B
  indep_empty := ⟨empty_subset M.E, M.exists_base.imp (fun B hB ↦ ⟨hB, empty_disjoint _⟩)⟩
  indep_subset := by
    rintro I J ⟨hJE, B, hB, hJB⟩ hIJ
    exact ⟨hIJ.trans hJE, ⟨B, hB, disjoint_of_subset_left hIJ hJB⟩⟩
  indep_aug := by
    

Proof state:
α : Type u_1
M✝ : Matroid α
I B X : Set α
M : Matroid α
⊢ ∀ ⦃I B : Set α⦄,
    (fun I => I ⊆ M.E ∧ ∃ B, M.Base B ∧ Disjoint I B) I →
      I ∉ maximals (fun x x_1 => x ⊆ x_1) {I | (fun I => I ⊆ M.E ∧ ∃ B, M.Base B ∧ Disjoint I B) I} →
        B ∈ maximals (fun x x_1 => x ⊆ x_1) {I | (fun I => I ⊆ M.E ∧ ∃ B, M.Base B ∧ Disjoint I B) I} →
          ∃ x ∈ B \ I, (fun I => I ⊆ M.E ∧ ∃ B, M.Base B ∧ Disjoint I B) (insert x I)

Next tactic:
rintro I X ⟨hIE, B, hB, hIB⟩ hI_not_max hX_max
/-- Given `M : Matroid α`, the `IndepMatroid α` whose independent sets are
  the subsets of `M.E` that are disjoint from some base of `M` -/
@[simps] def dualIndepMatroid (M : Matroid α) : IndepMatroid α where
  E := M.E
  Indep I := I ⊆ M.E ∧ ∃ B, M.Base B ∧ Disjoint I B
  indep_empty := ⟨empty_subset M.E, M.exists_base.imp (fun B hB ↦ ⟨hB, empty_disjoint _⟩)⟩
  indep_subset := by
    rintro I J ⟨hJE, B, hB, hJB⟩ hIJ
    exact ⟨hIJ.trans hJE, ⟨B, hB, disjoint_of_subset_left hIJ hJB⟩⟩
  indep_aug := by
    rintro I X ⟨hIE, B, hB, hIB⟩ hI_not_max hX_max
    

Proof state:
case intro.intro.intro
α : Type u_1
M✝ : Matroid α
I✝ B✝ X✝ : Set α
M : Matroid α
I X : Set α
hIE : I ⊆ M.E
B : Set α
hB : M.Base B
hIB : Disjoint I B
hI_not_max : I ∉ maximals (fun x x_1 => x ⊆ x_1) {I | (fun I => I ⊆ M.E ∧ ∃ B, M.Base B ∧ Disjoint I B) I}
hX_max : X ∈ maximals (fun x x_1 => x ⊆ x_1) {I | (fun I => I ⊆ M.E ∧ ∃ B, M.Base B ∧ Disjoint I B) I}
⊢ ∃ x ∈ X \ I, (fun I => I ⊆ M.E ∧ ∃ B, M.Base B ∧ Disjoint I B) (insert x I)

Next tactic:
have hXE := hX_max.1.1
/-- Given `M : Matroid α`, the `IndepMatroid α` whose independent sets are
  the subsets of `M.E` that are disjoint from some base of `M` -/
@[simps] def dualIndepMatroid (M : Matroid α) : IndepMatroid α where
  E := M.E
  Indep I := I ⊆ M.E ∧ ∃ B, M.Base B ∧ Disjoint I B
  indep_empty := ⟨empty_subset M.E, M.exists_base.imp (fun B hB ↦ ⟨hB, empty_disjoint _⟩)⟩
  indep_subset := by
    rintro I J ⟨hJE, B, hB, hJB⟩ hIJ
    exact ⟨hIJ.trans hJE, ⟨B, hB, disjoint_of_subset_left hIJ hJB⟩⟩
  indep_aug := by
    rintro I X ⟨hIE, B, hB, hIB⟩ hI_not_max hX_max
    have hXE := hX_max.1.1
    

Proof state:
case intro.intro.intro
α : Type u_1
M✝ : Matroid α
I✝ B✝ X✝ : Set α
M : Matroid α
I X : Set α
hIE : I ⊆ M.E
B : Set α
hB : M.Base B
hIB : Disjoint I B
hI_not_max : I ∉ maximals (fun x x_1 => x ⊆ x_1) {I | (fun I => I ⊆ M.E ∧ ∃ B, M.Base B ∧ Disjoint I B) I}
hX_max : X ∈ maximals (fun x x_1 => x ⊆ x_1) {I | (fun I => I ⊆ M.E ∧ ∃ B, M.Base B ∧ Disjoint I B) I}
hXE : X ⊆ M.E
⊢ ∃ x ∈ X \ I, (fun I => I ⊆ M.E ∧ ∃ B, M.Base B ∧ Disjoint I B) (insert x I)

Next tactic:
have hB' := (base_compl_iff_mem_maximals_disjoint_base hXE).mpr hX_max