l3lab/ntp-mathlib huggingface dataset:
/-- If `F : C ⥤ D` is a representably flat functor between small categories, then the functor
`Lan F.op` that takes presheaves over `C` to presheaves over `D` preserves finite limits.
-/
noncomputable instance lanPreservesFiniteLimitsOfFlat (F : C ⥤ D) [RepresentablyFlat F] :
    PreservesFiniteLimits (lan F.op : _ ⥤ Dᵒᵖ ⥤ E) := by
  apply preservesFiniteLimitsOfPreservesFiniteLimitsOfSize.{u₁}
  intro J _ _; skip
  apply preservesLimitsOfShapeOfEvaluation (lan F.op : (Cᵒᵖ ⥤ E) ⥤ Dᵒᵖ ⥤ E) J
  intro K
  haveI : IsFiltered (CostructuredArrow F.op K) :=
    IsFiltered.of_equivalence (structuredArrowOpEquivalence F (unop K))
  

Proof state:
case h
C D : Type u₁
inst✝⁹ : SmallCategory C
inst✝⁸ : SmallCategory D
E : Type u₂
inst✝⁷ : Category.{u₁, u₂} E
inst✝⁶ : ConcreteCategory E
inst✝⁵ : HasLimits E
inst✝⁴ : HasColimits E
inst✝³ : ReflectsLimits (forget E)
inst✝² : PreservesFilteredColimits (forget E)
inst✝¹ : PreservesLimits (forget E)
F : C ⥤ D
inst✝ : RepresentablyFlat F
J : Type u₁
𝒥✝ : SmallCategory J
x✝ : FinCategory J
K : Dᵒᵖ
this : IsFiltered (CostructuredArrow F.op K)
⊢ PreservesLimitsOfShape J (lan F.op ⋙ (evaluation Dᵒᵖ E).obj K)

Next tactic:
exact preservesLimitsOfShapeOfNatIso (lanEvaluationIsoColim _ _ _).symm
noncomputable instance lanPreservesFiniteLimitsOfPreservesFiniteLimits (F : C ⥤ D)
    [PreservesFiniteLimits F] : PreservesFiniteLimits (lan F.op : _ ⥤ Dᵒᵖ ⥤ E) := by
  

Proof state:
C D : Type u₁
inst✝¹⁰ : SmallCategory C
inst✝⁹ : SmallCategory D
E : Type u₂
inst✝⁸ : Category.{u₁, u₂} E
inst✝⁷ : ConcreteCategory E
inst✝⁶ : HasLimits E
inst✝⁵ : HasColimits E
inst✝⁴ : ReflectsLimits (forget E)
inst✝³ : PreservesFilteredColimits (forget E)
inst✝² : PreservesLimits (forget E)
inst✝¹ : HasFiniteLimits C
F : C ⥤ D
inst✝ : PreservesFiniteLimits F
⊢ PreservesFiniteLimits (lan F.op)

Next tactic:
haveI := flat_of_preservesFiniteLimits F
noncomputable instance lanPreservesFiniteLimitsOfPreservesFiniteLimits (F : C ⥤ D)
    [PreservesFiniteLimits F] : PreservesFiniteLimits (lan F.op : _ ⥤ Dᵒᵖ ⥤ E) := by
  haveI := flat_of_preservesFiniteLimits F
  

Proof state:
C D : Type u₁
inst✝¹⁰ : SmallCategory C
inst✝⁹ : SmallCategory D
E : Type u₂
inst✝⁸ : Category.{u₁, u₂} E
inst✝⁷ : ConcreteCategory E
inst✝⁶ : HasLimits E
inst✝⁵ : HasColimits E
inst✝⁴ : ReflectsLimits (forget E)
inst✝³ : PreservesFilteredColimits (forget E)
inst✝² : PreservesLimits (forget E)
inst✝¹ : HasFiniteLimits C
F : C ⥤ D
inst✝ : PreservesFiniteLimits F
this : RepresentablyFlat F
⊢ PreservesFiniteLimits (lan F.op)

Next tactic:
infer_instance
theorem flat_iff_lan_flat (F : C ⥤ D) :
    RepresentablyFlat F ↔ RepresentablyFlat (lan F.op : _ ⥤ Dᵒᵖ ⥤ Type u₁) :=
  ⟨fun H => inferInstance, fun H => by
    

Proof state:
C D : Type u₁
inst✝⁹ : SmallCategory C
inst✝⁸ : SmallCategory D
E : Type u₂
inst✝⁷ : Category.{u₁, u₂} E
inst✝⁶ : ConcreteCategory E
inst✝⁵ : HasLimits E
inst✝⁴ : HasColimits E
inst✝³ : ReflectsLimits (forget E)
inst✝² : PreservesFilteredColimits (forget E)
inst✝¹ : PreservesLimits (forget E)
inst✝ : HasFiniteLimits C
F : C ⥤ D
H : RepresentablyFlat (lan F.op)
⊢ RepresentablyFlat F

