l3lab/ntp-mathlib huggingface dataset:
/-- We deduce that `N₂ : Karoubi (SimplicialObject C) ⥤ Karoubi (ChainComplex C ℕ))`
reflects isomorphisms from the fact that
`N₁ : SimplicialObject (Karoubi C) ⥤ Karoubi (ChainComplex (Karoubi C) ℕ)` does. -/
instance : ReflectsIsomorphisms (N₂ : Karoubi (SimplicialObject C) ⥤ Karoubi (ChainComplex C ℕ)) :=
  ⟨fun f => by
    intro
    -- The following functor `F` reflects isomorphism because it is
    -- a composition of four functors which reflects isomorphisms.
    -- Then, it suffices to show that `F.map f` is an isomorphism.
    let F₁ := karoubiFunctorCategoryEmbedding SimplexCategoryᵒᵖ C
    let F₂ : SimplicialObject (Karoubi C) ⥤ _ := N₁
    let F₃ := (karoubiChainComplexEquivalence (Karoubi C) ℕ).functor
    let F₄ := Functor.mapHomologicalComplex (KaroubiKaroubi.equivalence C).inverse
      (ComplexShape.down ℕ)
    let F := F₁ ⋙ F₂ ⋙ F₃ ⋙ F₄
    -- porting note: we have to help Lean4 find the `ReflectsIsomorphisms` instances
    -- could this be fixed by setting better instance priorities?
    haveI : ReflectsIsomorphisms F₁ := reflectsIsomorphisms_of_full_and_faithful _
    haveI : ReflectsIsomorphisms F₂ := by infer_instance
    haveI : ReflectsIsomorphisms F₃ := reflectsIsomorphisms_of_full_and_faithful _
    haveI : ReflectsIsomorphisms ((KaroubiKaroubi.equivalence C).inverse) :=
      reflectsIsomorphisms_of_full_and_faithful _
    have : IsIso (F.map f) := by
      simp only
      rw [← compatibility_N₂_N₁_karoubi, Functor.comp_map]
      

Proof state:
C : Type u_1
inst✝² : Category.{?u.73743, u_1} C
inst✝¹ : Preadditive C
A✝ B✝ : Karoubi (SimplicialObject C)
f : A✝ ⟶ B✝
inst✝ : IsIso (N₂.map f)
F₁ : Karoubi (SimplexCategoryᵒᵖ ⥤ C) ⥤ SimplexCategoryᵒᵖ ⥤ Karoubi C :=
  karoubiFunctorCategoryEmbedding SimplexCategoryᵒᵖ C
F₂ : SimplicialObject (Karoubi C) ⥤ Karoubi (ChainComplex (Karoubi C) ℕ) := N₁
F₃ : Karoubi (ChainComplex (Karoubi C) ℕ) ⥤ ChainComplex (Karoubi (Karoubi C)) ℕ :=
  (karoubiChainComplexEquivalence (Karoubi C) ℕ).functor
F₄ : HomologicalComplex (Karoubi (Karoubi C)) (ComplexShape.down ℕ) ⥤
  HomologicalComplex (Karoubi C) (ComplexShape.down ℕ) :=
  Functor.mapHomologicalComplex (KaroubiKaroubi.equivalence C).inverse (ComplexShape.down ℕ)
F : Karoubi (SimplexCategoryᵒᵖ ⥤ C) ⥤ HomologicalComplex (Karoubi C) (ComplexShape.down ℕ) := F₁ ⋙ F₂ ⋙ F₃ ⋙ F₄
this✝² : ReflectsIsomorphisms F₁
this✝¹ : ReflectsIsomorphisms F₂
this✝ : ReflectsIsomorphisms F₃
this : ReflectsIsomorphisms (KaroubiKaroubi.equivalence C).inverse
⊢ IsIso ((karoubiChainComplexEquivalence C ℕ).functor.map (N₂.map f))

Next tactic:
apply Functor.map_isIso
/-- We deduce that `N₂ : Karoubi (SimplicialObject C) ⥤ Karoubi (ChainComplex C ℕ))`
reflects isomorphisms from the fact that
`N₁ : SimplicialObject (Karoubi C) ⥤ Karoubi (ChainComplex (Karoubi C) ℕ)` does. -/
instance : ReflectsIsomorphisms (N₂ : Karoubi (SimplicialObject C) ⥤ Karoubi (ChainComplex C ℕ)) :=
  ⟨fun f => by
    intro
    -- The following functor `F` reflects isomorphism because it is
    -- a composition of four functors which reflects isomorphisms.
    -- Then, it suffices to show that `F.map f` is an isomorphism.
    let F₁ := karoubiFunctorCategoryEmbedding SimplexCategoryᵒᵖ C
    let F₂ : SimplicialObject (Karoubi C) ⥤ _ := N₁
    let F₃ := (karoubiChainComplexEquivalence (Karoubi C) ℕ).functor
    let F₄ := Functor.mapHomologicalComplex (KaroubiKaroubi.equivalence C).inverse
      (ComplexShape.down ℕ)
    let F := F₁ ⋙ F₂ ⋙ F₃ ⋙ F₄
    -- porting note: we have to help Lean4 find the `ReflectsIsomorphisms` instances
    -- could this be fixed by setting better instance priorities?
    haveI : ReflectsIsomorphisms F₁ := reflectsIsomorphisms_of_full_and_faithful _
    haveI : ReflectsIsomorphisms F₂ := by infer_instance
    haveI : ReflectsIsomorphisms F₃ := reflectsIsomorphisms_of_full_and_faithful _
    haveI : ReflectsIsomorphisms ((KaroubiKaroubi.equivalence C).inverse) :=
      reflectsIsomorphisms_of_full_and_faithful _
    have : IsIso (F.map f) := by
      simp only
      rw [← compatibility_N₂_N₁_karoubi, Functor.comp_map]
      apply Functor.map_isIso
    

