Theorem: CategoryTheory.Sheaf.isLocallyBijective_iff_isIso'
File: Mathlib/CategoryTheory/Sites/LocallyBijective.lean

tactic: constructor
state_before: C : Type u
inst✝² : Category.{v, u} C
J : GrothendieckTopology C
A : Type u'
inst✝¹ : Category.{v', u'} A
inst✝ : ConcreteCategory A
F G : Sheaf J (Type w)
f : F ⟶ G
⊢ IsLocallyInjective f ∧ IsLocallySurjective f ↔ IsIso f
state_after: case mp
C : Type u
inst✝² : Category.{v, u} C
J : GrothendieckTopology C
A : Type u'
inst✝¹ : Category.{v', u'} A
inst✝ : ConcreteCategory A
F G : Sheaf J (Type w)
f : F ⟶ G
⊢ IsLocallyInjective f ∧ IsLocallySurjective f → IsIso f

case mpr
C : Type u
inst✝² : Category.{v, u} C
J : GrothendieckTopology C
A : Type u'
inst✝¹ : Category.{v', u'} A
inst✝ : ConcreteCategory A
F G : Sheaf J (Type w)
f : F ⟶ G
⊢ IsIso f → IsLocallyInjective f ∧ IsLocallySurjective f

tactic: rintro ⟨h₁, _⟩
state_before: case mp
C : Type u
inst✝² : Category.{v, u} C
J : GrothendieckTopology C
A : Type u'
inst✝¹ : Category.{v', u'} A
inst✝ : ConcreteCategory A
F G : Sheaf J (Type w)
f : F ⟶ G
⊢ IsLocallyInjective f ∧ IsLocallySurjective f → IsIso f
state_after: case mp.intro
C : Type u
inst✝² : Category.{v, u} C
J : GrothendieckTopology C
A : Type u'
inst✝¹ : Category.{v', u'} A
inst✝ : ConcreteCategory A
F G : Sheaf J (Type w)
f : F ⟶ G
h₁ : IsLocallyInjective f
right✝ : IsLocallySurjective f
⊢ IsIso f

tactic: rw [isLocallyInjective_iff_injective] at h₁
state_before: case mp.intro
C : Type u
inst✝² : Category.{v, u} C
J : GrothendieckTopology C
A : Type u'
inst✝¹ : Category.{v', u'} A
inst✝ : ConcreteCategory A
F G : Sheaf J (Type w)
f : F ⟶ G
h₁ : IsLocallyInjective f
right✝ : IsLocallySurjective f
⊢ IsIso f
state_after: case mp.intro
C : Type u
inst✝² : Category.{v, u} C
J : GrothendieckTopology C
A : Type u'
inst✝¹ : Category.{v', u'} A
inst✝ : ConcreteCategory A
F G : Sheaf J (Type w)
f : F ⟶ G
h₁ : ∀ (X : Cᵒᵖ), Function.Injective ⇑(f.val.app X)
right✝ : IsLocallySurjective f
⊢ IsIso f

tactic: suffices ∀ (X : Cᵒᵖ), Function.Surjective (f.val.app X) by
  rw [← isIso_iff_of_reflects_iso _ (sheafToPresheaf _ _), NatTrans.isIso_iff_isIso_app]
  intro X
  rw [isIso_iff_bijective]
  exact ⟨h₁ X, this X⟩
state_before: case mp.intro
C : Type u
inst✝² : Category.{v, u} C
J : GrothendieckTopology C
A : Type u'
inst✝¹ : Category.{v', u'} A
inst✝ : ConcreteCategory A
F G : Sheaf J (Type w)
f : F ⟶ G
h₁ : ∀ (X : Cᵒᵖ), Function.Injective ⇑(f.val.app X)
right✝ : IsLocallySurjective f
⊢ IsIso f
state_after: case mp.intro
C : Type u
inst✝² : Category.{v, u} C
J : GrothendieckTopology C
A : Type u'
inst✝¹ : Category.{v', u'} A
inst✝ : ConcreteCategory A
F G : Sheaf J (Type w)
f : F ⟶ G
h₁ : ∀ (X : Cᵒᵖ), Function.Injective ⇑(f.val.app X)
right✝ : IsLocallySurjective f
⊢ ∀ (X : Cᵒᵖ), Function.Surjective (f.val.app X)

tactic: intro X s
state_before: case mp.intro
C : Type u
inst✝² : Category.{v, u} C
J : GrothendieckTopology C
A : Type u'
inst✝¹ : Category.{v', u'} A
inst✝ : ConcreteCategory A
F G : Sheaf J (Type w)
f : F ⟶ G
h₁ : ∀ (X : Cᵒᵖ), Function.Injective ⇑(f.val.app X)
right✝ : IsLocallySurjective f
⊢ ∀ (X : Cᵒᵖ), Function.Surjective (f.val.app X)
state_after: case mp.intro
C : Type u
inst✝² : Category.{v, u} C
J : GrothendieckTopology C
A : Type u'
inst✝¹ : Category.{v', u'} A
inst✝ : ConcreteCategory A
F G : Sheaf J (Type w)
f : F ⟶ G
h₁ : ∀ (X : Cᵒᵖ), Function.Injective ⇑(f.val.app X)
right✝ : IsLocallySurjective f
X : Cᵒᵖ
s : G.val.obj X
⊢ ∃ a, f.val.app X a = s

tactic: have H := (isSheaf_iff_isSheaf_of_type J F.val).1 F.cond _ (Presheaf.imageSieve_mem J f.val s)
state_before: case mp.intro
C : Type u
inst✝² : Category.{v, u} C
J : GrothendieckTopology C
A : Type u'
inst✝¹ : Category.{v', u'} A
inst✝ : ConcreteCategory A
F G : Sheaf J (Type w)
f : F ⟶ G
h₁ : ∀ (X : Cᵒᵖ), Function.Injective ⇑(f.val.app X)
right✝ : IsLocallySurjective f
X : Cᵒᵖ
s : G.val.obj X
⊢ ∃ a, f.val.app X a = s
state_after: case mp.intro
C : Type u
inst✝² : Category.{v, u} C
J : GrothendieckTopology C
A : Type u'
inst✝¹ : Category.{v', u'} A
inst✝ : ConcreteCategory A
F G : Sheaf J (Type w)
f : F ⟶ G
h₁ : ∀ (X : Cᵒᵖ), Function.Injective ⇑(f.val.app X)
right✝ : IsLocallySurjective f
X : Cᵒᵖ
s : G.val.obj X
H : Presieve.IsSheafFor F.val (Presheaf.imageSieve f.val s).arrows
⊢ ∃ a, f.val.app X a = s

tactic: let t : Presieve.FamilyOfElements F.val (Presheaf.imageSieve f.val s).arrows :=
  fun Y g hg => Presheaf.localPreimage f.val s g hg
