l3lab/ntp-mathlib huggingface dataset:
/-- This theorem establishes **Leibniz's series for `π`**: The alternating sum of the reciprocals
  of the odd numbers is `π/4`. Note that this is a conditionally rather than absolutely convergent
  series. The main tool that this proof uses is the Mean Value Theorem (specifically avoiding the
  Fundamental Theorem of Calculus).

  Intuitively, the theorem holds because Leibniz's series is the Taylor series of `arctan x`
  centered about `0` and evaluated at the value `x = 1`. Therefore, much of this proof consists of
  reasoning about a function
    `f := arctan x - ∑ i in Finset.range k, (-(1:ℝ))^i * x^(2*i+1) / (2*i+1)`,
  the difference between `arctan` and the `k`-th partial sum of its Taylor series. Some ingenuity is
  required due to the fact that the Taylor series is not absolutely convergent at `x = 1`.

  This proof requires a bound on `f 1`, the key idea being that `f 1` can be split as the sum of
  `f 1 - f u` and `f u`, where `u` is a sequence of values in [0,1], carefully chosen such that
  each of these two terms can be controlled (in different ways).

  We begin the proof by (1) introducing that sequence `u` and then proving that another sequence
  constructed from `u` tends to `0` at `+∞`. After (2) converting the limit in our goal to an
  inequality, we (3) introduce the auxiliary function `f` defined above. Next, we (4) compute the
  derivative of `f`, denoted by `f'`, first generally and then on each of two subintervals of [0,1].
  We then (5) prove a bound for `f'`, again both generally as well as on each of the two
  subintervals. Finally, we (6) apply the Mean Value Theorem twice, obtaining bounds on `f 1 - f u`
  and `f u - f 0` from the bounds on `f'` (note that `f 0 = 0`). -/
theorem tendsto_sum_pi_div_four :
    Tendsto (fun k => ∑ i in Finset.range k, (-(1 : ℝ)) ^ i / (2 * i + 1)) atTop (𝓝 (π / 4)) := by
  rw [tendsto_iff_norm_sub_tendsto_zero, ← tendsto_zero_iff_norm_tendsto_zero]
  -- (1) We introduce a useful sequence `u` of values in [0,1], then prove that another sequence
  --     constructed from `u` tends to `0` at `+∞`
  let u := fun k : ℕ => (k : NNReal) ^ (-1 / (2 * (k : ℝ) + 1))
  have H : Tendsto (fun k : ℕ => (1 : ℝ) - u k + u k ^ (2 * (k : ℝ) + 1)) atTop (𝓝 0) := by
    convert (((tendsto_rpow_div_mul_add (-1) 2 1 two_ne_zero.symm).neg.const_add 1).add
        tendsto_inv_atTop_zero).comp tendsto_nat_cast_atTop_atTop using 1
    · ext k
      simp only [NNReal.coe_nat_cast, Function.comp_apply, NNReal.coe_rpow]
      rw [← rpow_mul (Nat.cast_nonneg k) (-1 / (2 * (k : ℝ) + 1)) (2 * (k : ℝ) + 1),
        @div_mul_cancel _ _ (2 * (k : ℝ) + 1) _
          (by norm_cast; simp only [Nat.succ_ne_zero, not_false_iff]),
        rpow_neg_one k, sub_eq_add_neg]
    · simp only [add_zero, add_right_neg]
  -- (2) We convert the limit in our goal to an inequality
  refine' squeeze_zero_norm _ H
  

Proof state:
u : ℕ → NNReal := fun k => ↑k ^ (-1 / (2 * ↑k + 1))
H : Tendsto (fun k => 1 - ↑(u k) + ↑(u k) ^ (2 * ↑k + 1)) atTop (𝓝 0)
⊢ ∀ (n : ℕ), ‖∑ i in Finset.range n, (-1) ^ i / (2 * ↑i + 1) - π / 4‖ ≤ 1 - ↑(u n) + ↑(u n) ^ (2 * ↑n + 1)

Next tactic:
intro k
/-- Given `f : F ⟶ G`, a morphism between presieves, and `s : G.obj (op U)`, this is the sieve
of `U` consisting of the `i : V ⟶ U` such that `s` restricted along `i` is in the image of `f`. -/
@[simps (config := .lemmasOnly)]
def imageSieve {F G : Cᵒᵖ ⥤ A} (f : F ⟶ G) {U : C} (s : G.obj (op U)) : Sieve U where
  arrows V i := ∃ t : F.obj (op V), f.app _ t = G.map i.op s
  downward_closed := by
    