Next tactic:
skip
theorem flat_iff_lan_flat (F : C ⥤ D) :
    RepresentablyFlat F ↔ RepresentablyFlat (lan F.op : _ ⥤ Dᵒᵖ ⥤ Type u₁) :=
  ⟨fun H => inferInstance, fun H => by
    skip
    

Proof state:
C D : Type u₁
inst✝⁹ : SmallCategory C
inst✝⁸ : SmallCategory D
E : Type u₂
inst✝⁷ : Category.{u₁, u₂} E
inst✝⁶ : ConcreteCategory E
inst✝⁵ : HasLimits E
inst✝⁴ : HasColimits E
inst✝³ : ReflectsLimits (forget E)
inst✝² : PreservesFilteredColimits (forget E)
inst✝¹ : PreservesLimits (forget E)
inst✝ : HasFiniteLimits C
F : C ⥤ D
H : RepresentablyFlat (lan F.op)
⊢ RepresentablyFlat F

Next tactic:
haveI := preservesFiniteLimitsOfFlat (lan F.op : _ ⥤ Dᵒᵖ ⥤ Type u₁)
theorem flat_iff_lan_flat (F : C ⥤ D) :
    RepresentablyFlat F ↔ RepresentablyFlat (lan F.op : _ ⥤ Dᵒᵖ ⥤ Type u₁) :=
  ⟨fun H => inferInstance, fun H => by
    skip
    haveI := preservesFiniteLimitsOfFlat (lan F.op : _ ⥤ Dᵒᵖ ⥤ Type u₁)
    

Proof state:
C D : Type u₁
inst✝⁹ : SmallCategory C
inst✝⁸ : SmallCategory D
E : Type u₂
inst✝⁷ : Category.{u₁, u₂} E
inst✝⁶ : ConcreteCategory E
inst✝⁵ : HasLimits E
inst✝⁴ : HasColimits E
inst✝³ : ReflectsLimits (forget E)
inst✝² : PreservesFilteredColimits (forget E)
inst✝¹ : PreservesLimits (forget E)
inst✝ : HasFiniteLimits C
F : C ⥤ D
H : RepresentablyFlat (lan F.op)
this : PreservesFiniteLimits (lan F.op)
⊢ RepresentablyFlat F

Next tactic:
haveI : PreservesFiniteLimits F := by
      apply preservesFiniteLimitsOfPreservesFiniteLimitsOfSize.{u₁}
      intros; skip; apply preservesLimitOfLanPreservesLimit
theorem flat_iff_lan_flat (F : C ⥤ D) :
    RepresentablyFlat F ↔ RepresentablyFlat (lan F.op : _ ⥤ Dᵒᵖ ⥤ Type u₁) :=
  ⟨fun H => inferInstance, fun H => by
    skip
    haveI := preservesFiniteLimitsOfFlat (lan F.op : _ ⥤ Dᵒᵖ ⥤ Type u₁)
    haveI : PreservesFiniteLimits F := by
      

Proof state:
C D : Type u₁
inst✝⁹ : SmallCategory C
inst✝⁸ : SmallCategory D
E : Type u₂
inst✝⁷ : Category.{u₁, u₂} E
inst✝⁶ : ConcreteCategory E
inst✝⁵ : HasLimits E
inst✝⁴ : HasColimits E
inst✝³ : ReflectsLimits (forget E)
inst✝² : PreservesFilteredColimits (forget E)
inst✝¹ : PreservesLimits (forget E)
inst✝ : HasFiniteLimits C
F : C ⥤ D
H : RepresentablyFlat (lan F.op)
this : PreservesFiniteLimits (lan F.op)
⊢ PreservesFiniteLimits F

Next tactic:
apply preservesFiniteLimitsOfPreservesFiniteLimitsOfSize.{u₁}
theorem flat_iff_lan_flat (F : C ⥤ D) :
    RepresentablyFlat F ↔ RepresentablyFlat (lan F.op : _ ⥤ Dᵒᵖ ⥤ Type u₁) :=
  ⟨fun H => inferInstance, fun H => by
    skip
    haveI := preservesFiniteLimitsOfFlat (lan F.op : _ ⥤ Dᵒᵖ ⥤ Type u₁)
    haveI : PreservesFiniteLimits F := by
      apply preservesFiniteLimitsOfPreservesFiniteLimitsOfSize.{u₁}
      