state_before: case mp.intro
C : Type u
inst✝² : Category.{v, u} C
J : GrothendieckTopology C
A : Type u'
inst✝¹ : Category.{v', u'} A
inst✝ : ConcreteCategory A
F G : Sheaf J (Type w)
f : F ⟶ G
h₁ : ∀ (X : Cᵒᵖ), Function.Injective ⇑(f.val.app X)
right✝ : IsLocallySurjective f
X : Cᵒᵖ
s : G.val.obj X
H : Presieve.IsSheafFor F.val (Presheaf.imageSieve f.val s).arrows
⊢ ∃ a, f.val.app X a = s
state_after: case mp.intro
C : Type u
inst✝² : Category.{v, u} C
J : GrothendieckTopology C
A : Type u'
inst✝¹ : Category.{v', u'} A
inst✝ : ConcreteCategory A
F G : Sheaf J (Type w)
f : F ⟶ G
h₁ : ∀ (X : Cᵒᵖ), Function.Injective ⇑(f.val.app X)
right✝ : IsLocallySurjective f
X : Cᵒᵖ
s : G.val.obj X
H : Presieve.IsSheafFor F.val (Presheaf.imageSieve f.val s).arrows
t : Presieve.FamilyOfElements F.val (Presheaf.imageSieve f.val s).arrows :=
  fun Y g hg => Presheaf.localPreimage f.val s g hg
⊢ ∃ a, f.val.app X a = s

tactic: have ht : t.Compatible := by
  intro Y₁ Y₂ W g₁ g₂ f₁ f₂ hf₁ hf₂ w
  apply h₁
  have eq₁ := FunctorToTypes.naturality _ _ f.val g₁.op (t f₁ hf₁)
  have eq₂ := FunctorToTypes.naturality _ _ f.val g₂.op (t f₂ hf₂)
  have eq₃ := congr_arg (G.val.map g₁.op) (Presheaf.app_localPreimage f.val s _ hf₁)
  have eq₄ := congr_arg (G.val.map g₂.op) (Presheaf.app_localPreimage f.val s _ hf₂)
  refine eq₁.trans (eq₃.trans (Eq.trans ?_ (eq₄.symm.trans eq₂.symm)))
  erw [← FunctorToTypes.map_comp_apply, ← FunctorToTypes.map_comp_apply]
  simp only [← op_comp, w]
state_before: case mp.intro
C : Type u
inst✝² : Category.{v, u} C
J : GrothendieckTopology C
A : Type u'
inst✝¹ : Category.{v', u'} A
inst✝ : ConcreteCategory A
F G : Sheaf J (Type w)
f : F ⟶ G
h₁ : ∀ (X : Cᵒᵖ), Function.Injective ⇑(f.val.app X)
right✝ : IsLocallySurjective f
X : Cᵒᵖ
s : G.val.obj X
H : Presieve.IsSheafFor F.val (Presheaf.imageSieve f.val s).arrows
t : Presieve.FamilyOfElements F.val (Presheaf.imageSieve f.val s).arrows :=
  fun Y g hg => Presheaf.localPreimage f.val s g hg
⊢ ∃ a, f.val.app X a = s
state_after: case mp.intro
C : Type u
inst✝² : Category.{v, u} C
J : GrothendieckTopology C
A : Type u'
inst✝¹ : Category.{v', u'} A
inst✝ : ConcreteCategory A
F G : Sheaf J (Type w)
f : F ⟶ G
h₁ : ∀ (X : Cᵒᵖ), Function.Injective ⇑(f.val.app X)
right✝ : IsLocallySurjective f
X : Cᵒᵖ
s : G.val.obj X
H : Presieve.IsSheafFor F.val (Presheaf.imageSieve f.val s).arrows
t : Presieve.FamilyOfElements F.val (Presheaf.imageSieve f.val s).arrows :=
  fun Y g hg => Presheaf.localPreimage f.val s g hg
ht : t.Compatible
⊢ ∃ a, f.val.app X a = s

tactic: refine ⟨H.amalgamate t ht, ?_⟩
state_before: case mp.intro
C : Type u
inst✝² : Category.{v, u} C
J : GrothendieckTopology C
A : Type u'
inst✝¹ : Category.{v', u'} A
inst✝ : ConcreteCategory A
F G : Sheaf J (Type w)
f : F ⟶ G
h₁ : ∀ (X : Cᵒᵖ), Function.Injective ⇑(f.val.app X)
right✝ : IsLocallySurjective f
X : Cᵒᵖ
s : G.val.obj X
H : Presieve.IsSheafFor F.val (Presheaf.imageSieve f.val s).arrows
t : Presieve.FamilyOfElements F.val (Presheaf.imageSieve f.val s).arrows :=
  fun Y g hg => Presheaf.localPreimage f.val s g hg
ht : t.Compatible
⊢ ∃ a, f.val.app X a = s
state_after: case mp.intro
C : Type u
inst✝² : Category.{v, u} C
J : GrothendieckTopology C
A : Type u'
inst✝¹ : Category.{v', u'} A
inst✝ : ConcreteCategory A
F G : Sheaf J (Type w)
f : F ⟶ G
h₁ : ∀ (X : Cᵒᵖ), Function.Injective ⇑(f.val.app X)
right✝ : IsLocallySurjective f
X : Cᵒᵖ
s : G.val.obj X
H : Presieve.IsSheafFor F.val (Presheaf.imageSieve f.val s).arrows
t : Presieve.FamilyOfElements F.val (Presheaf.imageSieve f.val s).arrows :=
  fun Y g hg => Presheaf.localPreimage f.val s g hg
ht : t.Compatible
⊢ f.val.app X (H.amalgamate t ht) = s

tactic: rw [← isIso_iff_of_reflects_iso _ (sheafToPresheaf _ _), NatTrans.isIso_iff_isIso_app]
state_before: C : Type u
inst✝² : Category.{v, u} C
J : GrothendieckTopology C
A : Type u'
inst✝¹ : Category.{v', u'} A
inst✝ : ConcreteCategory A
F G : Sheaf J (Type w)
f : F ⟶ G
h₁ : ∀ (X : Cᵒᵖ), Function.Injective ⇑(f.val.app X)
right✝ : IsLocallySurjective f
this : ∀ (X : Cᵒᵖ), Function.Surjective (f.val.app X)
⊢ IsIso f
state_after: C : Type u
inst✝² : Category.{v, u} C
J : GrothendieckTopology C
A : Type u'
inst✝¹ : Category.{v', u'} A
inst✝ : ConcreteCategory A
F G : Sheaf J (Type w)
f : F ⟶ G
h₁ : ∀ (X : Cᵒᵖ), Function.Injective ⇑(f.val.app X)
right✝ : IsLocallySurjective f
this : ∀ (X : Cᵒᵖ), Function.Surjective (f.val.app X)
⊢ ∀ (X : Cᵒᵖ), IsIso (((sheafToPresheaf J (Type w)).map f).app X)

tactic: intro X
state_before: C : Type u
inst✝² : Category.{v, u} C
J : GrothendieckTopology C
A : Type u'
inst✝¹ : Category.{v', u'} A
inst✝ : ConcreteCategory A
F G : Sheaf J (Type w)
f : F ⟶ G
h₁ : ∀ (X : Cᵒᵖ), Function.Injective ⇑(f.val.app X)
right✝ : IsLocallySurjective f
this : ∀ (X : Cᵒᵖ), Function.Surjective (f.val.app X)
⊢ ∀ (X : Cᵒᵖ), IsIso (((sheafToPresheaf J (Type w)).map f).app X)
state_after: C : Type u
inst✝² : Category.{v, u} C
J : GrothendieckTopology C
A : Type u'
inst✝¹ : Category.{v', u'} A
inst✝ : ConcreteCategory A
F G : Sheaf J (Type w)
f : F ⟶ G
h₁ : ∀ (X : Cᵒᵖ), Function.Injective ⇑(f.val.app X)
right✝ : IsLocallySurjective f
this : ∀ (X : Cᵒᵖ), Function.Surjective (f.val.app X)
X : Cᵒᵖ
⊢ IsIso (((sheafToPresheaf J (Type w)).map f).app X)