Proof state:
C : Type u
inst✝² : Category.{v, u} C
J : GrothendieckTopology C
A : Type u'
inst✝¹ : Category.{v', u'} A
inst✝ : ConcreteCategory A
F G : Cᵒᵖ ⥤ A
f : F ⟶ G
U : C
s : (forget A).obj (G.obj (op U))
⊢ ∀ {Y Z : C} {f_1 : Y ⟶ U},
    (fun V i => ∃ t, (f.app (op V)) t = (G.map i.op) s) Y f_1 →
      ∀ (g : Z ⟶ Y), (fun V i => ∃ t, (f.app (op V)) t = (G.map i.op) s) Z (g ≫ f_1)

Next tactic:
rintro V W i ⟨t, ht⟩ j
/-- Given `f : F ⟶ G`, a morphism between presieves, and `s : G.obj (op U)`, this is the sieve
of `U` consisting of the `i : V ⟶ U` such that `s` restricted along `i` is in the image of `f`. -/
@[simps (config := .lemmasOnly)]
def imageSieve {F G : Cᵒᵖ ⥤ A} (f : F ⟶ G) {U : C} (s : G.obj (op U)) : Sieve U where
  arrows V i := ∃ t : F.obj (op V), f.app _ t = G.map i.op s
  downward_closed := by
    rintro V W i ⟨t, ht⟩ j
    

Proof state:
case 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 : Cᵒᵖ ⥤ A
f : F ⟶ G
U : C
s : (forget A).obj (G.obj (op U))
V W : C
i : V ⟶ U
t : (forget A).obj (F.obj (op V))
ht : (f.app (op V)) t = (G.map i.op) s
j : W ⟶ V
⊢ ∃ t, (f.app (op W)) t = (G.map (j ≫ i).op) s

Next tactic:
refine' ⟨F.map j.op t, _⟩
/-- Given `f : F ⟶ G`, a morphism between presieves, and `s : G.obj (op U)`, this is the sieve
of `U` consisting of the `i : V ⟶ U` such that `s` restricted along `i` is in the image of `f`. -/
@[simps (config := .lemmasOnly)]
def imageSieve {F G : Cᵒᵖ ⥤ A} (f : F ⟶ G) {U : C} (s : G.obj (op U)) : Sieve U where
  arrows V i := ∃ t : F.obj (op V), f.app _ t = G.map i.op s
  downward_closed := by
    rintro V W i ⟨t, ht⟩ j
    refine' ⟨F.map j.op t, _⟩
    

Proof state:
case 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 : Cᵒᵖ ⥤ A
f : F ⟶ G
U : C
s : (forget A).obj (G.obj (op U))
V W : C
i : V ⟶ U
t : (forget A).obj (F.obj (op V))
ht : (f.app (op V)) t = (G.map i.op) s
j : W ⟶ V
⊢ (f.app (op W)) ((F.map j.op) t) = (G.map (j ≫ i).op) s

Next tactic:
rw [op_comp, G.map_comp, comp_apply, ← ht, elementwise_of% f.naturality]
theorem imageSieve_app {F G : Cᵒᵖ ⥤ A} (f : F ⟶ G) {U : C} (s : F.obj (op U)) :
    imageSieve f (f.app _ s) = ⊤ := by
  

Proof state:
C : Type u
inst✝² : Category.{v, u} C
J : GrothendieckTopology C
A : Type u'
inst✝¹ : Category.{v', u'} A
inst✝ : ConcreteCategory A
F G : Cᵒᵖ ⥤ A
f : F ⟶ G
U : C
s : (forget A).obj (F.obj (op U))
⊢ imageSieve f ((f.app (op U)) s) = ⊤

Next tactic:
ext V i
theorem imageSieve_app {F G : Cᵒᵖ ⥤ A} (f : F ⟶ G) {U : C} (s : F.obj (op U)) :
    imageSieve f (f.app _ s) = ⊤ := by
  ext V i
  

Proof state:
case h
C : Type u
inst✝² : Category.{v, u} C
J : GrothendieckTopology C
A : Type u'
inst✝¹ : Category.{v', u'} A
inst✝ : ConcreteCategory A
F G : Cᵒᵖ ⥤ A
f : F ⟶ G
U : C
s : (forget A).obj (F.obj (op U))
V : C
i : V ⟶ U
⊢ (imageSieve f ((f.app (op U)) s)).arrows i ↔ ⊤.arrows i

Next tactic:
simp only [Sieve.top_apply, iff_true_iff, imageSieve_apply]
theorem imageSieve_app {F G : Cᵒᵖ ⥤ A} (f : F ⟶ G) {U : C} (s : F.obj (op U)) :
    imageSieve f (f.app _ s) = ⊤ := by
  ext V i
  simp only [Sieve.top_apply, iff_true_iff, imageSieve_apply]
  