Proof state:
case h
C D : Type u₁
inst✝⁹ : SmallCategory C
inst✝⁸ : SmallCategory D
E : Type u₂
inst✝⁷ : Category.{u₁, u₂} E
inst✝⁶ : ConcreteCategory E
inst✝⁵ : HasLimits E
inst✝⁴ : HasColimits E
inst✝³ : ReflectsLimits (forget E)
inst✝² : PreservesFilteredColimits (forget E)
inst✝¹ : PreservesLimits (forget E)
inst✝ : HasFiniteLimits C
F : C ⥤ D
H : RepresentablyFlat (lan F.op)
this : PreservesFiniteLimits (lan F.op)
⊢ (J : Type u₁) → {𝒥 : SmallCategory J} → FinCategory J → PreservesLimitsOfShape J F

Next tactic:
intros
theorem flat_iff_lan_flat (F : C ⥤ D) :
    RepresentablyFlat F ↔ RepresentablyFlat (lan F.op : _ ⥤ Dᵒᵖ ⥤ Type u₁) :=
  ⟨fun H => inferInstance, fun H => by
    skip
    haveI := preservesFiniteLimitsOfFlat (lan F.op : _ ⥤ Dᵒᵖ ⥤ Type u₁)
    haveI : PreservesFiniteLimits F := by
      apply preservesFiniteLimitsOfPreservesFiniteLimitsOfSize.{u₁}
      intros; 

Proof state:
case h
C D : Type u₁
inst✝⁹ : SmallCategory C
inst✝⁸ : SmallCategory D
E : Type u₂
inst✝⁷ : Category.{u₁, u₂} E
inst✝⁶ : ConcreteCategory E
inst✝⁵ : HasLimits E
inst✝⁴ : HasColimits E
inst✝³ : ReflectsLimits (forget E)
inst✝² : PreservesFilteredColimits (forget E)
inst✝¹ : PreservesLimits (forget E)
inst✝ : HasFiniteLimits C
F : C ⥤ D
H : RepresentablyFlat (lan F.op)
this : PreservesFiniteLimits (lan F.op)
J✝ : Type u₁
𝒥✝ : SmallCategory J✝
x✝ : FinCategory J✝
⊢ PreservesLimitsOfShape J✝ F

Next tactic:
skip
theorem flat_iff_lan_flat (F : C ⥤ D) :
    RepresentablyFlat F ↔ RepresentablyFlat (lan F.op : _ ⥤ Dᵒᵖ ⥤ Type u₁) :=
  ⟨fun H => inferInstance, fun H => by
    skip
    haveI := preservesFiniteLimitsOfFlat (lan F.op : _ ⥤ Dᵒᵖ ⥤ Type u₁)
    haveI : PreservesFiniteLimits F := by
      apply preservesFiniteLimitsOfPreservesFiniteLimitsOfSize.{u₁}
      intros; skip; 

Proof state:
case h
C D : Type u₁
inst✝⁹ : SmallCategory C
inst✝⁸ : SmallCategory D
E : Type u₂
inst✝⁷ : Category.{u₁, u₂} E
inst✝⁶ : ConcreteCategory E
inst✝⁵ : HasLimits E
inst✝⁴ : HasColimits E
inst✝³ : ReflectsLimits (forget E)
inst✝² : PreservesFilteredColimits (forget E)
inst✝¹ : PreservesLimits (forget E)
inst✝ : HasFiniteLimits C
F : C ⥤ D
H : RepresentablyFlat (lan F.op)
this : PreservesFiniteLimits (lan F.op)
J✝ : Type u₁
𝒥✝ : SmallCategory J✝
x✝ : FinCategory J✝
⊢ PreservesLimitsOfShape J✝ F

Next tactic:
apply preservesLimitOfLanPreservesLimit
theorem flat_iff_lan_flat (F : C ⥤ D) :
    RepresentablyFlat F ↔ RepresentablyFlat (lan F.op : _ ⥤ Dᵒᵖ ⥤ Type u₁) :=
  ⟨fun H => inferInstance, fun H => by
    skip
    haveI := preservesFiniteLimitsOfFlat (lan F.op : _ ⥤ Dᵒᵖ ⥤ Type u₁)
    haveI : PreservesFiniteLimits F := by
      apply preservesFiniteLimitsOfPreservesFiniteLimitsOfSize.{u₁}
      intros; skip; apply preservesLimitOfLanPreservesLimit
    