tactic: rw [isIso_iff_bijective]
state_before: C : Type u
inst✝² : Category.{v, u} C
J : GrothendieckTopology C
A : Type u'
inst✝¹ : Category.{v', u'} A
inst✝ : ConcreteCategory A
F G : Sheaf J (Type w)
f : F ⟶ G
h₁ : ∀ (X : Cᵒᵖ), Function.Injective ⇑(f.val.app X)
right✝ : IsLocallySurjective f
this : ∀ (X : Cᵒᵖ), Function.Surjective (f.val.app X)
X : Cᵒᵖ
⊢ IsIso (((sheafToPresheaf J (Type w)).map f).app X)
state_after: C : Type u
inst✝² : Category.{v, u} C
J : GrothendieckTopology C
A : Type u'
inst✝¹ : Category.{v', u'} A
inst✝ : ConcreteCategory A
F G : Sheaf J (Type w)
f : F ⟶ G
h₁ : ∀ (X : Cᵒᵖ), Function.Injective ⇑(f.val.app X)
right✝ : IsLocallySurjective f
this : ∀ (X : Cᵒᵖ), Function.Surjective (f.val.app X)
X : Cᵒᵖ
⊢ Function.Bijective (((sheafToPresheaf J (Type w)).map f).app X)

tactic: exact ⟨h₁ X, this X⟩
state_before: C : Type u
inst✝² : Category.{v, u} C
J : GrothendieckTopology C
A : Type u'
inst✝¹ : Category.{v', u'} A
inst✝ : ConcreteCategory A
F G : Sheaf J (Type w)
f : F ⟶ G
h₁ : ∀ (X : Cᵒᵖ), Function.Injective ⇑(f.val.app X)
right✝ : IsLocallySurjective f
this : ∀ (X : Cᵒᵖ), Function.Surjective (f.val.app X)
X : Cᵒᵖ
⊢ Function.Bijective (((sheafToPresheaf J (Type w)).map f).app X)
state_after: no goals

tactic: intro Y₁ Y₂ W g₁ g₂ f₁ f₂ hf₁ hf₂ w
state_before: C : Type u
inst✝² : Category.{v, u} C
J : GrothendieckTopology C
A : Type u'
inst✝¹ : Category.{v', u'} A
inst✝ : ConcreteCategory A
F G : Sheaf J (Type w)
f : F ⟶ G
h₁ : ∀ (X : Cᵒᵖ), Function.Injective ⇑(f.val.app X)
right✝ : IsLocallySurjective f
X : Cᵒᵖ
s : G.val.obj X
H : Presieve.IsSheafFor F.val (Presheaf.imageSieve f.val s).arrows
t : Presieve.FamilyOfElements F.val (Presheaf.imageSieve f.val s).arrows :=
  fun Y g hg => Presheaf.localPreimage f.val s g hg
⊢ t.Compatible
state_after: C : Type u
inst✝² : Category.{v, u} C
J : GrothendieckTopology C
A : Type u'
inst✝¹ : Category.{v', u'} A
inst✝ : ConcreteCategory A
F G : Sheaf J (Type w)
f : F ⟶ G
h₁ : ∀ (X : Cᵒᵖ), Function.Injective ⇑(f.val.app X)
right✝ : IsLocallySurjective f
X : Cᵒᵖ
s : G.val.obj X
H : Presieve.IsSheafFor F.val (Presheaf.imageSieve f.val s).arrows
t : Presieve.FamilyOfElements F.val (Presheaf.imageSieve f.val s).arrows :=
  fun Y g hg => Presheaf.localPreimage f.val s g hg
Y₁ Y₂ W : C
g₁ : W ⟶ Y₁
g₂ : W ⟶ Y₂
f₁ : Y₁ ⟶ X.unop
f₂ : Y₂ ⟶ X.unop
hf₁ : (Presheaf.imageSieve f.val s).arrows f₁
hf₂ : (Presheaf.imageSieve f.val s).arrows f₂
w : g₁ ≫ f₁ = g₂ ≫ f₂
⊢ F.val.map g₁.op (t f₁ hf₁) = F.val.map g₂.op (t f₂ hf₂)

tactic: apply h₁
state_before: C : Type u
inst✝² : Category.{v, u} C
J : GrothendieckTopology C
A : Type u'
inst✝¹ : Category.{v', u'} A
inst✝ : ConcreteCategory A
F G : Sheaf J (Type w)
f : F ⟶ G
h₁ : ∀ (X : Cᵒᵖ), Function.Injective ⇑(f.val.app X)
right✝ : IsLocallySurjective f
X : Cᵒᵖ
s : G.val.obj X
H : Presieve.IsSheafFor F.val (Presheaf.imageSieve f.val s).arrows
t : Presieve.FamilyOfElements F.val (Presheaf.imageSieve f.val s).arrows :=
  fun Y g hg => Presheaf.localPreimage f.val s g hg
Y₁ Y₂ W : C
g₁ : W ⟶ Y₁
g₂ : W ⟶ Y₂
f₁ : Y₁ ⟶ X.unop
f₂ : Y₂ ⟶ X.unop
hf₁ : (Presheaf.imageSieve f.val s).arrows f₁
hf₂ : (Presheaf.imageSieve f.val s).arrows f₂
w : g₁ ≫ f₁ = g₂ ≫ f₂
⊢ F.val.map g₁.op (t f₁ hf₁) = F.val.map g₂.op (t f₂ hf₂)
state_after: case a
C : Type u
inst✝² : Category.{v, u} C
J : GrothendieckTopology C
A : Type u'
inst✝¹ : Category.{v', u'} A
inst✝ : ConcreteCategory A
F G : Sheaf J (Type w)
f : F ⟶ G
h₁ : ∀ (X : Cᵒᵖ), Function.Injective ⇑(f.val.app X)
right✝ : IsLocallySurjective f
X : Cᵒᵖ
s : G.val.obj X
H : Presieve.IsSheafFor F.val (Presheaf.imageSieve f.val s).arrows
t : Presieve.FamilyOfElements F.val (Presheaf.imageSieve f.val s).arrows :=
  fun Y g hg => Presheaf.localPreimage f.val s g hg
Y₁ Y₂ W : C
g₁ : W ⟶ Y₁
g₂ : W ⟶ Y₂
f₁ : Y₁ ⟶ X.unop
f₂ : Y₂ ⟶ X.unop
hf₁ : (Presheaf.imageSieve f.val s).arrows f₁
hf₂ : (Presheaf.imageSieve f.val s).arrows f₂
w : g₁ ≫ f₁ = g₂ ≫ f₂
⊢ (f.val.app { unop := W }) (F.val.map g₁.op (t f₁ hf₁)) = (f.val.app { unop := W }) (F.val.map g₂.op (t f₂ hf₂))