Proof state:
case h
C : Type u
inst✝² : Category.{v, u} C
J : GrothendieckTopology C
A : Type u'
inst✝¹ : Category.{v', u'} A
inst✝ : ConcreteCategory A
F G : Cᵒᵖ ⥤ A
f : F ⟶ G
U : C
s : (forget A).obj (F.obj (op U))
V : C
i : V ⟶ U
⊢ ∃ t, (f.app (op V)) t = (G.map i.op) ((f.app (op U)) s)

Next tactic:
have := elementwise_of% (f.naturality i.op)
theorem imageSieve_app {F G : Cᵒᵖ ⥤ A} (f : F ⟶ G) {U : C} (s : F.obj (op U)) :
    imageSieve f (f.app _ s) = ⊤ := by
  ext V i
  simp only [Sieve.top_apply, iff_true_iff, imageSieve_apply]
  have := elementwise_of% (f.naturality i.op)
  

Proof state:
case h
C : Type u
inst✝² : Category.{v, u} C
J : GrothendieckTopology C
A : Type u'
inst✝¹ : Category.{v', u'} A
inst✝ : ConcreteCategory A
F G : Cᵒᵖ ⥤ A
f : F ⟶ G
U : C
s : (forget A).obj (F.obj (op U))
V : C
i : V ⟶ U
this : ∀ (x : (forget A).obj (F.obj (op U))), (f.app (op V)) ((F.map i.op) x) = (G.map i.op) ((f.app (op U)) x)
⊢ ∃ t, (f.app (op V)) t = (G.map i.op) ((f.app (op U)) s)

Next tactic:
exact ⟨F.map i.op s, this s⟩
theorem isLocallySurjective_iff_imagePresheaf_sheafify_eq_top {F G : Cᵒᵖ ⥤ A} (f : F ⟶ G) :
    IsLocallySurjective J f ↔ (imagePresheaf (whiskerRight f (forget A))).sheafify J = ⊤ := by
  

Proof state:
C : Type u
inst✝² : Category.{v, u} C
J : GrothendieckTopology C
A : Type u'
inst✝¹ : Category.{v', u'} A
inst✝ : ConcreteCategory A
F G : Cᵒᵖ ⥤ A
f : F ⟶ G
⊢ IsLocallySurjective J f ↔ Subpresheaf.sheafify J (imagePresheaf (whiskerRight f (forget A))) = ⊤

Next tactic:
simp only [Subpresheaf.ext_iff, Function.funext_iff, Set.ext_iff, top_subpresheaf_obj,
    Set.top_eq_univ, Set.mem_univ, iff_true_iff]
theorem isLocallySurjective_iff_imagePresheaf_sheafify_eq_top {F G : Cᵒᵖ ⥤ A} (f : F ⟶ G) :
    IsLocallySurjective J f ↔ (imagePresheaf (whiskerRight f (forget A))).sheafify J = ⊤ := by
  simp only [Subpresheaf.ext_iff, Function.funext_iff, Set.ext_iff, top_subpresheaf_obj,
    Set.top_eq_univ, Set.mem_univ, iff_true_iff]
  

Proof state:
C : Type u
inst✝² : Category.{v, u} C
J : GrothendieckTopology C
A : Type u'
inst✝¹ : Category.{v', u'} A
inst✝ : ConcreteCategory A
F G : Cᵒᵖ ⥤ A
f : F ⟶ G
⊢ IsLocallySurjective J f ↔
    ∀ (a : Cᵒᵖ) (x : (G ⋙ forget A).obj a),
      x ∈ Subpresheaf.obj (Subpresheaf.sheafify J (imagePresheaf (whiskerRight f (forget A)))) a

Next tactic:
exact ⟨fun H U => H (unop U), fun H U => H (op U)⟩
theorem isLocallySurjective_iff_imagePresheaf_sheafify_eq_top' {F G : Cᵒᵖ ⥤ Type w} (f : F ⟶ G) :
    IsLocallySurjective J f ↔ (imagePresheaf f).sheafify J = ⊤ := by
  

Proof state:
C : Type u
inst✝² : Category.{v, u} C
J : GrothendieckTopology C
A : Type u'
inst✝¹ : Category.{v', u'} A
inst✝ : ConcreteCategory A
F G : Cᵒᵖ ⥤ Type w
f : F ⟶ G
⊢ IsLocallySurjective J f ↔ Subpresheaf.sheafify J (imagePresheaf f) = ⊤