Proof state:
C : Type u_1
inst✝² : Category.{?u.73743, u_1} C
inst✝¹ : Preadditive C
A✝ B✝ : Karoubi (SimplicialObject C)
f : A✝ ⟶ B✝
inst✝ : IsIso (N₂.map f)
F₁ : Karoubi (SimplexCategoryᵒᵖ ⥤ C) ⥤ SimplexCategoryᵒᵖ ⥤ Karoubi C :=
  karoubiFunctorCategoryEmbedding SimplexCategoryᵒᵖ C
F₂ : SimplicialObject (Karoubi C) ⥤ Karoubi (ChainComplex (Karoubi C) ℕ) := N₁
F₃ : Karoubi (ChainComplex (Karoubi C) ℕ) ⥤ ChainComplex (Karoubi (Karoubi C)) ℕ :=
  (karoubiChainComplexEquivalence (Karoubi C) ℕ).functor
F₄ : HomologicalComplex (Karoubi (Karoubi C)) (ComplexShape.down ℕ) ⥤
  HomologicalComplex (Karoubi C) (ComplexShape.down ℕ) :=
  Functor.mapHomologicalComplex (KaroubiKaroubi.equivalence C).inverse (ComplexShape.down ℕ)
F : Karoubi (SimplexCategoryᵒᵖ ⥤ C) ⥤ HomologicalComplex (Karoubi C) (ComplexShape.down ℕ) := F₁ ⋙ F₂ ⋙ F₃ ⋙ F₄
this✝³ : ReflectsIsomorphisms F₁
this✝² : ReflectsIsomorphisms F₂
this✝¹ : ReflectsIsomorphisms F₃
this✝ : ReflectsIsomorphisms (KaroubiKaroubi.equivalence C).inverse
this : IsIso (F.map f)
⊢ IsIso f

Next tactic:
exact isIso_of_reflects_iso f F
theorem pullbackCompatible_iff (x : FamilyOfElements P R) [R.hasPullbacks] :
    x.Compatible ↔ x.PullbackCompatible := by
  

Proof state:
C : Type u₁
inst✝¹ : Category.{v₁, u₁} C
P Q U : Cᵒᵖ ⥤ Type w
X Y : C
S : Sieve X
R : Presieve X
x : FamilyOfElements P R
inst✝ : hasPullbacks R
⊢ FamilyOfElements.Compatible x ↔ FamilyOfElements.PullbackCompatible x

Next tactic:
constructor
theorem pullbackCompatible_iff (x : FamilyOfElements P R) [R.hasPullbacks] :
    x.Compatible ↔ x.PullbackCompatible := by
  constructor
  · 

Proof state:
case mp
C : Type u₁
inst✝¹ : Category.{v₁, u₁} C
P Q U : Cᵒᵖ ⥤ Type w
X Y : C
S : Sieve X
R : Presieve X
x : FamilyOfElements P R
inst✝ : hasPullbacks R
⊢ FamilyOfElements.Compatible x → FamilyOfElements.PullbackCompatible x

Next tactic:
intro t Y₁ Y₂ f₁ f₂ hf₁ hf₂
theorem pullbackCompatible_iff (x : FamilyOfElements P R) [R.hasPullbacks] :
    x.Compatible ↔ x.PullbackCompatible := by
  constructor
  · intro t Y₁ Y₂ f₁ f₂ hf₁ hf₂
    

Proof state:
case mp
C : Type u₁
inst✝¹ : Category.{v₁, u₁} C
P Q U : Cᵒᵖ ⥤ Type w
X Y : C
S : Sieve X
R : Presieve X
x : FamilyOfElements P R
inst✝ : hasPullbacks R
t : FamilyOfElements.Compatible x
Y₁ Y₂ : C
f₁ : Y₁ ⟶ X
f₂ : Y₂ ⟶ X
hf₁ : R f₁
hf₂ : R f₂
⊢ P.map pullback.fst.op (x f₁ hf₁) = P.map pullback.snd.op (x f₂ hf₂)