tactic: have eq₁ := FunctorToTypes.naturality _ _ f.val g₁.op (t f₁ hf₁)
state_before: case a
C : Type u
inst✝² : Category.{v, u} C
J : GrothendieckTopology C
A : Type u'
inst✝¹ : Category.{v', u'} A
inst✝ : ConcreteCategory A
F G : Sheaf J (Type w)
f : F ⟶ G
h₁ : ∀ (X : Cᵒᵖ), Function.Injective ⇑(f.val.app X)
right✝ : IsLocallySurjective f
X : Cᵒᵖ
s : G.val.obj X
H : Presieve.IsSheafFor F.val (Presheaf.imageSieve f.val s).arrows
t : Presieve.FamilyOfElements F.val (Presheaf.imageSieve f.val s).arrows :=
  fun Y g hg => Presheaf.localPreimage f.val s g hg
Y₁ Y₂ W : C
g₁ : W ⟶ Y₁
g₂ : W ⟶ Y₂
f₁ : Y₁ ⟶ X.unop
f₂ : Y₂ ⟶ X.unop
hf₁ : (Presheaf.imageSieve f.val s).arrows f₁
hf₂ : (Presheaf.imageSieve f.val s).arrows f₂
w : g₁ ≫ f₁ = g₂ ≫ f₂
⊢ (f.val.app { unop := W }) (F.val.map g₁.op (t f₁ hf₁)) = (f.val.app { unop := W }) (F.val.map g₂.op (t f₂ hf₂))
state_after: case a
C : Type u
inst✝² : Category.{v, u} C
J : GrothendieckTopology C
A : Type u'
inst✝¹ : Category.{v', u'} A
inst✝ : ConcreteCategory A
F G : Sheaf J (Type w)
f : F ⟶ G
h₁ : ∀ (X : Cᵒᵖ), Function.Injective ⇑(f.val.app X)
right✝ : IsLocallySurjective f
X : Cᵒᵖ
s : G.val.obj X
H : Presieve.IsSheafFor F.val (Presheaf.imageSieve f.val s).arrows
t : Presieve.FamilyOfElements F.val (Presheaf.imageSieve f.val s).arrows :=
  fun Y g hg => Presheaf.localPreimage f.val s g hg
Y₁ Y₂ W : C
g₁ : W ⟶ Y₁
g₂ : W ⟶ Y₂
f₁ : Y₁ ⟶ X.unop
f₂ : Y₂ ⟶ X.unop
hf₁ : (Presheaf.imageSieve f.val s).arrows f₁
hf₂ : (Presheaf.imageSieve f.val s).arrows f₂
w : g₁ ≫ f₁ = g₂ ≫ f₂
eq₁ : f.val.app { unop := W } (F.val.map g₁.op (t f₁ hf₁)) = G.val.map g₁.op (f.val.app { unop := Y₁ } (t f₁ hf₁))
⊢ (f.val.app { unop := W }) (F.val.map g₁.op (t f₁ hf₁)) = (f.val.app { unop := W }) (F.val.map g₂.op (t f₂ hf₂))

tactic: have eq₂ := FunctorToTypes.naturality _ _ f.val g₂.op (t f₂ hf₂)
state_before: case a
C : Type u
inst✝² : Category.{v, u} C
J : GrothendieckTopology C
A : Type u'
inst✝¹ : Category.{v', u'} A
inst✝ : ConcreteCategory A
F G : Sheaf J (Type w)
f : F ⟶ G
h₁ : ∀ (X : Cᵒᵖ), Function.Injective ⇑(f.val.app X)
right✝ : IsLocallySurjective f
X : Cᵒᵖ
s : G.val.obj X
H : Presieve.IsSheafFor F.val (Presheaf.imageSieve f.val s).arrows
t : Presieve.FamilyOfElements F.val (Presheaf.imageSieve f.val s).arrows :=
  fun Y g hg => Presheaf.localPreimage f.val s g hg
Y₁ Y₂ W : C
g₁ : W ⟶ Y₁
g₂ : W ⟶ Y₂
f₁ : Y₁ ⟶ X.unop
f₂ : Y₂ ⟶ X.unop
hf₁ : (Presheaf.imageSieve f.val s).arrows f₁
hf₂ : (Presheaf.imageSieve f.val s).arrows f₂
w : g₁ ≫ f₁ = g₂ ≫ f₂
eq₁ : f.val.app { unop := W } (F.val.map g₁.op (t f₁ hf₁)) = G.val.map g₁.op (f.val.app { unop := Y₁ } (t f₁ hf₁))
⊢ (f.val.app { unop := W }) (F.val.map g₁.op (t f₁ hf₁)) = (f.val.app { unop := W }) (F.val.map g₂.op (t f₂ hf₂))
state_after: case a
C : Type u
inst✝² : Category.{v, u} C
J : GrothendieckTopology C
A : Type u'
inst✝¹ : Category.{v', u'} A
inst✝ : ConcreteCategory A
F G : Sheaf J (Type w)
f : F ⟶ G
h₁ : ∀ (X : Cᵒᵖ), Function.Injective ⇑(f.val.app X)
right✝ : IsLocallySurjective f
X : Cᵒᵖ
s : G.val.obj X
H : Presieve.IsSheafFor F.val (Presheaf.imageSieve f.val s).arrows
t : Presieve.FamilyOfElements F.val (Presheaf.imageSieve f.val s).arrows :=
  fun Y g hg => Presheaf.localPreimage f.val s g hg
Y₁ Y₂ W : C
g₁ : W ⟶ Y₁
g₂ : W ⟶ Y₂
f₁ : Y₁ ⟶ X.unop
f₂ : Y₂ ⟶ X.unop
hf₁ : (Presheaf.imageSieve f.val s).arrows f₁
hf₂ : (Presheaf.imageSieve f.val s).arrows f₂
w : g₁ ≫ f₁ = g₂ ≫ f₂
eq₁ : f.val.app { unop := W } (F.val.map g₁.op (t f₁ hf₁)) = G.val.map g₁.op (f.val.app { unop := Y₁ } (t f₁ hf₁))
eq₂ : f.val.app { unop := W } (F.val.map g₂.op (t f₂ hf₂)) = G.val.map g₂.op (f.val.app { unop := Y₂ } (t f₂ hf₂))
⊢ (f.val.app { unop := W }) (F.val.map g₁.op (t f₁ hf₁)) = (f.val.app { unop := W }) (F.val.map g₂.op (t f₂ hf₂))

tactic: have eq₃ := congr_arg (G.val.map g₁.op) (Presheaf.app_localPreimage f.val s _ hf₁)
state_before: case a
C : Type u
inst✝² : Category.{v, u} C
J : GrothendieckTopology C
A : Type u'
inst✝¹ : Category.{v', u'} A
inst✝ : ConcreteCategory A
F G : Sheaf J (Type w)
f : F ⟶ G
h₁ : ∀ (X : Cᵒᵖ), Function.Injective ⇑(f.val.app X)
right✝ : IsLocallySurjective f
X : Cᵒᵖ
s : G.val.obj X
H : Presieve.IsSheafFor F.val (Presheaf.imageSieve f.val s).arrows
t : Presieve.FamilyOfElements F.val (Presheaf.imageSieve f.val s).arrows :=
  fun Y g hg => Presheaf.localPreimage f.val s g hg