Proof state:
C D : Type u₁
inst✝⁹ : SmallCategory C
inst✝⁸ : SmallCategory D
E : Type u₂
inst✝⁷ : Category.{u₁, u₂} E
inst✝⁶ : ConcreteCategory E
inst✝⁵ : HasLimits E
inst✝⁴ : HasColimits E
inst✝³ : ReflectsLimits (forget E)
inst✝² : PreservesFilteredColimits (forget E)
inst✝¹ : PreservesLimits (forget E)
inst✝ : HasFiniteLimits C
F : C ⥤ D
H : RepresentablyFlat (lan F.op)
this✝ : PreservesFiniteLimits (lan F.op)
this : PreservesFiniteLimits F
⊢ RepresentablyFlat F

Next tactic:
apply flat_of_preservesFiniteLimits
/-- If `C` is finitely complete, then `F : C ⥤ D` preserves finite limits iff
`Lan F.op : (Cᵒᵖ ⥤ Type*) ⥤ (Dᵒᵖ ⥤ Type*)` preserves finite limits.
-/
noncomputable def preservesFiniteLimitsIffLanPreservesFiniteLimits (F : C ⥤ D) :
    PreservesFiniteLimits F ≃ PreservesFiniteLimits (lan F.op : _ ⥤ Dᵒᵖ ⥤ Type u₁) where
  toFun _ := inferInstance
  invFun _ := by
    

Proof state:
C D : Type u₁
inst✝⁹ : SmallCategory C
inst✝⁸ : SmallCategory D
E : Type u₂
inst✝⁷ : Category.{u₁, u₂} E
inst✝⁶ : ConcreteCategory E
inst✝⁵ : HasLimits E
inst✝⁴ : HasColimits E
inst✝³ : ReflectsLimits (forget E)
inst✝² : PreservesFilteredColimits (forget E)
inst✝¹ : PreservesLimits (forget E)
inst✝ : HasFiniteLimits C
F : C ⥤ D
x✝ : PreservesFiniteLimits (lan F.op)
⊢ PreservesFiniteLimits F

Next tactic:
apply preservesFiniteLimitsOfPreservesFiniteLimitsOfSize.{u₁}
/-- If `C` is finitely complete, then `F : C ⥤ D` preserves finite limits iff
`Lan F.op : (Cᵒᵖ ⥤ Type*) ⥤ (Dᵒᵖ ⥤ Type*)` preserves finite limits.
-/
noncomputable def preservesFiniteLimitsIffLanPreservesFiniteLimits (F : C ⥤ D) :
    PreservesFiniteLimits F ≃ PreservesFiniteLimits (lan F.op : _ ⥤ Dᵒᵖ ⥤ Type u₁) where
  toFun _ := inferInstance
  invFun _ := by
    apply preservesFiniteLimitsOfPreservesFiniteLimitsOfSize.{u₁}
    

Proof state:
case h
C D : Type u₁
inst✝⁹ : SmallCategory C
inst✝⁸ : SmallCategory D
E : Type u₂
inst✝⁷ : Category.{u₁, u₂} E
inst✝⁶ : ConcreteCategory E
inst✝⁵ : HasLimits E
inst✝⁴ : HasColimits E
inst✝³ : ReflectsLimits (forget E)
inst✝² : PreservesFilteredColimits (forget E)
inst✝¹ : PreservesLimits (forget E)
inst✝ : HasFiniteLimits C
F : C ⥤ D
x✝ : PreservesFiniteLimits (lan F.op)
⊢ (J : Type u₁) → {𝒥 : SmallCategory J} → FinCategory J → PreservesLimitsOfShape J F

Next tactic:
intros
/-- If `C` is finitely complete, then `F : C ⥤ D` preserves finite limits iff
`Lan F.op : (Cᵒᵖ ⥤ Type*) ⥤ (Dᵒᵖ ⥤ Type*)` preserves finite limits.
-/
noncomputable def preservesFiniteLimitsIffLanPreservesFiniteLimits (F : C ⥤ D) :
    PreservesFiniteLimits F ≃ PreservesFiniteLimits (lan F.op : _ ⥤ Dᵒᵖ ⥤ Type u₁) where
  toFun _ := inferInstance
  invFun _ := by
    apply preservesFiniteLimitsOfPreservesFiniteLimitsOfSize.{u₁}
    intros; 

Proof state:
case h
C D : Type u₁
inst✝⁹ : SmallCategory C
inst✝⁸ : SmallCategory D
E : Type u₂
inst✝⁷ : Category.{u₁, u₂} E
inst✝⁶ : ConcreteCategory E
inst✝⁵ : HasLimits E
inst✝⁴ : HasColimits E
inst✝³ : ReflectsLimits (forget E)
inst✝² : PreservesFilteredColimits (forget E)
inst✝¹ : PreservesLimits (forget E)
inst✝ : HasFiniteLimits C
F : C ⥤ D
x✝¹ : PreservesFiniteLimits (lan F.op)
J✝ : Type u₁
𝒥✝ : SmallCategory J✝
x✝ : FinCategory J✝
⊢ PreservesLimitsOfShape J✝ F