Next tactic:
apply t
theorem pullbackCompatible_iff (x : FamilyOfElements P R) [R.hasPullbacks] :
    x.Compatible ↔ x.PullbackCompatible := by
  constructor
  · intro t Y₁ Y₂ f₁ f₂ hf₁ hf₂
    apply t
    

Proof state:
case mp.a
C : Type u₁
inst✝¹ : Category.{v₁, u₁} C
P Q U : Cᵒᵖ ⥤ Type w
X Y : C
S : Sieve X
R : Presieve X
x : FamilyOfElements P R
inst✝ : hasPullbacks R
t : FamilyOfElements.Compatible x
Y₁ Y₂ : C
f₁ : Y₁ ⟶ X
f₂ : Y₂ ⟶ X
hf₁ : R f₁
hf₂ : R f₂
⊢ pullback.fst ≫ f₁ = pullback.snd ≫ f₂

Next tactic:
haveI := hasPullbacks.has_pullbacks hf₁ hf₂
theorem pullbackCompatible_iff (x : FamilyOfElements P R) [R.hasPullbacks] :
    x.Compatible ↔ x.PullbackCompatible := by
  constructor
  · intro t Y₁ Y₂ f₁ f₂ hf₁ hf₂
    apply t
    haveI := hasPullbacks.has_pullbacks hf₁ hf₂
    

Proof state:
case mp.a
C : Type u₁
inst✝¹ : Category.{v₁, u₁} C
P Q U : Cᵒᵖ ⥤ Type w
X Y : C
S : Sieve X
R : Presieve X
x : FamilyOfElements P R
inst✝ : hasPullbacks R
t : FamilyOfElements.Compatible x
Y₁ Y₂ : C
f₁ : Y₁ ⟶ X
f₂ : Y₂ ⟶ X
hf₁ : R f₁
hf₂ : R f₂
this : HasPullback f₁ f₂
⊢ pullback.fst ≫ f₁ = pullback.snd ≫ f₂

Next tactic:
apply pullback.condition
theorem pullbackCompatible_iff (x : FamilyOfElements P R) [R.hasPullbacks] :
    x.Compatible ↔ x.PullbackCompatible := by
  constructor
  · intro t Y₁ Y₂ f₁ f₂ hf₁ hf₂
    apply t
    haveI := hasPullbacks.has_pullbacks hf₁ hf₂
    apply pullback.condition
  · 

Proof state:
case mpr
C : Type u₁
inst✝¹ : Category.{v₁, u₁} C
P Q U : Cᵒᵖ ⥤ Type w
X Y : C
S : Sieve X
R : Presieve X
x : FamilyOfElements P R
inst✝ : hasPullbacks R
⊢ FamilyOfElements.PullbackCompatible x → FamilyOfElements.Compatible x

Next tactic:
intro t Y₁ Y₂ Z g₁ g₂ f₁ f₂ hf₁ hf₂ comm
theorem pullbackCompatible_iff (x : FamilyOfElements P R) [R.hasPullbacks] :
    x.Compatible ↔ x.PullbackCompatible := by
  constructor
  · intro t Y₁ Y₂ f₁ f₂ hf₁ hf₂
    apply t
    haveI := hasPullbacks.has_pullbacks hf₁ hf₂
    apply pullback.condition
  · intro t Y₁ Y₂ Z g₁ g₂ f₁ f₂ hf₁ hf₂ comm
    

Proof state:
case mpr
C : Type u₁
inst✝¹ : Category.{v₁, u₁} C
P Q U : Cᵒᵖ ⥤ Type w
X Y : C
S : Sieve X
R : Presieve X
x : FamilyOfElements P R
inst✝ : hasPullbacks R
t : FamilyOfElements.PullbackCompatible x
Y₁ Y₂ Z : C
g₁ : Z ⟶ Y₁
g₂ : Z ⟶ Y₂
f₁ : Y₁ ⟶ X
f₂ : Y₂ ⟶ X
hf₁ : R f₁
hf₂ : R f₂
comm : g₁ ≫ f₁ = g₂ ≫ f₂
⊢ P.map g₁.op (x f₁ hf₁) = P.map g₂.op (x f₂ hf₂)

Next tactic:
haveI := hasPullbacks.has_pullbacks hf₁ hf₂
theorem pullbackCompatible_iff (x : FamilyOfElements P R) [R.hasPullbacks] :
    x.Compatible ↔ x.PullbackCompatible := by
  constructor
  · intro t Y₁ Y₂ f₁ f₂ hf₁ hf₂
    apply t
    haveI := hasPullbacks.has_pullbacks hf₁ hf₂
    apply pullback.condition
  · intro t Y₁ Y₂ Z g₁ g₂ f₁ f₂ hf₁ hf₂ comm
    haveI := hasPullbacks.has_pullbacks hf₁ hf₂
    