Y₁ Y₂ W : C
g₁ : W ⟶ Y₁
g₂ : W ⟶ Y₂
f₁ : Y₁ ⟶ X.unop
f₂ : Y₂ ⟶ X.unop
hf₁ : (Presheaf.imageSieve f.val s).arrows f₁
hf₂ : (Presheaf.imageSieve f.val s).arrows f₂
w : g₁ ≫ f₁ = g₂ ≫ f₂
eq₁ : f.val.app { unop := W } (F.val.map g₁.op (t f₁ hf₁)) = G.val.map g₁.op (f.val.app { unop := Y₁ } (t f₁ hf₁))
eq₂ : f.val.app { unop := W } (F.val.map g₂.op (t f₂ hf₂)) = G.val.map g₂.op (f.val.app { unop := Y₂ } (t f₂ hf₂))
⊢ (f.val.app { unop := W }) (F.val.map g₁.op (t f₁ hf₁)) = (f.val.app { unop := W }) (F.val.map g₂.op (t f₂ hf₂))
state_after: case a
C : Type u
inst✝² : Category.{v, u} C
J : GrothendieckTopology C
A : Type u'
inst✝¹ : Category.{v', u'} A
inst✝ : ConcreteCategory A
F G : Sheaf J (Type w)
f : F ⟶ G
h₁ : ∀ (X : Cᵒᵖ), Function.Injective ⇑(f.val.app X)
right✝ : IsLocallySurjective f
X : Cᵒᵖ
s : G.val.obj X
H : Presieve.IsSheafFor F.val (Presheaf.imageSieve f.val s).arrows
t : Presieve.FamilyOfElements F.val (Presheaf.imageSieve f.val s).arrows :=
  fun Y g hg => Presheaf.localPreimage f.val s g hg
Y₁ Y₂ W : C
g₁ : W ⟶ Y₁
g₂ : W ⟶ Y₂
f₁ : Y₁ ⟶ X.unop
f₂ : Y₂ ⟶ X.unop
hf₁ : (Presheaf.imageSieve f.val s).arrows f₁
hf₂ : (Presheaf.imageSieve f.val s).arrows f₂
w : g₁ ≫ f₁ = g₂ ≫ f₂
eq₁ : f.val.app { unop := W } (F.val.map g₁.op (t f₁ hf₁)) = G.val.map g₁.op (f.val.app { unop := Y₁ } (t f₁ hf₁))
eq₂ : f.val.app { unop := W } (F.val.map g₂.op (t f₂ hf₂)) = G.val.map g₂.op (f.val.app { unop := Y₂ } (t f₂ hf₂))
eq₃ :
  G.val.map g₁.op ((f.val.app { unop := Y₁ }) (Presheaf.localPreimage f.val s f₁ hf₁)) =
    G.val.map g₁.op ((G.val.map f₁.op) s)
⊢ (f.val.app { unop := W }) (F.val.map g₁.op (t f₁ hf₁)) = (f.val.app { unop := W }) (F.val.map g₂.op (t f₂ hf₂))

tactic: have eq₄ := congr_arg (G.val.map g₂.op) (Presheaf.app_localPreimage f.val s _ hf₂)
state_before: case a
C : Type u
inst✝² : Category.{v, u} C
J : GrothendieckTopology C
A : Type u'
inst✝¹ : Category.{v', u'} A
inst✝ : ConcreteCategory A
F G : Sheaf J (Type w)
f : F ⟶ G
h₁ : ∀ (X : Cᵒᵖ), Function.Injective ⇑(f.val.app X)
right✝ : IsLocallySurjective f
X : Cᵒᵖ
s : G.val.obj X
H : Presieve.IsSheafFor F.val (Presheaf.imageSieve f.val s).arrows
t : Presieve.FamilyOfElements F.val (Presheaf.imageSieve f.val s).arrows :=
  fun Y g hg => Presheaf.localPreimage f.val s g hg
Y₁ Y₂ W : C
g₁ : W ⟶ Y₁
g₂ : W ⟶ Y₂
f₁ : Y₁ ⟶ X.unop
f₂ : Y₂ ⟶ X.unop
hf₁ : (Presheaf.imageSieve f.val s).arrows f₁
hf₂ : (Presheaf.imageSieve f.val s).arrows f₂
w : g₁ ≫ f₁ = g₂ ≫ f₂
eq₁ : f.val.app { unop := W } (F.val.map g₁.op (t f₁ hf₁)) = G.val.map g₁.op (f.val.app { unop := Y₁ } (t f₁ hf₁))
eq₂ : f.val.app { unop := W } (F.val.map g₂.op (t f₂ hf₂)) = G.val.map g₂.op (f.val.app { unop := Y₂ } (t f₂ hf₂))
eq₃ :
  G.val.map g₁.op ((f.val.app { unop := Y₁ }) (Presheaf.localPreimage f.val s f₁ hf₁)) =
    G.val.map g₁.op ((G.val.map f₁.op) s)
⊢ (f.val.app { unop := W }) (F.val.map g₁.op (t f₁ hf₁)) = (f.val.app { unop := W }) (F.val.map g₂.op (t f₂ hf₂))
state_after: case a
C : Type u
inst✝² : Category.{v, u} C
J : GrothendieckTopology C
A : Type u'
inst✝¹ : Category.{v', u'} A
inst✝ : ConcreteCategory A
F G : Sheaf J (Type w)
f : F ⟶ G
h₁ : ∀ (X : Cᵒᵖ), Function.Injective ⇑(f.val.app X)
right✝ : IsLocallySurjective f
X : Cᵒᵖ
s : G.val.obj X
H : Presieve.IsSheafFor F.val (Presheaf.imageSieve f.val s).arrows
t : Presieve.FamilyOfElements F.val (Presheaf.imageSieve f.val s).arrows :=
  fun Y g hg => Presheaf.localPreimage f.val s g hg
Y₁ Y₂ W : C
g₁ : W ⟶ Y₁
g₂ : W ⟶ Y₂
f₁ : Y₁ ⟶ X.unop
f₂ : Y₂ ⟶ X.unop
hf₁ : (Presheaf.imageSieve f.val s).arrows f₁
hf₂ : (Presheaf.imageSieve f.val s).arrows f₂
w : g₁ ≫ f₁ = g₂ ≫ f₂
eq₁ : f.val.app { unop := W } (F.val.map g₁.op (t f₁ hf₁)) = G.val.map g₁.op (f.val.app { unop := Y₁ } (t f₁ hf₁))
eq₂ : f.val.app { unop := W } (F.val.map g₂.op (t f₂ hf₂)) = G.val.map g₂.op (f.val.app { unop := Y₂ } (t f₂ hf₂))
eq₃ :
  G.val.map g₁.op ((f.val.app { unop := Y₁ }) (Presheaf.localPreimage f.val s f₁ hf₁)) =
    G.val.map g₁.op ((G.val.map f₁.op) s)
eq₄ :
  G.val.map g₂.op ((f.val.app { unop := Y₂ }) (Presheaf.localPreimage f.val s f₂ hf₂)) =
    G.val.map g₂.op ((G.val.map f₂.op) s)