Next tactic:
apply preservesLimitOfLanPreservesLimit
/-- If `C` is finitely complete, then `F : C ⥤ D` preserves finite limits iff
`Lan F.op : (Cᵒᵖ ⥤ Type*) ⥤ (Dᵒᵖ ⥤ Type*)` preserves finite limits.
-/
noncomputable def preservesFiniteLimitsIffLanPreservesFiniteLimits (F : C ⥤ D) :
    PreservesFiniteLimits F ≃ PreservesFiniteLimits (lan F.op : _ ⥤ Dᵒᵖ ⥤ Type u₁) where
  toFun _ := inferInstance
  invFun _ := by
    apply preservesFiniteLimitsOfPreservesFiniteLimitsOfSize.{u₁}
    intros; apply preservesLimitOfLanPreservesLimit
  left_inv x := by
    -- porting note: `cases x` and an `unfold` not necessary in lean 4.
    -- Remark : in mathlib3 we had `unfold preservesFiniteLimitsOfFlat`
    -- but there was no `preservesFiniteLimitsOfFlat` in the goal! Experimentation
    -- indicates that it was doing the same as `dsimp only`
    

Proof state:
C D : Type u₁
inst✝⁹ : SmallCategory C
inst✝⁸ : SmallCategory D
E : Type u₂
inst✝⁷ : Category.{u₁, u₂} E
inst✝⁶ : ConcreteCategory E
inst✝⁵ : HasLimits E
inst✝⁴ : HasColimits E
inst✝³ : ReflectsLimits (forget E)
inst✝² : PreservesFilteredColimits (forget E)
inst✝¹ : PreservesLimits (forget E)
inst✝ : HasFiniteLimits C
F : C ⥤ D
x : PreservesFiniteLimits F
⊢ (fun x => preservesFiniteLimitsOfPreservesFiniteLimitsOfSize F fun J {𝒥} x_1 => preservesLimitOfLanPreservesLimit F J)
      ((fun x => inferInstance) x) =
    x

Next tactic:
dsimp only [preservesFiniteLimitsOfPreservesFiniteLimitsOfSize]
/-- If `C` is finitely complete, then `F : C ⥤ D` preserves finite limits iff
`Lan F.op : (Cᵒᵖ ⥤ Type*) ⥤ (Dᵒᵖ ⥤ Type*)` preserves finite limits.
-/
noncomputable def preservesFiniteLimitsIffLanPreservesFiniteLimits (F : C ⥤ D) :
    PreservesFiniteLimits F ≃ PreservesFiniteLimits (lan F.op : _ ⥤ Dᵒᵖ ⥤ Type u₁) where
  toFun _ := inferInstance
  invFun _ := by
    apply preservesFiniteLimitsOfPreservesFiniteLimitsOfSize.{u₁}
    intros; apply preservesLimitOfLanPreservesLimit
  left_inv x := by
    -- porting note: `cases x` and an `unfold` not necessary in lean 4.
    -- Remark : in mathlib3 we had `unfold preservesFiniteLimitsOfFlat`
    -- but there was no `preservesFiniteLimitsOfFlat` in the goal! Experimentation
    -- indicates that it was doing the same as `dsimp only`
    dsimp only [preservesFiniteLimitsOfPreservesFiniteLimitsOfSize]; 

Proof state:
C D : Type u₁
inst✝⁹ : SmallCategory C
inst✝⁸ : SmallCategory D
E : Type u₂
inst✝⁷ : Category.{u₁, u₂} E
inst✝⁶ : ConcreteCategory E
inst✝⁵ : HasLimits E
inst✝⁴ : HasColimits E
inst✝³ : ReflectsLimits (forget E)
inst✝² : PreservesFilteredColimits (forget E)
inst✝¹ : PreservesLimits (forget E)
inst✝ : HasFiniteLimits C
F : C ⥤ D
x : PreservesFiniteLimits F
⊢ PreservesFiniteLimits.mk = x