Proof state:
case mpr
C : Type u₁
inst✝¹ : Category.{v₁, u₁} C
P Q U : Cᵒᵖ ⥤ Type w
X Y : C
S : Sieve X
R : Presieve X
x : FamilyOfElements P R
inst✝ : hasPullbacks R
t : FamilyOfElements.PullbackCompatible x
Y₁ Y₂ Z : C
g₁ : Z ⟶ Y₁
g₂ : Z ⟶ Y₂
f₁ : Y₁ ⟶ X
f₂ : Y₂ ⟶ X
hf₁ : R f₁
hf₂ : R f₂
comm : g₁ ≫ f₁ = g₂ ≫ f₂
this : HasPullback f₁ f₂
⊢ P.map g₁.op (x f₁ hf₁) = P.map g₂.op (x f₂ hf₂)

Next tactic:
rw [← pullback.lift_fst _ _ comm, op_comp, FunctorToTypes.map_comp_apply, t hf₁ hf₂,
      ← FunctorToTypes.map_comp_apply, ← op_comp, pullback.lift_snd]
/-- The extension of a compatible family to the generated sieve is compatible. -/
theorem FamilyOfElements.Compatible.sieveExtend {x : FamilyOfElements P R} (hx : x.Compatible) :
    x.sieveExtend.Compatible := by
  

Proof state:
C : Type u₁
inst✝ : Category.{v₁, u₁} C
P Q U : Cᵒᵖ ⥤ Type w
X Y : C
S : Sieve X
R : Presieve X
x : FamilyOfElements P R
hx : Compatible x
⊢ Compatible (FamilyOfElements.sieveExtend x)

Next tactic:
intro _ _ _ _ _ _ _ h₁ h₂ comm
/-- The extension of a compatible family to the generated sieve is compatible. -/
theorem FamilyOfElements.Compatible.sieveExtend {x : FamilyOfElements P R} (hx : x.Compatible) :
    x.sieveExtend.Compatible := by
  intro _ _ _ _ _ _ _ h₁ h₂ comm
  

Proof state:
C : Type u₁
inst✝ : Category.{v₁, u₁} C
P Q U : Cᵒᵖ ⥤ Type w
X Y : C
S : Sieve X
R : Presieve X
x : FamilyOfElements P R
hx : Compatible x
Y₁✝ Y₂✝ Z✝ : C
g₁✝ : Z✝ ⟶ Y₁✝
g₂✝ : Z✝ ⟶ Y₂✝
f₁✝ : Y₁✝ ⟶ X
f₂✝ : Y₂✝ ⟶ X
h₁ : (generate R).arrows f₁✝
h₂ : (generate R).arrows f₂✝
comm : g₁✝ ≫ f₁✝ = g₂✝ ≫ f₂✝
⊢ P.map g₁✝.op (FamilyOfElements.sieveExtend x f₁✝ h₁) = P.map g₂✝.op (FamilyOfElements.sieveExtend x f₂✝ h₂)

Next tactic:
iterate 2 erw [← FunctorToTypes.map_comp_apply]; rw [← op_comp]
/-- The extension of a compatible family to the generated sieve is compatible. -/
theorem FamilyOfElements.Compatible.sieveExtend {x : FamilyOfElements P R} (hx : x.Compatible) :
    x.sieveExtend.Compatible := by
  intro _ _ _ _ _ _ _ h₁ h₂ comm
  iterate 2 

Proof state:
C : Type u₁
inst✝ : Category.{v₁, u₁} C
P Q U : Cᵒᵖ ⥤ Type w
X Y : C
S : Sieve X
R : Presieve X
x : FamilyOfElements P R
hx : Compatible x
Y₁✝ Y₂✝ Z✝ : C
g₁✝ : Z✝ ⟶ Y₁✝
g₂✝ : Z✝ ⟶ Y₂✝
f₁✝ : Y₁✝ ⟶ X
f₂✝ : Y₂✝ ⟶ X
h₁ : (generate R).arrows f₁✝
h₂ : (generate R).arrows f₂✝
comm : g₁✝ ≫ f₁✝ = g₂✝ ≫ f₂✝
⊢ P.map g₁✝.op (FamilyOfElements.sieveExtend x f₁✝ h₁) = P.map g₂✝.op (FamilyOfElements.sieveExtend x f₂✝ h₂)

Next tactic:
erw [← FunctorToTypes.map_comp_apply]
/-- The extension of a compatible family to the generated sieve is compatible. -/
theorem FamilyOfElements.Compatible.sieveExtend {x : FamilyOfElements P R} (hx : x.Compatible) :
    x.sieveExtend.Compatible := by
  intro _ _ _ _ _ _ _ h₁ h₂ comm
  iterate 2 erw [← FunctorToTypes.map_comp_apply]; 