⊢ (f.val.app { unop := W }) (F.val.map g₁.op (t f₁ hf₁)) = (f.val.app { unop := W }) (F.val.map g₂.op (t f₂ hf₂))

tactic: refine eq₁.trans (eq₃.trans (Eq.trans ?_ (eq₄.symm.trans eq₂.symm)))
state_before: case a
C : Type u
inst✝² : Category.{v, u} C
J : GrothendieckTopology C
A : Type u'
inst✝¹ : Category.{v', u'} A
inst✝ : ConcreteCategory A
F G : Sheaf J (Type w)
f : F ⟶ G
h₁ : ∀ (X : Cᵒᵖ), Function.Injective ⇑(f.val.app X)
right✝ : IsLocallySurjective f
X : Cᵒᵖ
s : G.val.obj X
H : Presieve.IsSheafFor F.val (Presheaf.imageSieve f.val s).arrows
t : Presieve.FamilyOfElements F.val (Presheaf.imageSieve f.val s).arrows :=
  fun Y g hg => Presheaf.localPreimage f.val s g hg
Y₁ Y₂ W : C
g₁ : W ⟶ Y₁
g₂ : W ⟶ Y₂
f₁ : Y₁ ⟶ X.unop
f₂ : Y₂ ⟶ X.unop
hf₁ : (Presheaf.imageSieve f.val s).arrows f₁
hf₂ : (Presheaf.imageSieve f.val s).arrows f₂
w : g₁ ≫ f₁ = g₂ ≫ f₂
eq₁ : f.val.app { unop := W } (F.val.map g₁.op (t f₁ hf₁)) = G.val.map g₁.op (f.val.app { unop := Y₁ } (t f₁ hf₁))
eq₂ : f.val.app { unop := W } (F.val.map g₂.op (t f₂ hf₂)) = G.val.map g₂.op (f.val.app { unop := Y₂ } (t f₂ hf₂))
eq₃ :
  G.val.map g₁.op ((f.val.app { unop := Y₁ }) (Presheaf.localPreimage f.val s f₁ hf₁)) =
    G.val.map g₁.op ((G.val.map f₁.op) s)
eq₄ :
  G.val.map g₂.op ((f.val.app { unop := Y₂ }) (Presheaf.localPreimage f.val s f₂ hf₂)) =
    G.val.map g₂.op ((G.val.map f₂.op) s)
⊢ (f.val.app { unop := W }) (F.val.map g₁.op (t f₁ hf₁)) = (f.val.app { unop := W }) (F.val.map g₂.op (t f₂ hf₂))
state_after: case a
C : Type u
inst✝² : Category.{v, u} C
J : GrothendieckTopology C
A : Type u'
inst✝¹ : Category.{v', u'} A
inst✝ : ConcreteCategory A
F G : Sheaf J (Type w)
f : F ⟶ G
h₁ : ∀ (X : Cᵒᵖ), Function.Injective ⇑(f.val.app X)
right✝ : IsLocallySurjective f
X : Cᵒᵖ
s : G.val.obj X
H : Presieve.IsSheafFor F.val (Presheaf.imageSieve f.val s).arrows
t : Presieve.FamilyOfElements F.val (Presheaf.imageSieve f.val s).arrows :=
  fun Y g hg => Presheaf.localPreimage f.val s g hg
Y₁ Y₂ W : C
g₁ : W ⟶ Y₁
g₂ : W ⟶ Y₂
f₁ : Y₁ ⟶ X.unop
f₂ : Y₂ ⟶ X.unop
hf₁ : (Presheaf.imageSieve f.val s).arrows f₁
hf₂ : (Presheaf.imageSieve f.val s).arrows f₂
w : g₁ ≫ f₁ = g₂ ≫ f₂
eq₁ : f.val.app { unop := W } (F.val.map g₁.op (t f₁ hf₁)) = G.val.map g₁.op (f.val.app { unop := Y₁ } (t f₁ hf₁))
eq₂ : f.val.app { unop := W } (F.val.map g₂.op (t f₂ hf₂)) = G.val.map g₂.op (f.val.app { unop := Y₂ } (t f₂ hf₂))
eq₃ :
  G.val.map g₁.op ((f.val.app { unop := Y₁ }) (Presheaf.localPreimage f.val s f₁ hf₁)) =
    G.val.map g₁.op ((G.val.map f₁.op) s)
eq₄ :
  G.val.map g₂.op ((f.val.app { unop := Y₂ }) (Presheaf.localPreimage f.val s f₂ hf₂)) =
    G.val.map g₂.op ((G.val.map f₂.op) s)
⊢ G.val.map g₁.op ((G.val.map f₁.op) s) = G.val.map g₂.op ((G.val.map f₂.op) s)

tactic: erw [← FunctorToTypes.map_comp_apply, ← FunctorToTypes.map_comp_apply]
state_before: case a
C : Type u
inst✝² : Category.{v, u} C
J : GrothendieckTopology C
A : Type u'
inst✝¹ : Category.{v', u'} A
inst✝ : ConcreteCategory A
F G : Sheaf J (Type w)
f : F ⟶ G
h₁ : ∀ (X : Cᵒᵖ), Function.Injective ⇑(f.val.app X)
right✝ : IsLocallySurjective f
X : Cᵒᵖ
s : G.val.obj X
H : Presieve.IsSheafFor F.val (Presheaf.imageSieve f.val s).arrows
t : Presieve.FamilyOfElements F.val (Presheaf.imageSieve f.val s).arrows :=
  fun Y g hg => Presheaf.localPreimage f.val s g hg
Y₁ Y₂ W : C
g₁ : W ⟶ Y₁
g₂ : W ⟶ Y₂
f₁ : Y₁ ⟶ X.unop
f₂ : Y₂ ⟶ X.unop
hf₁ : (Presheaf.imageSieve f.val s).arrows f₁
hf₂ : (Presheaf.imageSieve f.val s).arrows f₂
w : g₁ ≫ f₁ = g₂ ≫ f₂
eq₁ : f.val.app { unop := W } (F.val.map g₁.op (t f₁ hf₁)) = G.val.map g₁.op (f.val.app { unop := Y₁ } (t f₁ hf₁))
eq₂ : f.val.app { unop := W } (F.val.map g₂.op (t f₂ hf₂)) = G.val.map g₂.op (f.val.app { unop := Y₂ } (t f₂ hf₂))
eq₃ :
  G.val.map g₁.op ((f.val.app { unop := Y₁ }) (Presheaf.localPreimage f.val s f₁ hf₁)) =
    G.val.map g₁.op ((G.val.map f₁.op) s)
eq₄ :
  G.val.map g₂.op ((f.val.app { unop := Y₂ }) (Presheaf.localPreimage f.val s f₂ hf₂)) =
    G.val.map g₂.op ((G.val.map f₂.op) s)