Next tactic:
simp only [Subpresheaf.ext_iff, Function.funext_iff, Set.ext_iff, top_subpresheaf_obj,
    Set.top_eq_univ, Set.mem_univ, iff_true_iff]
theorem isLocallySurjective_iff_imagePresheaf_sheafify_eq_top' {F G : Cᵒᵖ ⥤ Type w} (f : F ⟶ G) :
    IsLocallySurjective J f ↔ (imagePresheaf f).sheafify J = ⊤ := by
  simp only [Subpresheaf.ext_iff, Function.funext_iff, Set.ext_iff, top_subpresheaf_obj,
    Set.top_eq_univ, Set.mem_univ, iff_true_iff]
  

Proof state:
C : Type u
inst✝² : Category.{v, u} C
J : GrothendieckTopology C
A : Type u'
inst✝¹ : Category.{v', u'} A
inst✝ : ConcreteCategory A
F G : Cᵒᵖ ⥤ Type w
f : F ⟶ G
⊢ IsLocallySurjective J f ↔ ∀ (a : Cᵒᵖ) (x : G.obj a), x ∈ Subpresheaf.obj (Subpresheaf.sheafify J (imagePresheaf f)) a

Next tactic:
exact ⟨fun H U => H (unop U), fun H U => H (op U)⟩
theorem isLocallySurjective_iff_isIso {F G : Sheaf J (Type w)} (f : F ⟶ G) :
    IsLocallySurjective J f.1 ↔ IsIso (imageSheafι f) := by
  

Proof state:
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
⊢ IsLocallySurjective J f.val ↔ IsIso (imageSheafι f)

Next tactic:
rw [imageSheafι, isLocallySurjective_iff_imagePresheaf_sheafify_eq_top',
    Subpresheaf.eq_top_iff_isIso]
theorem isLocallySurjective_iff_isIso {F G : Sheaf J (Type w)} (f : F ⟶ G) :
    IsLocallySurjective J f.1 ↔ IsIso (imageSheafι f) := by
  rw [imageSheafι, isLocallySurjective_iff_imagePresheaf_sheafify_eq_top',
    Subpresheaf.eq_top_iff_isIso]
  

Proof state:
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 (Subpresheaf.ι (Subpresheaf.sheafify J (imagePresheaf f.val))) ↔
    IsIso { val := Subpresheaf.ι (Subpresheaf.sheafify J (imagePresheaf f.val)) }

Next tactic:
exact
    ⟨fun h => @isIso_of_reflects_iso _ _ _ _ _ _ (imageSheafι f) (sheafToPresheaf J _) h _, fun h =>
      @Functor.map_isIso _ _ _ _ _ _ (sheafToPresheaf J _) _ h⟩
theorem isLocallySurjective_iff_whisker_forget {F G : Cᵒᵖ ⥤ A} (f : F ⟶ G) :
    IsLocallySurjective J f ↔ IsLocallySurjective J (whiskerRight f (forget A)) := by
  

Proof state:
C : Type u
inst✝² : Category.{v, u} C
J : GrothendieckTopology C
A : Type u'
inst✝¹ : Category.{v', u'} A
inst✝ : ConcreteCategory A
F G : Cᵒᵖ ⥤ A
f : F ⟶ G
⊢ IsLocallySurjective J f ↔ IsLocallySurjective J (whiskerRight f (forget A))

Next tactic:
simp only [isLocallySurjective_iff_imagePresheaf_sheafify_eq_top]
theorem isLocallySurjective_iff_whisker_forget {F G : Cᵒᵖ ⥤ A} (f : F ⟶ G) :
    IsLocallySurjective J f ↔ IsLocallySurjective J (whiskerRight f (forget A)) := by
  simp only [isLocallySurjective_iff_imagePresheaf_sheafify_eq_top]
  