Proof state:
C : Type u₁
inst✝ : Category.{v₁, u₁} C
P Q U : Cᵒᵖ ⥤ Type w
X Y : C
S : Sieve X
R : Presieve X
x : FamilyOfElements P R
hx : Compatible x
Y₁✝ Y₂✝ Z✝ : C
g₁✝ : Z✝ ⟶ Y₁✝
g₂✝ : Z✝ ⟶ Y₂✝
f₁✝ : Y₁✝ ⟶ X
f₂✝ : Y₂✝ ⟶ X
h₁ : (generate R).arrows f₁✝
h₂ : (generate R).arrows f₂✝
comm : g₁✝ ≫ f₁✝ = g₂✝ ≫ f₂✝
⊢ P.map ((Exists.choose (_ : ∃ h g, R g ∧ h ≫ g = f₁✝)).op ≫ g₁✝.op)
      (x (Exists.choose (_ : ∃ g, R g ∧ Exists.choose (_ : ∃ h g, R g ∧ h ≫ g = f₁✝) ≫ g = f₁✝))
        (_ : R (Exists.choose (_ : ∃ g, R g ∧ Exists.choose (_ : ∃ h g, R g ∧ h ≫ g = f₁✝) ≫ g = f₁✝)))) =
    P.map g₂✝.op (FamilyOfElements.sieveExtend x f₂✝ h₂)

Next tactic:
rw [← op_comp]
/-- The extension of a compatible family to the generated sieve is compatible. -/
theorem FamilyOfElements.Compatible.sieveExtend {x : FamilyOfElements P R} (hx : x.Compatible) :
    x.sieveExtend.Compatible := by
  intro _ _ _ _ _ _ _ h₁ h₂ comm
  iterate 2 

Proof state:
C : Type u₁
inst✝ : Category.{v₁, u₁} C
P Q U : Cᵒᵖ ⥤ Type w
X Y : C
S : Sieve X
R : Presieve X
x : FamilyOfElements P R
hx : Compatible x
Y₁✝ Y₂✝ Z✝ : C
g₁✝ : Z✝ ⟶ Y₁✝
g₂✝ : Z✝ ⟶ Y₂✝
f₁✝ : Y₁✝ ⟶ X
f₂✝ : Y₂✝ ⟶ X
h₁ : (generate R).arrows f₁✝
h₂ : (generate R).arrows f₂✝
comm : g₁✝ ≫ f₁✝ = g₂✝ ≫ f₂✝
⊢ P.map (g₁✝ ≫ Exists.choose (_ : ∃ h g, R g ∧ h ≫ g = f₁✝)).op
      (x (Exists.choose (_ : ∃ g, R g ∧ Exists.choose (_ : ∃ h g, R g ∧ h ≫ g = f₁✝) ≫ g = f₁✝))
        (_ : R (Exists.choose (_ : ∃ g, R g ∧ Exists.choose (_ : ∃ h g, R g ∧ h ≫ g = f₁✝) ≫ g = f₁✝)))) =
    P.map g₂✝.op (FamilyOfElements.sieveExtend x f₂✝ h₂)

Next tactic:
erw [← FunctorToTypes.map_comp_apply]
/-- The extension of a compatible family to the generated sieve is compatible. -/
theorem FamilyOfElements.Compatible.sieveExtend {x : FamilyOfElements P R} (hx : x.Compatible) :
    x.sieveExtend.Compatible := by
  intro _ _ _ _ _ _ _ h₁ h₂ comm
  iterate 2 erw [← FunctorToTypes.map_comp_apply]; 

Proof state:
C : Type u₁
inst✝ : Category.{v₁, u₁} C
P Q U : Cᵒᵖ ⥤ Type w
X Y : C
S : Sieve X
R : Presieve X
x : FamilyOfElements P R
hx : Compatible x
Y₁✝ Y₂✝ Z✝ : C
g₁✝ : Z✝ ⟶ Y₁✝
g₂✝ : Z✝ ⟶ Y₂✝
f₁✝ : Y₁✝ ⟶ X
f₂✝ : Y₂✝ ⟶ X
h₁ : (generate R).arrows f₁✝
h₂ : (generate R).arrows f₂✝
comm : g₁✝ ≫ f₁✝ = g₂✝ ≫ f₂✝
⊢ P.map (g₁✝ ≫ Exists.choose (_ : ∃ h g, R g ∧ h ≫ g = f₁✝)).op
      (x (Exists.choose (_ : ∃ g, R g ∧ Exists.choose (_ : ∃ h g, R g ∧ h ≫ g = f₁✝) ≫ g = f₁✝))
        (_ : R (Exists.choose (_ : ∃ g, R g ∧ Exists.choose (_ : ∃ h g, R g ∧ h ≫ g = f₁✝) ≫ g = f₁✝)))) =
    P.map ((Exists.choose (_ : ∃ h g, R g ∧ h ≫ g = f₂✝)).op ≫ g₂✝.op)
      (x (Exists.choose (_ : ∃ g, R g ∧ Exists.choose (_ : ∃ h g, R g ∧ h ≫ g = f₂✝) ≫ g = f₂✝))
        (_ : R (Exists.choose (_ : ∃ g, R g ∧ Exists.choose (_ : ∃ h g, R g ∧ h ≫ g = f₂✝) ≫ g = f₂✝))))