⊢ G.val.map g₁.op ((G.val.map f₁.op) s) = G.val.map g₂.op ((G.val.map f₂.op) s)
state_after: case a
C : Type u
inst✝² : Category.{v, u} C
J : GrothendieckTopology C
A : Type u'
inst✝¹ : Category.{v', u'} A
inst✝ : ConcreteCategory A
F G : Sheaf J (Type w)
f : F ⟶ G
h₁ : ∀ (X : Cᵒᵖ), Function.Injective ⇑(f.val.app X)
right✝ : IsLocallySurjective f
X : Cᵒᵖ
s : G.val.obj X
H : Presieve.IsSheafFor F.val (Presheaf.imageSieve f.val s).arrows
t : Presieve.FamilyOfElements F.val (Presheaf.imageSieve f.val s).arrows :=
  fun Y g hg => Presheaf.localPreimage f.val s g hg
Y₁ Y₂ W : C
g₁ : W ⟶ Y₁
g₂ : W ⟶ Y₂
f₁ : Y₁ ⟶ X.unop
f₂ : Y₂ ⟶ X.unop
hf₁ : (Presheaf.imageSieve f.val s).arrows f₁
hf₂ : (Presheaf.imageSieve f.val s).arrows f₂
w : g₁ ≫ f₁ = g₂ ≫ f₂
eq₁ : f.val.app { unop := W } (F.val.map g₁.op (t f₁ hf₁)) = G.val.map g₁.op (f.val.app { unop := Y₁ } (t f₁ hf₁))
eq₂ : f.val.app { unop := W } (F.val.map g₂.op (t f₂ hf₂)) = G.val.map g₂.op (f.val.app { unop := Y₂ } (t f₂ hf₂))
eq₃ :
  G.val.map g₁.op ((f.val.app { unop := Y₁ }) (Presheaf.localPreimage f.val s f₁ hf₁)) =
    G.val.map g₁.op ((G.val.map f₁.op) s)
eq₄ :
  G.val.map g₂.op ((f.val.app { unop := Y₂ }) (Presheaf.localPreimage f.val s f₂ hf₂)) =
    G.val.map g₂.op ((G.val.map f₂.op) s)
⊢ G.val.map (f₁.op ≫ g₁.op) s = G.val.map (f₂.op ≫ g₂.op) s

tactic: simp only [← op_comp, w]
state_before: case a
C : Type u
inst✝² : Category.{v, u} C
J : GrothendieckTopology C
A : Type u'
inst✝¹ : Category.{v', u'} A
inst✝ : ConcreteCategory A
F G : Sheaf J (Type w)
f : F ⟶ G
h₁ : ∀ (X : Cᵒᵖ), Function.Injective ⇑(f.val.app X)
right✝ : IsLocallySurjective f
X : Cᵒᵖ
s : G.val.obj X
H : Presieve.IsSheafFor F.val (Presheaf.imageSieve f.val s).arrows
t : Presieve.FamilyOfElements F.val (Presheaf.imageSieve f.val s).arrows :=
  fun Y g hg => Presheaf.localPreimage f.val s g hg
Y₁ Y₂ W : C
g₁ : W ⟶ Y₁
g₂ : W ⟶ Y₂
f₁ : Y₁ ⟶ X.unop
f₂ : Y₂ ⟶ X.unop
hf₁ : (Presheaf.imageSieve f.val s).arrows f₁
hf₂ : (Presheaf.imageSieve f.val s).arrows f₂
w : g₁ ≫ f₁ = g₂ ≫ f₂
eq₁ : f.val.app { unop := W } (F.val.map g₁.op (t f₁ hf₁)) = G.val.map g₁.op (f.val.app { unop := Y₁ } (t f₁ hf₁))
eq₂ : f.val.app { unop := W } (F.val.map g₂.op (t f₂ hf₂)) = G.val.map g₂.op (f.val.app { unop := Y₂ } (t f₂ hf₂))
eq₃ :
  G.val.map g₁.op ((f.val.app { unop := Y₁ }) (Presheaf.localPreimage f.val s f₁ hf₁)) =
    G.val.map g₁.op ((G.val.map f₁.op) s)
eq₄ :
  G.val.map g₂.op ((f.val.app { unop := Y₂ }) (Presheaf.localPreimage f.val s f₂ hf₂)) =
    G.val.map g₂.op ((G.val.map f₂.op) s)
⊢ G.val.map (f₁.op ≫ g₁.op) s = G.val.map (f₂.op ≫ g₂.op) s
state_after: no goals

tactic: apply (Presieve.isSeparated_of_isSheaf _ _
  ((isSheaf_iff_isSheaf_of_type J G.val).1 G.cond) _
  (Presheaf.imageSieve_mem J f.val s)).ext
state_before: case mp.intro
C : Type u
inst✝² : Category.{v, u} C
J : GrothendieckTopology C
A : Type u'
inst✝¹ : Category.{v', u'} A
inst✝ : ConcreteCategory A
F G : Sheaf J (Type w)
f : F ⟶ G
h₁ : ∀ (X : Cᵒᵖ), Function.Injective ⇑(f.val.app X)
right✝ : IsLocallySurjective f
X : Cᵒᵖ
s : G.val.obj X
H : Presieve.IsSheafFor F.val (Presheaf.imageSieve f.val s).arrows
t : Presieve.FamilyOfElements F.val (Presheaf.imageSieve f.val s).arrows :=
  fun Y g hg => Presheaf.localPreimage f.val s g hg
ht : t.Compatible
⊢ f.val.app X (H.amalgamate t ht) = s
state_after: case mp.intro
C : Type u
inst✝² : Category.{v, u} C
J : GrothendieckTopology C
A : Type u'
inst✝¹ : Category.{v', u'} A
inst✝ : ConcreteCategory A
F G : Sheaf J (Type w)
f : F ⟶ G
h₁ : ∀ (X : Cᵒᵖ), Function.Injective ⇑(f.val.app X)
right✝ : IsLocallySurjective f
X : Cᵒᵖ
s : G.val.obj X
H : Presieve.IsSheafFor F.val (Presheaf.imageSieve f.val s).arrows
t : Presieve.FamilyOfElements F.val (Presheaf.imageSieve f.val s).arrows :=
  fun Y g hg => Presheaf.localPreimage f.val s g hg
ht : t.Compatible
⊢ ∀ ⦃Y : C⦄ ⦃f_1 : Y ⟶ X.unop⦄,
    (Presheaf.imageSieve f.val s).arrows f_1 → G.val.map f_1.op (f.val.app X (H.amalgamate t ht)) = G.val.map f_1.op s

tactic: intro Y g hg
state_before: case mp.intro
C : Type u
inst✝² : Category.{v, u} C
J : GrothendieckTopology C
A : Type u'
inst✝¹ : Category.{v', u'} A
inst✝ : ConcreteCategory A
F G : Sheaf J (Type w)
f : F ⟶ G
h₁ : ∀ (X : Cᵒᵖ), Function.Injective ⇑(f.val.app X)
right✝ : IsLocallySurjective f
X : Cᵒᵖ
s : G.val.obj X
H : Presieve.IsSheafFor F.val (Presheaf.imageSieve f.val s).arrows
t : Presieve.FamilyOfElements F.val (Presheaf.imageSieve f.val s).arrows :=
  fun Y g hg => Presheaf.localPreimage f.val s g hg
ht : t.Compatible
⊢ ∀ ⦃Y : C⦄ ⦃f_1 : Y ⟶ X.unop⦄,
    (Presheaf.imageSieve f.val s).arrows f_1 → G.val.map f_1.op (f.val.app X (H.amalgamate t ht)) = G.val.map f_1.op s