Next tactic:
congr
/-- If `C` is finitely complete, then `F : C ⥤ D` preserves finite limits iff
`Lan F.op : (Cᵒᵖ ⥤ Type*) ⥤ (Dᵒᵖ ⥤ Type*)` preserves finite limits.
-/
noncomputable def preservesFiniteLimitsIffLanPreservesFiniteLimits (F : C ⥤ D) :
    PreservesFiniteLimits F ≃ PreservesFiniteLimits (lan F.op : _ ⥤ Dᵒᵖ ⥤ Type u₁) where
  toFun _ := inferInstance
  invFun _ := by
    apply preservesFiniteLimitsOfPreservesFiniteLimitsOfSize.{u₁}
    intros; apply preservesLimitOfLanPreservesLimit
  left_inv x := by
    -- porting note: `cases x` and an `unfold` not necessary in lean 4.
    -- Remark : in mathlib3 we had `unfold preservesFiniteLimitsOfFlat`
    -- but there was no `preservesFiniteLimitsOfFlat` in the goal! Experimentation
    -- indicates that it was doing the same as `dsimp only`
    dsimp only [preservesFiniteLimitsOfPreservesFiniteLimitsOfSize]; congr
    -- porting note: next line wasn't necessary in lean 3
    

Proof state:
case e_preservesFiniteLimits
C D : Type u₁
inst✝⁹ : SmallCategory C
inst✝⁸ : SmallCategory D
E : Type u₂
inst✝⁷ : Category.{u₁, u₂} E
inst✝⁶ : ConcreteCategory E
inst✝⁵ : HasLimits E
inst✝⁴ : HasColimits E
inst✝³ : ReflectsLimits (forget E)
inst✝² : PreservesFilteredColimits (forget E)
inst✝¹ : PreservesLimits (forget E)
inst✝ : HasFiniteLimits C
F : C ⥤ D
x : PreservesFiniteLimits F
⊢ (fun J x_1 x_2 => preservesLimitsOfShapeOfEquiv (ULiftHomULiftCategory.equiv J).symm F) =
    PreservesFiniteLimits.preservesFiniteLimits

Next tactic:
apply Subsingleton.elim
/-- If `C` is finitely complete, then `F : C ⥤ D` preserves finite limits iff
`Lan F.op : (Cᵒᵖ ⥤ Type*) ⥤ (Dᵒᵖ ⥤ Type*)` preserves finite limits.
-/
noncomputable def preservesFiniteLimitsIffLanPreservesFiniteLimits (F : C ⥤ D) :
    PreservesFiniteLimits F ≃ PreservesFiniteLimits (lan F.op : _ ⥤ Dᵒᵖ ⥤ Type u₁) where
  toFun _ := inferInstance
  invFun _ := by
    apply preservesFiniteLimitsOfPreservesFiniteLimitsOfSize.{u₁}
    intros; apply preservesLimitOfLanPreservesLimit
  left_inv x := by
    -- porting note: `cases x` and an `unfold` not necessary in lean 4.
    -- Remark : in mathlib3 we had `unfold preservesFiniteLimitsOfFlat`
    -- but there was no `preservesFiniteLimitsOfFlat` in the goal! Experimentation
    -- indicates that it was doing the same as `dsimp only`
    dsimp only [preservesFiniteLimitsOfPreservesFiniteLimitsOfSize]; congr
    -- porting note: next line wasn't necessary in lean 3
    apply Subsingleton.elim
  right_inv x := by
    -- cases x; -- porting note: not necessary in lean 4
    

Proof state:
C D : Type u₁
inst✝⁹ : SmallCategory C
inst✝⁸ : SmallCategory D
E : Type u₂
inst✝⁷ : Category.{u₁, u₂} E
inst✝⁶ : ConcreteCategory E
inst✝⁵ : HasLimits E
inst✝⁴ : HasColimits E
inst✝³ : ReflectsLimits (forget E)
inst✝² : PreservesFilteredColimits (forget E)
inst✝¹ : PreservesLimits (forget E)
inst✝ : HasFiniteLimits C
F : C ⥤ D
x : PreservesFiniteLimits (lan F.op)
⊢ (fun x => inferInstance)
      ((fun x =>
          preservesFiniteLimitsOfPreservesFiniteLimitsOfSize F fun J {𝒥} x_1 => preservesLimitOfLanPreservesLimit F J)
        x) =
    x

Next tactic:
dsimp only [lanPreservesFiniteLimitsOfPreservesFiniteLimits,
      lanPreservesFiniteLimitsOfFlat,
      preservesFiniteLimitsOfPreservesFiniteLimitsOfSize]