Next tactic:
rw [← op_comp]
/-- The extension of a compatible family to the generated sieve is compatible. -/
theorem FamilyOfElements.Compatible.sieveExtend {x : FamilyOfElements P R} (hx : x.Compatible) :
    x.sieveExtend.Compatible := by
  intro _ _ _ _ _ _ _ h₁ h₂ comm
  iterate 2 erw [← FunctorToTypes.map_comp_apply]; rw [← op_comp]
  

Proof state:
C : Type u₁
inst✝ : Category.{v₁, u₁} C
P Q U : Cᵒᵖ ⥤ Type w
X Y : C
S : Sieve X
R : Presieve X
x : FamilyOfElements P R
hx : Compatible x
Y₁✝ Y₂✝ Z✝ : C
g₁✝ : Z✝ ⟶ Y₁✝
g₂✝ : Z✝ ⟶ Y₂✝
f₁✝ : Y₁✝ ⟶ X
f₂✝ : Y₂✝ ⟶ X
h₁ : (generate R).arrows f₁✝
h₂ : (generate R).arrows f₂✝
comm : g₁✝ ≫ f₁✝ = g₂✝ ≫ f₂✝
⊢ P.map (g₁✝ ≫ Exists.choose (_ : ∃ h g, R g ∧ h ≫ g = f₁✝)).op
      (x (Exists.choose (_ : ∃ g, R g ∧ Exists.choose (_ : ∃ h g, R g ∧ h ≫ g = f₁✝) ≫ g = f₁✝))
        (_ : R (Exists.choose (_ : ∃ g, R g ∧ Exists.choose (_ : ∃ h g, R g ∧ h ≫ g = f₁✝) ≫ g = f₁✝)))) =
    P.map (g₂✝ ≫ Exists.choose (_ : ∃ h g, R g ∧ h ≫ g = f₂✝)).op
      (x (Exists.choose (_ : ∃ g, R g ∧ Exists.choose (_ : ∃ h g, R g ∧ h ≫ g = f₂✝) ≫ g = f₂✝))
        (_ : R (Exists.choose (_ : ∃ g, R g ∧ Exists.choose (_ : ∃ h g, R g ∧ h ≫ g = f₂✝) ≫ g = f₂✝))))

Next tactic:
apply hx
/-- The extension of a compatible family to the generated sieve is compatible. -/
theorem FamilyOfElements.Compatible.sieveExtend {x : FamilyOfElements P R} (hx : x.Compatible) :
    x.sieveExtend.Compatible := by
  intro _ _ _ _ _ _ _ h₁ h₂ comm
  iterate 2 erw [← FunctorToTypes.map_comp_apply]; rw [← op_comp]
  apply hx
  

Proof state:
case a
C : Type u₁
inst✝ : Category.{v₁, u₁} C
P Q U : Cᵒᵖ ⥤ Type w
X Y : C
S : Sieve X
R : Presieve X
x : FamilyOfElements P R
hx : Compatible x
Y₁✝ Y₂✝ Z✝ : C
g₁✝ : Z✝ ⟶ Y₁✝
g₂✝ : Z✝ ⟶ Y₂✝
f₁✝ : Y₁✝ ⟶ X
f₂✝ : Y₂✝ ⟶ X
h₁ : (generate R).arrows f₁✝
h₂ : (generate R).arrows f₂✝
comm : g₁✝ ≫ f₁✝ = g₂✝ ≫ f₂✝
⊢ (g₁✝ ≫ Exists.choose (_ : ∃ h g, R g ∧ h ≫ g = f₁✝)) ≫
      Exists.choose (_ : ∃ g, R g ∧ Exists.choose (_ : ∃ h g, R g ∧ h ≫ g = f₁✝) ≫ g = f₁✝) =
    (g₂✝ ≫ Exists.choose (_ : ∃ h g, R g ∧ h ≫ g = f₂✝)) ≫
      Exists.choose (_ : ∃ g, R g ∧ Exists.choose (_ : ∃ h g, R g ∧ h ≫ g = f₂✝) ≫ g = f₂✝)

Next tactic:
simp [comm, h₁.choose_spec.choose_spec.choose_spec.2, h₂.choose_spec.choose_spec.choose_spec.2]
/-- The extension of a family agrees with the original family. -/
theorem extend_agrees {x : FamilyOfElements P R} (t : x.Compatible) {f : Y ⟶ X} (hf : R f) :
    x.sieveExtend f (le_generate R Y hf) = x f hf := by
  