state_after: case mp.intro
C : Type u
inst✝² : Category.{v, u} C
J : GrothendieckTopology C
A : Type u'
inst✝¹ : Category.{v', u'} A
inst✝ : ConcreteCategory A
F G : Sheaf J (Type w)
f : F ⟶ G
h₁ : ∀ (X : Cᵒᵖ), Function.Injective ⇑(f.val.app X)
right✝ : IsLocallySurjective f
X : Cᵒᵖ
s : G.val.obj X
H : Presieve.IsSheafFor F.val (Presheaf.imageSieve f.val s).arrows
t : Presieve.FamilyOfElements F.val (Presheaf.imageSieve f.val s).arrows :=
  fun Y g hg => Presheaf.localPreimage f.val s g hg
ht : t.Compatible
Y : C
g : Y ⟶ X.unop
hg : (Presheaf.imageSieve f.val s).arrows g
⊢ G.val.map g.op (f.val.app X (H.amalgamate t ht)) = G.val.map g.op s

tactic: rw [← FunctorToTypes.naturality, H.valid_glue ht]
state_before: case mp.intro
C : Type u
inst✝² : Category.{v, u} C
J : GrothendieckTopology C
A : Type u'
inst✝¹ : Category.{v', u'} A
inst✝ : ConcreteCategory A
F G : Sheaf J (Type w)
f : F ⟶ G
h₁ : ∀ (X : Cᵒᵖ), Function.Injective ⇑(f.val.app X)
right✝ : IsLocallySurjective f
X : Cᵒᵖ
s : G.val.obj X
H : Presieve.IsSheafFor F.val (Presheaf.imageSieve f.val s).arrows
t : Presieve.FamilyOfElements F.val (Presheaf.imageSieve f.val s).arrows :=
  fun Y g hg => Presheaf.localPreimage f.val s g hg
ht : t.Compatible
Y : C
g : Y ⟶ X.unop
hg : (Presheaf.imageSieve f.val s).arrows g
⊢ G.val.map g.op (f.val.app X (H.amalgamate t ht)) = G.val.map g.op s
state_after: case mp.intro
C : Type u
inst✝² : Category.{v, u} C
J : GrothendieckTopology C
A : Type u'
inst✝¹ : Category.{v', u'} A
inst✝ : ConcreteCategory A
F G : Sheaf J (Type w)
f : F ⟶ G
h₁ : ∀ (X : Cᵒᵖ), Function.Injective ⇑(f.val.app X)
right✝ : IsLocallySurjective f
X : Cᵒᵖ
s : G.val.obj X
H : Presieve.IsSheafFor F.val (Presheaf.imageSieve f.val s).arrows
t : Presieve.FamilyOfElements F.val (Presheaf.imageSieve f.val s).arrows :=
  fun Y g hg => Presheaf.localPreimage f.val s g hg
ht : t.Compatible
Y : C
g : Y ⟶ X.unop
hg : (Presheaf.imageSieve f.val s).arrows g
⊢ f.val.app { unop := Y } (t g ?mp.intro.Hf) = G.val.map g.op s

case mp.intro.Hf
C : Type u
inst✝² : Category.{v, u} C
J : GrothendieckTopology C
A : Type u'
inst✝¹ : Category.{v', u'} A
inst✝ : ConcreteCategory A
F G : Sheaf J (Type w)
f : F ⟶ G
h₁ : ∀ (X : Cᵒᵖ), Function.Injective ⇑(f.val.app X)
right✝ : IsLocallySurjective f
X : Cᵒᵖ
s : G.val.obj X
H : Presieve.IsSheafFor F.val (Presheaf.imageSieve f.val s).arrows
t : Presieve.FamilyOfElements F.val (Presheaf.imageSieve f.val s).arrows :=
  fun Y g hg => Presheaf.localPreimage f.val s g hg
ht : t.Compatible
Y : C
g : Y ⟶ X.unop
hg : (Presheaf.imageSieve f.val s).arrows g
⊢ (Presheaf.imageSieve f.val s).arrows g

tactic: exact Presheaf.app_localPreimage f.val s g hg
state_before: case mp.intro
C : Type u
inst✝² : Category.{v, u} C
J : GrothendieckTopology C
A : Type u'
inst✝¹ : Category.{v', u'} A
inst✝ : ConcreteCategory A
F G : Sheaf J (Type w)
f : F ⟶ G
h₁ : ∀ (X : Cᵒᵖ), Function.Injective ⇑(f.val.app X)
right✝ : IsLocallySurjective f
X : Cᵒᵖ
s : G.val.obj X
H : Presieve.IsSheafFor F.val (Presheaf.imageSieve f.val s).arrows
t : Presieve.FamilyOfElements F.val (Presheaf.imageSieve f.val s).arrows :=
  fun Y g hg => Presheaf.localPreimage f.val s g hg
ht : t.Compatible
Y : C
g : Y ⟶ X.unop
hg : (Presheaf.imageSieve f.val s).arrows g
⊢ f.val.app { unop := Y } (t g ?mp.intro.Hf) = G.val.map g.op s

case mp.intro.Hf
C : Type u
inst✝² : Category.{v, u} C
J : GrothendieckTopology C
A : Type u'
inst✝¹ : Category.{v', u'} A
inst✝ : ConcreteCategory A
F G : Sheaf J (Type w)
f : F ⟶ G
h₁ : ∀ (X : Cᵒᵖ), Function.Injective ⇑(f.val.app X)
right✝ : IsLocallySurjective f
X : Cᵒᵖ
s : G.val.obj X
H : Presieve.IsSheafFor F.val (Presheaf.imageSieve f.val s).arrows
t : Presieve.FamilyOfElements F.val (Presheaf.imageSieve f.val s).arrows :=
  fun Y g hg => Presheaf.localPreimage f.val s g hg
ht : t.Compatible
Y : C
g : Y ⟶ X.unop
hg : (Presheaf.imageSieve f.val s).arrows g
⊢ (Presheaf.imageSieve f.val s).arrows g
state_after: no goals

tactic: intro
state_before: case mpr
C : Type u
inst✝² : Category.{v, u} C
J : GrothendieckTopology C
A : Type u'
inst✝¹ : Category.{v', u'} A
inst✝ : ConcreteCategory A
F G : Sheaf J (Type w)
f : F ⟶ G
⊢ IsIso f → IsLocallyInjective f ∧ IsLocallySurjective f
state_after: case mpr
C : Type u
inst✝² : Category.{v, u} C
J : GrothendieckTopology C
A : Type u'
inst✝¹ : Category.{v', u'} A
inst✝ : ConcreteCategory A
F G : Sheaf J (Type w)
f : F ⟶ G
a✝ : IsIso f
⊢ IsLocallyInjective f ∧ IsLocallySurjective f

tactic: constructor <;> infer_instance
state_before: case mpr
C : Type u
inst✝² : Category.{v, u} C
J : GrothendieckTopology C
A : Type u'
inst✝¹ : Category.{v', u'} A
inst✝ : ConcreteCategory A
F G : Sheaf J (Type w)
f : F ⟶ G
a✝ : IsIso f
⊢ IsLocallyInjective f ∧ IsLocallySurjective f
state_after: no goals