/-- If `C` is finitely complete, then `F : C ⥤ D` preserves finite limits iff
`Lan F.op : (Cᵒᵖ ⥤ Type*) ⥤ (Dᵒᵖ ⥤ Type*)` preserves finite limits.
-/
noncomputable def preservesFiniteLimitsIffLanPreservesFiniteLimits (F : C ⥤ D) :
    PreservesFiniteLimits F ≃ PreservesFiniteLimits (lan F.op : _ ⥤ Dᵒᵖ ⥤ Type u₁) where
  toFun _ := inferInstance
  invFun _ := by
    apply preservesFiniteLimitsOfPreservesFiniteLimitsOfSize.{u₁}
    intros; apply preservesLimitOfLanPreservesLimit
  left_inv x := by
    -- porting note: `cases x` and an `unfold` not necessary in lean 4.
    -- Remark : in mathlib3 we had `unfold preservesFiniteLimitsOfFlat`
    -- but there was no `preservesFiniteLimitsOfFlat` in the goal! Experimentation
    -- indicates that it was doing the same as `dsimp only`
    dsimp only [preservesFiniteLimitsOfPreservesFiniteLimitsOfSize]; congr
    -- porting note: next line wasn't necessary in lean 3
    apply Subsingleton.elim
  right_inv x := by
    -- cases x; -- porting note: not necessary in lean 4
    dsimp only [lanPreservesFiniteLimitsOfPreservesFiniteLimits,
      lanPreservesFiniteLimitsOfFlat,
      preservesFiniteLimitsOfPreservesFiniteLimitsOfSize]
    

Proof state:
C D : Type u₁
inst✝⁹ : SmallCategory C
inst✝⁸ : SmallCategory D
E : Type u₂
inst✝⁷ : Category.{u₁, u₂} E
inst✝⁶ : ConcreteCategory E
inst✝⁵ : HasLimits E
inst✝⁴ : HasColimits E
inst✝³ : ReflectsLimits (forget E)
inst✝² : PreservesFilteredColimits (forget E)
inst✝¹ : PreservesLimits (forget E)
inst✝ : HasFiniteLimits C
F : C ⥤ D
x : PreservesFiniteLimits (lan F.op)
⊢ inferInstance = x

Next tactic:
congr
/-- If `C` is finitely complete, then `F : C ⥤ D` preserves finite limits iff
`Lan F.op : (Cᵒᵖ ⥤ Type*) ⥤ (Dᵒᵖ ⥤ Type*)` preserves finite limits.
-/
noncomputable def preservesFiniteLimitsIffLanPreservesFiniteLimits (F : C ⥤ D) :
    PreservesFiniteLimits F ≃ PreservesFiniteLimits (lan F.op : _ ⥤ Dᵒᵖ ⥤ Type u₁) where
  toFun _ := inferInstance
  invFun _ := by
    apply preservesFiniteLimitsOfPreservesFiniteLimitsOfSize.{u₁}
    intros; apply preservesLimitOfLanPreservesLimit
  left_inv x := by
    -- porting note: `cases x` and an `unfold` not necessary in lean 4.
    -- Remark : in mathlib3 we had `unfold preservesFiniteLimitsOfFlat`
    -- but there was no `preservesFiniteLimitsOfFlat` in the goal! Experimentation
    -- indicates that it was doing the same as `dsimp only`
    dsimp only [preservesFiniteLimitsOfPreservesFiniteLimitsOfSize]; congr
    -- porting note: next line wasn't necessary in lean 3
    apply Subsingleton.elim
  right_inv x := by
    -- cases x; -- porting note: not necessary in lean 4
    dsimp only [lanPreservesFiniteLimitsOfPreservesFiniteLimits,
      lanPreservesFiniteLimitsOfFlat,
      preservesFiniteLimitsOfPreservesFiniteLimitsOfSize]
    congr
    -- porting note: next line wasn't necessary in lean 3
    

Proof state:
case h.e_2.h.h.e_2.h.e_preservesFiniteLimits
C D : Type u₁
inst✝⁹ : SmallCategory C
inst✝⁸ : SmallCategory D
E : Type u₂
inst✝⁷ : Category.{u₁, u₂} E
inst✝⁶ : ConcreteCategory E
inst✝⁵ : HasLimits E
inst✝⁴ : HasColimits E
inst✝³ : ReflectsLimits (forget E)
inst✝² : PreservesFilteredColimits (forget E)
inst✝¹ : PreservesLimits (forget E)
inst✝ : HasFiniteLimits C
F : C ⥤ D
x : PreservesFiniteLimits (lan F.op)
⊢ (fun J x_1 x_2 => preservesLimitsOfShapeOfEquiv (ULiftHomULiftCategory.equiv J).symm (lan F.op)) =
    PreservesFiniteLimits.preservesFiniteLimits

Next tactic:
apply Subsingleton.elim
/-- Product of two equivalences, in terms of `PProd`. If `α ≃ β` and `γ ≃ δ`, then
`PProd α γ ≃ PProd β δ`. -/
-- porting note: in Lean 3 this had `@[congr]`
@[simps apply]
def pprodCongr (e₁ : α ≃ β) (e₂ : γ ≃ δ) : PProd α γ ≃ PProd β δ where
  toFun x := ⟨e₁ x.1, e₂ x.2⟩
  invFun x := ⟨e₁.symm x.1, e₂.symm x.2⟩
  left_inv := fun ⟨x, y⟩ => by 