Proof state:
C : Type u₁
inst✝ : Category.{v₁, u₁} C
P Q U : Cᵒᵖ ⥤ Type w
X Y : C
S : Sieve X
R : Presieve X
x : FamilyOfElements P R
t : FamilyOfElements.Compatible x
f : Y ⟶ X
hf : R f
⊢ FamilyOfElements.sieveExtend x f (_ : f ∈ (generate R).arrows) = x f hf

Next tactic:
have h := (le_generate R Y hf).choose_spec
/-- The extension of a family agrees with the original family. -/
theorem extend_agrees {x : FamilyOfElements P R} (t : x.Compatible) {f : Y ⟶ X} (hf : R f) :
    x.sieveExtend f (le_generate R Y hf) = x f hf := by
  have h := (le_generate R Y hf).choose_spec
  

Proof state:
C : Type u₁
inst✝ : Category.{v₁, u₁} C
P Q U : Cᵒᵖ ⥤ Type w
X Y : C
S : Sieve X
R : Presieve X
x : FamilyOfElements P R
t : FamilyOfElements.Compatible x
f : Y ⟶ X
hf : R f
h : ∃ h g, R g ∧ h ≫ g = f
⊢ FamilyOfElements.sieveExtend x f (_ : f ∈ (generate R).arrows) = x f hf

Next tactic:
unfold FamilyOfElements.sieveExtend
/-- The extension of a family agrees with the original family. -/
theorem extend_agrees {x : FamilyOfElements P R} (t : x.Compatible) {f : Y ⟶ X} (hf : R f) :
    x.sieveExtend f (le_generate R Y hf) = x f hf := by
  have h := (le_generate R Y hf).choose_spec
  unfold FamilyOfElements.sieveExtend
  

Proof state:
C : Type u₁
inst✝ : Category.{v₁, u₁} C
P Q U : Cᵒᵖ ⥤ Type w
X Y : C
S : Sieve X
R : Presieve X
x : FamilyOfElements P R
t : FamilyOfElements.Compatible x
f : Y ⟶ X
hf : R f
h : ∃ h g, R g ∧ h ≫ g = f
⊢ P.map (Exists.choose (_ : ∃ h g, R g ∧ h ≫ g = f)).op
      (x (Exists.choose (_ : ∃ g, R g ∧ Exists.choose (_ : ∃ h g, R g ∧ h ≫ g = f) ≫ g = f))
        (_ : R (Exists.choose (_ : ∃ g, R g ∧ Exists.choose (_ : ∃ h g, R g ∧ h ≫ g = f) ≫ g = f)))) =
    x f hf

Next tactic:
rw [t h.choose (𝟙 _) _ hf _]
/-- The extension of a family agrees with the original family. -/
theorem extend_agrees {x : FamilyOfElements P R} (t : x.Compatible) {f : Y ⟶ X} (hf : R f) :
    x.sieveExtend f (le_generate R Y hf) = x f hf := by
  have h := (le_generate R Y hf).choose_spec
  unfold FamilyOfElements.sieveExtend
  rw [t h.choose (𝟙 _) _ hf _]
  · 

Proof state:
C : Type u₁
inst✝ : Category.{v₁, u₁} C
P Q U : Cᵒᵖ ⥤ Type w
X Y : C
S : Sieve X
R : Presieve X
x : FamilyOfElements P R
t : FamilyOfElements.Compatible x
f : Y ⟶ X
hf : R f
h : ∃ h g, R g ∧ h ≫ g = f
⊢ P.map (𝟙 Y).op (x f hf) = x f hf

Next tactic:
simp
/-- The extension of a family agrees with the original family. -/
theorem extend_agrees {x : FamilyOfElements P R} (t : x.Compatible) {f : Y ⟶ X} (hf : R f) :
    x.sieveExtend f (le_generate R Y hf) = x f hf := by
  have h := (le_generate R Y hf).choose_spec
  unfold FamilyOfElements.sieveExtend
  rw [t h.choose (𝟙 _) _ hf _]
  · simp
  · 

Proof state:
C : Type u₁
inst✝ : Category.{v₁, u₁} C
P Q U : Cᵒᵖ ⥤ Type w
X Y : C
S : Sieve X
R : Presieve X
x : FamilyOfElements P R
t : FamilyOfElements.Compatible x
f : Y ⟶ X
hf : R f
h : ∃ h g, R g ∧ h ≫ g = f
⊢ Exists.choose h ≫ Exists.choose (_ : ∃ g, R g ∧ Exists.choose (_ : ∃ h g, R g ∧ h ≫ g = f) ≫ g = f) = 𝟙 Y ≫ f

Next tactic:
rw [id_comp]
/-- The extension of a family agrees with the original family. -/
theorem extend_agrees {x : FamilyOfElements P R} (t : x.Compatible) {f : Y ⟶ X} (hf : R f) :
    x.sieveExtend f (le_generate R Y hf) = x f hf := by
  have h := (le_generate R Y hf).choose_spec
  unfold FamilyOfElements.sieveExtend
  rw [t h.choose (𝟙 _) _ hf _]
  · simp
  · rw [id_comp]
    