Proof state:
C : Type u
inst✝² : Category.{v, u} C
J : GrothendieckTopology C
A : Type u'
inst✝¹ : Category.{v', u'} A
inst✝ : ConcreteCategory A
F G : Cᵒᵖ ⥤ A
f : F ⟶ G
⊢ Subpresheaf.sheafify J (imagePresheaf (whiskerRight f (forget A))) = ⊤ ↔
    Subpresheaf.sheafify J (imagePresheaf (whiskerRight (whiskerRight f (forget A)) (forget (Type w')))) = ⊤

Next tactic:
rfl
theorem isLocallySurjective_of_surjective {F G : Cᵒᵖ ⥤ A} (f : F ⟶ G)
    (H : ∀ U, Function.Surjective (f.app U)) : IsLocallySurjective J f := by
  

Proof state:
C : Type u
inst✝² : Category.{v, u} C
J : GrothendieckTopology C
A : Type u'
inst✝¹ : Category.{v', u'} A
inst✝ : ConcreteCategory A
F G : Cᵒᵖ ⥤ A
f : F ⟶ G
H : ∀ (U : Cᵒᵖ), Function.Surjective ⇑(f.app U)
⊢ IsLocallySurjective J f

Next tactic:
intro U s
theorem isLocallySurjective_of_surjective {F G : Cᵒᵖ ⥤ A} (f : F ⟶ G)
    (H : ∀ U, Function.Surjective (f.app U)) : IsLocallySurjective J f := by
  intro U s
  

Proof state:
C : Type u
inst✝² : Category.{v, u} C
J : GrothendieckTopology C
A : Type u'
inst✝¹ : Category.{v', u'} A
inst✝ : ConcreteCategory A
F G : Cᵒᵖ ⥤ A
f : F ⟶ G
H : ∀ (U : Cᵒᵖ), Function.Surjective ⇑(f.app U)
U : C
s : (forget A).obj (G.obj (op U))
⊢ imageSieve f s ∈ sieves J U

Next tactic:
obtain ⟨t, rfl⟩ := H _ s
theorem isLocallySurjective_of_surjective {F G : Cᵒᵖ ⥤ A} (f : F ⟶ G)
    (H : ∀ U, Function.Surjective (f.app U)) : IsLocallySurjective J f := by
  intro U s
  obtain ⟨t, rfl⟩ := H _ s
  

Proof state:
case 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 : Cᵒᵖ ⥤ A
f : F ⟶ G
H : ∀ (U : Cᵒᵖ), Function.Surjective ⇑(f.app U)
U : C
t : (forget A).obj (F.obj (op U))
⊢ imageSieve f ((f.app (op U)) t) ∈ sieves J U

Next tactic:
rw [imageSieve_app]
theorem isLocallySurjective_of_surjective {F G : Cᵒᵖ ⥤ A} (f : F ⟶ G)
    (H : ∀ U, Function.Surjective (f.app U)) : IsLocallySurjective J f := by
  intro U s
  obtain ⟨t, rfl⟩ := H _ s
  rw [imageSieve_app]
  

Proof state:
case 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 : Cᵒᵖ ⥤ A
f : F ⟶ G
H : ∀ (U : Cᵒᵖ), Function.Surjective ⇑(f.app U)
U : C
t : (forget A).obj (F.obj (op U))
⊢ ⊤ ∈ sieves J U

Next tactic:
exact J.top_mem _
theorem isLocallySurjective_of_iso {F G : Cᵒᵖ ⥤ A} (f : F ⟶ G) [IsIso f] :
    IsLocallySurjective J f := by
  

Proof state:
C : Type u
inst✝³ : Category.{v, u} C
J : GrothendieckTopology C
A : Type u'
inst✝² : Category.{v', u'} A
inst✝¹ : ConcreteCategory A
F G : Cᵒᵖ ⥤ A
f : F ⟶ G
inst✝ : IsIso f
⊢ IsLocallySurjective J f

Next tactic:
apply isLocallySurjective_of_surjective
theorem isLocallySurjective_of_iso {F G : Cᵒᵖ ⥤ A} (f : F ⟶ G) [IsIso f] :
    IsLocallySurjective J f := by
  apply isLocallySurjective_of_surjective
  

Proof state:
case H
C : Type u
inst✝³ : Category.{v, u} C
J : GrothendieckTopology C
A : Type u'
inst✝² : Category.{v', u'} A
inst✝¹ : ConcreteCategory A
F G : Cᵒᵖ ⥤ A
f : F ⟶ G
inst✝ : IsIso f
⊢ ∀ (U : Cᵒᵖ), Function.Surjective ⇑(f.app U)

Next tactic:
intro U
theorem isLocallySurjective_of_iso {F G : Cᵒᵖ ⥤ A} (f : F ⟶ G) [IsIso f] :
    IsLocallySurjective J f := by
  apply isLocallySurjective_of_surjective
  intro U
  

Proof state:
case H
C : Type u
inst✝³ : Category.{v, u} C
J : GrothendieckTopology C
A : Type u'
inst✝² : Category.{v', u'} A
inst✝¹ : ConcreteCategory A
F G : Cᵒᵖ ⥤ A
f : F ⟶ G
inst✝ : IsIso f
U : Cᵒᵖ
⊢ Function.Surjective ⇑(f.app U)

Next tactic:
apply Function.Bijective.surjective
theorem isLocallySurjective_of_iso {F G : Cᵒᵖ ⥤ A} (f : F ⟶ G) [IsIso f] :
    IsLocallySurjective J f := by
  apply isLocallySurjective_of_surjective
  intro U
  apply Function.Bijective.surjective
  

Proof state:
case H.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 : Cᵒᵖ ⥤ A
f : F ⟶ G
inst✝ : IsIso f
U : Cᵒᵖ
⊢ Function.Bijective ⇑(f.app U)

Next tactic:
rw [← isIso_iff_bijective, ← forget_map_eq_coe]
theorem isLocallySurjective_of_iso {F G : Cᵒᵖ ⥤ A} (f : F ⟶ G) [IsIso f] :
    IsLocallySurjective J f := by
  apply isLocallySurjective_of_surjective
  intro U
  apply Function.Bijective.surjective
  rw [← isIso_iff_bijective, ← forget_map_eq_coe]
  

Proof state:
case H.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 : Cᵒᵖ ⥤ A
f : F ⟶ G
inst✝ : IsIso f
U : Cᵒᵖ
⊢ IsIso ((forget A).map (f.app U))

Next tactic:
infer_instance
theorem IsLocallySurjective.comp {F₁ F₂ F₃ : Cᵒᵖ ⥤ A} {f₁ : F₁ ⟶ F₂} {f₂ : F₂ ⟶ F₃}
    (h₁ : IsLocallySurjective J f₁) (h₂ : IsLocallySurjective J f₂) :
    IsLocallySurjective J (f₁ ≫ f₂) := by
  

Proof state:
C : Type u
inst✝² : Category.{v, u} C
J : GrothendieckTopology C
A : Type u'
inst✝¹ : Category.{v', u'} A
inst✝ : ConcreteCategory A
F₁ F₂ F₃ : Cᵒᵖ ⥤ A
f₁ : F₁ ⟶ F₂
f₂ : F₂ ⟶ F₃
h₁ : IsLocallySurjective J f₁
h₂ : IsLocallySurjective J f₂
⊢ IsLocallySurjective J (f₁ ≫ f₂)

Next tactic:
intro U s
theorem IsLocallySurjective.comp {F₁ F₂ F₃ : Cᵒᵖ ⥤ A} {f₁ : F₁ ⟶ F₂} {f₂ : F₂ ⟶ F₃}
    (h₁ : IsLocallySurjective J f₁) (h₂ : IsLocallySurjective J f₂) :
    IsLocallySurjective J (f₁ ≫ f₂) := by
  intro U s
  

Proof state:
C : Type u
inst✝² : Category.{v, u} C
J : GrothendieckTopology C
A : Type u'
inst✝¹ : Category.{v', u'} A
inst✝ : ConcreteCategory A
F₁ F₂ F₃ : Cᵒᵖ ⥤ A
f₁ : F₁ ⟶ F₂
f₂ : F₂ ⟶ F₃
h₁ : IsLocallySurjective J f₁
h₂ : IsLocallySurjective J f₂
U : C
s : (forget A).obj (F₃.obj (op U))
⊢ imageSieve (f₁ ≫ f₂) s ∈ sieves J U

Next tactic:
have : (Sieve.bind (imageSieve f₂ s) fun _ _ h => imageSieve f₁ h.choose) ≤
      imageSieve (f₁ ≫ f₂) s := by
    rintro V i ⟨W, i, j, H, ⟨t', ht'⟩, rfl⟩
    refine' ⟨t', _⟩
    rw [op_comp, F₃.map_comp, NatTrans.comp_app, comp_apply, comp_apply, ht',
      elementwise_of% f₂.naturality, H.choose_spec]
theorem IsLocallySurjective.comp {F₁ F₂ F₃ : Cᵒᵖ ⥤ A} {f₁ : F₁ ⟶ F₂} {f₂ : F₂ ⟶ F₃}
    (h₁ : IsLocallySurjective J f₁) (h₂ : IsLocallySurjective J f₂) :
    IsLocallySurjective J (f₁ ≫ f₂) := by
  intro U s
  have : (Sieve.bind (imageSieve f₂ s) fun _ _ h => imageSieve f₁ h.choose) ≤
      imageSieve (f₁ ≫ f₂) s := by
    

Proof state:
C : Type u
inst✝² : Category.{v, u} C
J : GrothendieckTopology C
A : Type u'
inst✝¹ : Category.{v', u'} A
inst✝ : ConcreteCategory A
F₁ F₂ F₃ : Cᵒᵖ ⥤ A
f₁ : F₁ ⟶ F₂
f₂ : F₂ ⟶ F₃
h₁ : IsLocallySurjective J f₁
h₂ : IsLocallySurjective J f₂
U : C
s : (forget A).obj (F₃.obj (op U))
⊢ (Sieve.bind (imageSieve f₂ s).arrows fun x x_1 h => imageSieve f₁ (Exists.choose h)) ≤ imageSieve (f₁ ≫ f₂) s

Next tactic:
rintro V i ⟨W, i, j, H, ⟨t', ht'⟩, rfl⟩
theorem IsLocallySurjective.comp {F₁ F₂ F₃ : Cᵒᵖ ⥤ A} {f₁ : F₁ ⟶ F₂} {f₂ : F₂ ⟶ F₃}
    (h₁ : IsLocallySurjective J f₁) (h₂ : IsLocallySurjective J f₂) :
    IsLocallySurjective J (f₁ ≫ f₂) := by
  intro U s
  have : (Sieve.bind (imageSieve f₂ s) fun _ _ h => imageSieve f₁ h.choose) ≤
      imageSieve (f₁ ≫ f₂) s := by
    rintro V i ⟨W, i, j, H, ⟨t', ht'⟩, rfl⟩
    

Proof state:
case intro.intro.intro.intro.intro.intro
C : Type u
inst✝² : Category.{v, u} C
J : GrothendieckTopology C
A : Type u'
inst✝¹ : Category.{v', u'} A
inst✝ : ConcreteCategory A
F₁ F₂ F₃ : Cᵒᵖ ⥤ A
f₁ : F₁ ⟶ F₂
f₂ : F₂ ⟶ F₃
h₁ : IsLocallySurjective J f₁
h₂ : IsLocallySurjective J f₂
U : C
s : (forget A).obj (F₃.obj (op U))
V W : C
i : V ⟶ W
j : W ⟶ U
H : (imageSieve f₂ s).arrows j
t' : (forget A).obj (F₁.obj (op V))
ht' : (f₁.app (op V)) t' = (F₂.map i.op) (Exists.choose H)
⊢ (imageSieve (f₁ ≫ f₂) s).arrows (i ≫ j)

Next tactic:
refine' ⟨t', _⟩
theorem IsLocallySurjective.comp {F₁ F₂ F₃ : Cᵒᵖ ⥤ A} {f₁ : F₁ ⟶ F₂} {f₂ : F₂ ⟶ F₃}
    (h₁ : IsLocallySurjective J f₁) (h₂ : IsLocallySurjective J f₂) :
    IsLocallySurjective J (f₁ ≫ f₂) := by
  intro U s
  have : (Sieve.bind (imageSieve f₂ s) fun _ _ h => imageSieve f₁ h.choose) ≤
      imageSieve (f₁ ≫ f₂) s := by
    rintro V i ⟨W, i, j, H, ⟨t', ht'⟩, rfl⟩
    refine' ⟨t', _⟩
    

Proof state:
case intro.intro.intro.intro.intro.intro
C : Type u
inst✝² : Category.{v, u} C
J : GrothendieckTopology C
A : Type u'
inst✝¹ : Category.{v', u'} A
inst✝ : ConcreteCategory A
F₁ F₂ F₃ : Cᵒᵖ ⥤ A
f₁ : F₁ ⟶ F₂
f₂ : F₂ ⟶ F₃
h₁ : IsLocallySurjective J f₁
h₂ : IsLocallySurjective J f₂
U : C
s : (forget A).obj (F₃.obj (op U))
V W : C
i : V ⟶ W
j : W ⟶ U
H : (imageSieve f₂ s).arrows j
t' : (forget A).obj (F₁.obj (op V))
ht' : (f₁.app (op V)) t' = (F₂.map i.op) (Exists.choose H)
⊢ ((f₁ ≫ f₂).app (op V)) t' = (F₃.map (i ≫ j).op) s

Next tactic:
rw [op_comp, F₃.map_comp, NatTrans.comp_app, comp_apply, comp_apply, ht',
      elementwise_of% f₂.naturality, H.choose_spec]
theorem IsLocallySurjective.comp {F₁ F₂ F₃ : Cᵒᵖ ⥤ A} {f₁ : F₁ ⟶ F₂} {f₂ : F₂ ⟶ F₃}
    (h₁ : IsLocallySurjective J f₁) (h₂ : IsLocallySurjective J f₂) :
    IsLocallySurjective J (f₁ ≫ f₂) := by
  intro U s
  have : (Sieve.bind (imageSieve f₂ s) fun _ _ h => imageSieve f₁ h.choose) ≤
      imageSieve (f₁ ≫ f₂) s := by
    rintro V i ⟨W, i, j, H, ⟨t', ht'⟩, rfl⟩
    refine' ⟨t', _⟩
    rw [op_comp, F₃.map_comp, NatTrans.comp_app, comp_apply, comp_apply, ht',
      elementwise_of% f₂.naturality, H.choose_spec]
  

Proof state:
C : Type u
inst✝² : Category.{v, u} C
J : GrothendieckTopology C
A : Type u'
inst✝¹ : Category.{v', u'} A
inst✝ : ConcreteCategory A
F₁ F₂ F₃ : Cᵒᵖ ⥤ A
f₁ : F₁ ⟶ F₂
f₂ : F₂ ⟶ F₃
h₁ : IsLocallySurjective J f₁
h₂ : IsLocallySurjective J f₂
U : C
s : (forget A).obj (F₃.obj (op U))
this : (Sieve.bind (imageSieve f₂ s).arrows fun x x_1 h => imageSieve f₁ (Exists.choose h)) ≤ imageSieve (f₁ ≫ f₂) s
⊢ imageSieve (f₁ ≫ f₂) s ∈ sieves J U

Next tactic:
apply J.superset_covering this
theorem IsLocallySurjective.comp {F₁ F₂ F₃ : Cᵒᵖ ⥤ A} {f₁ : F₁ ⟶ F₂} {f₂ : F₂ ⟶ F₃}
    (h₁ : IsLocallySurjective J f₁) (h₂ : IsLocallySurjective J f₂) :
    IsLocallySurjective J (f₁ ≫ f₂) := by
  intro U s
  have : (Sieve.bind (imageSieve f₂ s) fun _ _ h => imageSieve f₁ h.choose) ≤
      imageSieve (f₁ ≫ f₂) s := by
    rintro V i ⟨W, i, j, H, ⟨t', ht'⟩, rfl⟩
    refine' ⟨t', _⟩
    rw [op_comp, F₃.map_comp, NatTrans.comp_app, comp_apply, comp_apply, ht',
      elementwise_of% f₂.naturality, H.choose_spec]
  apply J.superset_covering this
  

Proof state:
C : Type u
inst✝² : Category.{v, u} C
J : GrothendieckTopology C
A : Type u'
inst✝¹ : Category.{v', u'} A
inst✝ : ConcreteCategory A
F₁ F₂ F₃ : Cᵒᵖ ⥤ A
f₁ : F₁ ⟶ F₂
f₂ : F₂ ⟶ F₃
h₁ : IsLocallySurjective J f₁
h₂ : IsLocallySurjective J f₂
U : C
s : (forget A).obj (F₃.obj (op U))
this : (Sieve.bind (imageSieve f₂ s).arrows fun x x_1 h => imageSieve f₁ (Exists.choose h)) ≤ imageSieve (f₁ ≫ f₂) s
⊢ (Sieve.bind (imageSieve f₂ s).arrows fun x x_1 h => imageSieve f₁ (Exists.choose h)) ∈ sieves J U

Next tactic:
apply J.bind_covering
theorem IsLocallySurjective.comp {F₁ F₂ F₃ : Cᵒᵖ ⥤ A} {f₁ : F₁ ⟶ F₂} {f₂ : F₂ ⟶ F₃}
    (h₁ : IsLocallySurjective J f₁) (h₂ : IsLocallySurjective J f₂) :
    IsLocallySurjective J (f₁ ≫ f₂) := by
  intro U s
  have : (Sieve.bind (imageSieve f₂ s) fun _ _ h => imageSieve f₁ h.choose) ≤
      imageSieve (f₁ ≫ f₂) s := by
    rintro V i ⟨W, i, j, H, ⟨t', ht'⟩, rfl⟩
    refine' ⟨t', _⟩
    rw [op_comp, F₃.map_comp, NatTrans.comp_app, comp_apply, comp_apply, ht',
      elementwise_of% f₂.naturality, H.choose_spec]
  apply J.superset_covering this
  apply J.bind_covering
  · 

Proof state:
case hS
C : Type u
inst✝² : Category.{v, u} C
J : GrothendieckTopology C
A : Type u'
inst✝¹ : Category.{v', u'} A
inst✝ : ConcreteCategory A
F₁ F₂ F₃ : Cᵒᵖ ⥤ A
f₁ : F₁ ⟶ F₂
f₂ : F₂ ⟶ F₃
h₁ : IsLocallySurjective J f₁
h₂ : IsLocallySurjective J f₂
U : C
s : (forget A).obj (F₃.obj (op U))
this : (Sieve.bind (imageSieve f₂ s).arrows fun x x_1 h => imageSieve f₁ (Exists.choose h)) ≤ imageSieve (f₁ ≫ f₂) s
⊢ imageSieve f₂ s ∈ sieves J U

Next tactic:
apply h₂