Proof state:
α : Sort ?u.394
β : Sort ?u.393
γ : Sort ?u.398
δ : Sort ?u.397
e₁ : α ≃ β
e₂ : γ ≃ δ
x✝ : PProd α γ
x : α
y : γ
⊢ (fun x => { fst := e₁.symm x.fst, snd := e₂.symm x.snd })
      ((fun x => { fst := e₁ x.fst, snd := e₂ x.snd }) { fst := x, snd := y }) =
    { fst := x, snd := y }

Next tactic:
simp
/-- Product of two equivalences, in terms of `PProd`. If `α ≃ β` and `γ ≃ δ`, then
`PProd α γ ≃ PProd β δ`. -/
-- porting note: in Lean 3 this had `@[congr]`
@[simps apply]
def pprodCongr (e₁ : α ≃ β) (e₂ : γ ≃ δ) : PProd α γ ≃ PProd β δ where
  toFun x := ⟨e₁ x.1, e₂ x.2⟩
  invFun x := ⟨e₁.symm x.1, e₂.symm x.2⟩
  left_inv := fun ⟨x, y⟩ => by simp
  right_inv := fun ⟨x, y⟩ => by 

Proof state:
α : Sort ?u.394
β : Sort ?u.393
γ : Sort ?u.398
δ : Sort ?u.397
e₁ : α ≃ β
e₂ : γ ≃ δ
x✝ : PProd β δ
x : β
y : δ
⊢ (fun x => { fst := e₁ x.fst, snd := e₂ x.snd })
      ((fun x => { fst := e₁.symm x.fst, snd := e₂.symm x.snd }) { fst := x, snd := y }) =
    { fst := x, snd := y }

Next tactic:
simp
/-- Product of two equivalences. If `α₁ ≃ α₂` and `β₁ ≃ β₂`, then `α₁ × β₁ ≃ α₂ × β₂`. This is
`Prod.map` as an equivalence. -/
-- porting note: in Lean 3 there was also a @[congr] tag
@[simps (config := .asFn) apply]
def prodCongr (e₁ : α₁ ≃ α₂) (e₂ : β₁ ≃ β₂) : α₁ × β₁ ≃ α₂ × β₂ :=
  ⟨Prod.map e₁ e₂, Prod.map e₁.symm e₂.symm, fun ⟨a, b⟩ => by 

Proof state:
α₁ : Type ?u.3632
α₂ : Type ?u.3634
β₁ : Type ?u.3631
β₂ : Type ?u.3633
e₁ : α₁ ≃ α₂
e₂ : β₁ ≃ β₂
x✝ : α₁ × β₁
a : α₁
b : β₁
⊢ Prod.map (⇑e₁.symm) (⇑e₂.symm) (Prod.map ⇑e₁ ⇑e₂ (a, b)) = (a, b)

Next tactic:
simp
/-- Product of two equivalences. If `α₁ ≃ α₂` and `β₁ ≃ β₂`, then `α₁ × β₁ ≃ α₂ × β₂`. This is
`Prod.map` as an equivalence. -/
-- porting note: in Lean 3 there was also a @[congr] tag
@[simps (config := .asFn) apply]
def prodCongr (e₁ : α₁ ≃ α₂) (e₂ : β₁ ≃ β₂) : α₁ × β₁ ≃ α₂ × β₂ :=
  ⟨Prod.map e₁ e₂, Prod.map e₁.symm e₂.symm, fun ⟨a, b⟩ => by simp, fun ⟨a, b⟩ => by 

Proof state:
α₁ : Type ?u.3632
α₂ : Type ?u.3634
β₁ : Type ?u.3631
β₂ : Type ?u.3633
e₁ : α₁ ≃ α₂
e₂ : β₁ ≃ β₂
x✝ : α₂ × β₂
a : α₂
b : β₂
⊢ Prod.map (⇑e₁) (⇑e₂) (Prod.map ⇑e₁.symm ⇑e₂.symm (a, b)) = (a, b)

Next tactic:
simp
/-- `PSum` is equivalent to `Sum`. -/
def psumEquivSum (α β) : PSum α β ≃ Sum α β where
  toFun s := PSum.casesOn s inl inr
  invFun := Sum.elim PSum.inl PSum.inr
  left_inv s := by 

Proof state:
α : Type ?u.12316
β : Type ?u.12315
s : α ⊕' β
⊢ Sum.elim PSum.inl PSum.inr ((fun s => PSum.casesOn s inl inr) s) = s

Next tactic:
cases s