Proof state:
C : Type u₁
inst✝ : Category.{v₁, u₁} C
P Q U : Cᵒᵖ ⥤ Type w
X Y : C
S : Sieve X
R : Presieve X
x : FamilyOfElements P R
t : FamilyOfElements.Compatible x
f : Y ⟶ X
hf : R f
h : ∃ h g, R g ∧ h ≫ g = f
⊢ Exists.choose h ≫ Exists.choose (_ : ∃ g, R g ∧ Exists.choose (_ : ∃ h g, R g ∧ h ≫ g = f) ≫ g = f) = f

Next tactic:
exact h.choose_spec.choose_spec.2
/-- The restriction of an extension is the original. -/
@[simp]
theorem restrict_extend {x : FamilyOfElements P R} (t : x.Compatible) :
    x.sieveExtend.restrict (le_generate R) = x := by
  

Proof state:
C : Type u₁
inst✝ : Category.{v₁, u₁} C
P Q U : Cᵒᵖ ⥤ Type w
X Y : C
S : Sieve X
R : Presieve X
x : FamilyOfElements P R
t : FamilyOfElements.Compatible x
⊢ FamilyOfElements.restrict (_ : R ≤ (generate R).arrows) (FamilyOfElements.sieveExtend x) = x

Next tactic:
funext Y f hf
/-- The restriction of an extension is the original. -/
@[simp]
theorem restrict_extend {x : FamilyOfElements P R} (t : x.Compatible) :
    x.sieveExtend.restrict (le_generate R) = x := by
  funext Y f hf
  

Proof state:
case h.h.h
C : Type u₁
inst✝ : Category.{v₁, u₁} C
P Q U : Cᵒᵖ ⥤ Type w
X Y✝ : C
S : Sieve X
R : Presieve X
x : FamilyOfElements P R
t : FamilyOfElements.Compatible x
Y : C
f : Y ⟶ X
hf : R f
⊢ FamilyOfElements.restrict (_ : R ≤ (generate R).arrows) (FamilyOfElements.sieveExtend x) f hf = x f hf

Next tactic:
exact extend_agrees t hf
theorem compatible_iff_sieveCompatible (x : FamilyOfElements P (S : Presieve X)) :
    x.Compatible ↔ x.SieveCompatible := by
  

Proof state:
C : Type u₁
inst✝ : Category.{v₁, u₁} C
P Q U : Cᵒᵖ ⥤ Type w
X Y : C
S : Sieve X
R : Presieve X
x : FamilyOfElements P S.arrows
⊢ FamilyOfElements.Compatible x ↔ FamilyOfElements.SieveCompatible x

Next tactic:
constructor
theorem compatible_iff_sieveCompatible (x : FamilyOfElements P (S : Presieve X)) :
    x.Compatible ↔ x.SieveCompatible := by
  constructor
  · 

Proof state:
case mp
C : Type u₁
inst✝ : Category.{v₁, u₁} C
P Q U : Cᵒᵖ ⥤ Type w
X Y : C
S : Sieve X
R : Presieve X
x : FamilyOfElements P S.arrows
⊢ FamilyOfElements.Compatible x → FamilyOfElements.SieveCompatible x

Next tactic:
intro h Y Z f g hf
theorem compatible_iff_sieveCompatible (x : FamilyOfElements P (S : Presieve X)) :
    x.Compatible ↔ x.SieveCompatible := by
  constructor
  · intro h Y Z f g hf
    

Proof state:
case mp
C : Type u₁
inst✝ : Category.{v₁, u₁} C
P Q U : Cᵒᵖ ⥤ Type w
X Y✝ : C
S : Sieve X
R : Presieve X
x : FamilyOfElements P S.arrows
h : FamilyOfElements.Compatible x
Y Z : C
f : Y ⟶ X
g : Z ⟶ Y
hf : S.arrows f
⊢ x (g ≫ f) (_ : S.arrows (g ≫ f)) = P.map g.op (x f hf)

Next tactic:
simpa using h (𝟙 _) g (S.downward_closed hf g) hf (id_comp _)
theorem compatible_iff_sieveCompatible (x : FamilyOfElements P (S : Presieve X)) :
    x.Compatible ↔ x.SieveCompatible := by
  constructor
  · intro h Y Z f g hf
    simpa using h (𝟙 _) g (S.downward_closed hf g) hf (id_comp _)
  · 

Proof state:
case mpr
C : Type u₁
inst✝ : Category.{v₁, u₁} C
P Q U : Cᵒᵖ ⥤ Type w
X Y : C
S : Sieve X
R : Presieve X
x : FamilyOfElements P S.arrows
⊢ FamilyOfElements.SieveCompatible x → FamilyOfElements.Compatible x

Next tactic:
intro h Y₁ Y₂ Z g₁ g₂ f₁ f₂ h₁ h₂ k