l3lab/ntp-mathlib huggingface dataset:
theorem Finsupp.mul_sum (b : S) (s : α →₀ R) {f : α → R → S} :
    b * s.sum f = s.sum fun a c => b * f a c := by 

Proof state:
α : Type u_1
ι : Type u_2
γ : Type u_3
A : Type u_4
B : Type u_5
C : Type u_6
inst✝⁴ : AddCommMonoid A
inst✝³ : AddCommMonoid B
inst✝² : AddCommMonoid C
t : ι → A → C
h0 : ∀ (i : ι), t i 0 = 0
h1 : ∀ (i : ι) (x y : A), t i (x + y) = t i x + t i y
s✝ : Finset α
f✝ : α → ι →₀ A
i : ι
g : ι →₀ A
k : ι → A → γ → B
x : γ
β : Type u_7
M : Type u_8
M' : Type u_9
N : Type u_10
P : Type u_11
G : Type u_12
H : Type u_13
R : Type u_14
S : Type u_15
inst✝¹ : NonUnitalNonAssocSemiring R
inst✝ : NonUnitalNonAssocSemiring S
b : S
s : α →₀ R
f : α → R → S
⊢ b * sum s f = sum s fun a c => b * f a c

Next tactic:
simp only [Finsupp.sum, Finset.mul_sum]
/-- If `0 : ℕ` is not in the support of `f : ℕ →₀ ℕ` then `0 < ∏ x in f.support, x ^ (f x)`. -/
theorem prod_pow_pos_of_zero_not_mem_support {f : ℕ →₀ ℕ} (hf : 0 ∉ f.support) :
    0 < f.prod (· ^ ·) :=
 Finset.prod_pos fun a ha => pos_iff_ne_zero.mpr (pow_ne_zero _ fun H => by 

Proof state:
α : Type u_1
ι : Type u_2
γ : Type u_3
A : Type u_4
B : Type u_5
C : Type u_6
inst✝² : AddCommMonoid A
inst✝¹ : AddCommMonoid B
inst✝ : AddCommMonoid C
t : ι → A → C
h0 : ∀ (i : ι), t i 0 = 0
h1 : ∀ (i : ι) (x y : A), t i (x + y) = t i x + t i y
s : Finset α
f✝ : α → ι →₀ A
i : ι
g : ι →₀ A
k : ι → A → γ → B
x : γ
β : Type u_7
M : Type u_8
M' : Type u_9
N : Type u_10
P : Type u_11
G : Type u_12
H✝ : Type u_13
R : Type u_14
S : Type u_15
f : ℕ →₀ ℕ
hf : 0 ∉ f.support
a : ℕ
ha : a ∈ f.support
H : a = 0
⊢ False

Next tactic:
subst H
/-- If `0 : ℕ` is not in the support of `f : ℕ →₀ ℕ` then `0 < ∏ x in f.support, x ^ (f x)`. -/
theorem prod_pow_pos_of_zero_not_mem_support {f : ℕ →₀ ℕ} (hf : 0 ∉ f.support) :
    0 < f.prod (· ^ ·) :=
 Finset.prod_pos fun a ha => pos_iff_ne_zero.mpr (pow_ne_zero _ fun H => by subst H; 

Proof state:
α : Type u_1
ι : Type u_2
γ : Type u_3
A : Type u_4
B : Type u_5
C : Type u_6
inst✝² : AddCommMonoid A
inst✝¹ : AddCommMonoid B
inst✝ : AddCommMonoid C
t : ι → A → C
h0 : ∀ (i : ι), t i 0 = 0
h1 : ∀ (i : ι) (x y : A), t i (x + y) = t i x + t i y
s : Finset α
f✝ : α → ι →₀ A
i : ι
g : ι →₀ A
k : ι → A → γ → B
x : γ
β : Type u_7
M : Type u_8
M' : Type u_9
N : Type u_10
P : Type u_11
G : Type u_12
H : Type u_13
R : Type u_14
S : Type u_15
f : ℕ →₀ ℕ
hf : 0 ∉ f.support
ha : 0 ∈ f.support
⊢ False

Next tactic:
exact hf ha
/-- For a functor `G : C ⥤ D`, and an object `U : D`, `Sieve.coverByImage G U` is the sieve of `U`
consisting of those arrows that factor through images of `G`.
-/
def Sieve.coverByImage (G : C ⥤ D) (U : D) : Sieve U :=
  ⟨Presieve.coverByImage G U, fun ⟨⟨Z, f₁, f₂, (e : _ = _)⟩⟩ g =>
    ⟨⟨Z, g ≫ f₁, f₂, show (g ≫ f₁) ≫ f₂ = g ≫ _ by 

Proof state:
C : Type u_1
inst✝² : Category.{?u.2503, u_1} C
D : Type u_2
inst✝¹ : Category.{?u.2510, u_2} D
E : Type u_3
inst✝ : Category.{?u.2517, u_3} E
J : GrothendieckTopology C
K : GrothendieckTopology D
L : GrothendieckTopology E
G : C ⥤ D
U Y✝ Z✝ : D
f✝ : Y✝ ⟶ U
x✝ : Presieve.coverByImage G U f✝
g : Z✝ ⟶ Y✝
Z : C
f₁ : Y✝ ⟶ G.obj Z
f₂ : G.obj Z ⟶ U
e : f₁ ≫ f₂ = f✝
⊢ (g ≫ f₁) ≫ f₂ = g ≫ f✝

Next tactic:
rw [Category.assoc, ← e]
theorem Presieve.in_coverByImage (G : C ⥤ D) {X : D} {Y : C} (f : G.obj Y ⟶ X) :
    Presieve.coverByImage G X f :=
  ⟨⟨Y, 𝟙 _, f, by 

Proof state:
C : Type u_1
inst✝² : Category.{u_4, u_1} C
D : Type u_2
inst✝¹ : Category.{u_5, u_2} D
E : Type u_3
inst✝ : Category.{?u.4286, u_3} E
J : GrothendieckTopology C
K : GrothendieckTopology D
L : GrothendieckTopology E
G : C ⥤ D
X : D
Y : C
f : G.obj Y ⟶ X
⊢ 𝟙 (G.obj Y) ≫ f = f

Next tactic:
simp
lemma Functor.is_cover_of_isCoverDense (G : C ⥤ D) (K : GrothendieckTopology D)
    [G.IsCoverDense K] (U : D) : Sieve.coverByImage G U ∈ K U := by
  

Proof state:
C : Type u_1
inst✝³ : Category.{u_4, u_1} C
D : Type u_2
inst✝² : Category.{u_5, u_2} D
E : Type u_3
inst✝¹ : Category.{?u.5273, u_3} E
J : GrothendieckTopology C
K✝ : GrothendieckTopology D
L : GrothendieckTopology E
G : C ⥤ D
K : GrothendieckTopology D
inst✝ : IsCoverDense G K
U : D
⊢ Sieve.coverByImage G U ∈ GrothendieckTopology.sieves K U

Next tactic:
apply Functor.IsCoverDense.is_cover
theorem ext (ℱ : SheafOfTypes K) (X : D) {s t : ℱ.val.obj (op X)}
    (h : ∀ ⦃Y : C⦄ (f : G.obj Y ⟶ X), ℱ.val.map f.op s = ℱ.val.map f.op t) : s = t := by
  

Proof state:
C : Type u_1
inst✝⁴ : Category.{u_7, u_1} C
D : Type u_2
inst✝³ : Category.{u_6, u_2} D
E : Type u_3
inst✝² : Category.{?u.5805, u_3} E
J : GrothendieckTopology C
K : GrothendieckTopology D
L : GrothendieckTopology E
A : Type u_4
inst✝¹ : Category.{?u.5857, u_4} A
G : C ⥤ D
inst✝ : IsCoverDense G K
ℱ : SheafOfTypes K
X : D
s t : ℱ.val.obj (op X)
h : ∀ ⦃Y : C⦄ (f : G.obj Y ⟶ X), ℱ.val.map f.op s = ℱ.val.map f.op t
⊢ s = t

Next tactic:
apply (ℱ.cond (Sieve.coverByImage G X) (G.is_cover_of_isCoverDense K X)).isSeparatedFor.ext
theorem ext (ℱ : SheafOfTypes K) (X : D) {s t : ℱ.val.obj (op X)}
    (h : ∀ ⦃Y : C⦄ (f : G.obj Y ⟶ X), ℱ.val.map f.op s = ℱ.val.map f.op t) : s = t := by
  apply (ℱ.cond (Sieve.coverByImage G X) (G.is_cover_of_isCoverDense K X)).isSeparatedFor.ext
  

Proof state:
C : Type u_1
inst✝⁴ : Category.{u_7, u_1} C
D : Type u_2
inst✝³ : Category.{u_6, u_2} D
E : Type u_3
inst✝² : Category.{?u.5805, u_3} E
J : GrothendieckTopology C
K : GrothendieckTopology D
L : GrothendieckTopology E
A : Type u_4
inst✝¹ : Category.{?u.5857, u_4} A
G : C ⥤ D
inst✝ : IsCoverDense G K
ℱ : SheafOfTypes K
X : D
s t : ℱ.val.obj (op X)
h : ∀ ⦃Y : C⦄ (f : G.obj Y ⟶ X), ℱ.val.map f.op s = ℱ.val.map f.op t
⊢ ∀ ⦃Y : D⦄ ⦃f : Y ⟶ X⦄, (Sieve.coverByImage G X).arrows f → ℱ.val.map f.op s = ℱ.val.map f.op t

Next tactic:
rintro Y _ ⟨Z, f₁, f₂, ⟨rfl⟩⟩
theorem ext (ℱ : SheafOfTypes K) (X : D) {s t : ℱ.val.obj (op X)}
    (h : ∀ ⦃Y : C⦄ (f : G.obj Y ⟶ X), ℱ.val.map f.op s = ℱ.val.map f.op t) : s = t := by
  apply (ℱ.cond (Sieve.coverByImage G X) (G.is_cover_of_isCoverDense K X)).isSeparatedFor.ext
  rintro Y _ ⟨Z, f₁, f₂, ⟨rfl⟩⟩
  

Proof state:
case intro.mk.refl
C : Type u_1
inst✝⁴ : Category.{u_7, u_1} C
D : Type u_2
inst✝³ : Category.{u_6, u_2} D
E : Type u_3
inst✝² : Category.{?u.5805, u_3} E
J : GrothendieckTopology C
K : GrothendieckTopology D
L : GrothendieckTopology E
A : Type u_4
inst✝¹ : Category.{?u.5857, u_4} A
G : C ⥤ D
inst✝ : IsCoverDense G K
ℱ : SheafOfTypes K
X : D
s t : ℱ.val.obj (op X)
h : ∀ ⦃Y : C⦄ (f : G.obj Y ⟶ X), ℱ.val.map f.op s = ℱ.val.map f.op t
Y : D
Z : C
f₁ : Y ⟶ G.obj Z
f₂ : G.obj Z ⟶ X
⊢ ℱ.val.map (f₁ ≫ f₂).op s = ℱ.val.map (f₁ ≫ f₂).op t

Next tactic:
simp [h f₂]
theorem functorPullback_pushforward_covering [Full G] {X : C}
    (T : K (G.obj X)) : (T.val.functorPullback G).functorPushforward G ∈ K (G.obj X) := by
  

Proof state:
C : Type u_1
inst✝⁵ : Category.{u_5, u_1} C
D : Type u_2
inst✝⁴ : Category.{u_6, u_2} D
E : Type u_3
inst✝³ : Category.{?u.7689, u_3} E
J : GrothendieckTopology C
K : GrothendieckTopology D
L : GrothendieckTopology E
A : Type u_4
inst✝² : Category.{?u.7741, u_4} A
G : C ⥤ D
inst✝¹ : IsCoverDense G K
inst✝ : Full G
X : C
T : ↑(GrothendieckTopology.sieves K (G.obj X))
⊢ Sieve.functorPushforward G (Sieve.functorPullback G ↑T) ∈ GrothendieckTopology.sieves K (G.obj X)

Next tactic:
refine' K.superset_covering _ (K.bind_covering T.property
    fun Y f _ => G.is_cover_of_isCoverDense K Y)
theorem functorPullback_pushforward_covering [Full G] {X : C}
    (T : K (G.obj X)) : (T.val.functorPullback G).functorPushforward G ∈ K (G.obj X) := by
  refine' K.superset_covering _ (K.bind_covering T.property
    fun Y f _ => G.is_cover_of_isCoverDense K Y)
  

Proof state:
C : Type u_1
inst✝⁵ : Category.{u_5, u_1} C
D : Type u_2
inst✝⁴ : Category.{u_6, u_2} D
E : Type u_3
inst✝³ : Category.{?u.7689, u_3} E
J : GrothendieckTopology C
K : GrothendieckTopology D
L : GrothendieckTopology E
A : Type u_4
inst✝² : Category.{?u.7741, u_4} A
G : C ⥤ D
inst✝¹ : IsCoverDense G K
inst✝ : Full G
X : C
T : ↑(GrothendieckTopology.sieves K (G.obj X))
⊢ (Sieve.bind (↑T).arrows fun Y f x => Sieve.coverByImage G Y) ≤ Sieve.functorPushforward G (Sieve.functorPullback G ↑T)

Next tactic:
rintro Y _ ⟨Z, _, f, hf, ⟨W, g, f', ⟨rfl⟩⟩, rfl⟩
theorem functorPullback_pushforward_covering [Full G] {X : C}
    (T : K (G.obj X)) : (T.val.functorPullback G).functorPushforward G ∈ K (G.obj X) := by
  refine' K.superset_covering _ (K.bind_covering T.property
    fun Y f _ => G.is_cover_of_isCoverDense K Y)
  rintro Y _ ⟨Z, _, f, hf, ⟨W, g, f', ⟨rfl⟩⟩, rfl⟩
  

Proof state:
case intro.intro.intro.intro.intro.intro.mk.refl
C : Type u_1
inst✝⁵ : Category.{u_5, u_1} C
D : Type u_2
inst✝⁴ : Category.{u_6, u_2} D
E : Type u_3
inst✝³ : Category.{?u.7689, u_3} E
J : GrothendieckTopology C
K : GrothendieckTopology D
L : GrothendieckTopology E
A : Type u_4
inst✝² : Category.{?u.7741, u_4} A
G : C ⥤ D
inst✝¹ : IsCoverDense G K
inst✝ : Full G
X : C
T : ↑(GrothendieckTopology.sieves K (G.obj X))
Y Z : D
f : Z ⟶ G.obj X
hf : (↑T).arrows f
W : C
g : Y ⟶ G.obj W
f' : G.obj W ⟶ Z
⊢ (Sieve.functorPushforward G (Sieve.functorPullback G ↑T)).arrows ((g ≫ f') ≫ f)

Next tactic:
use W
theorem functorPullback_pushforward_covering [Full G] {X : C}
    (T : K (G.obj X)) : (T.val.functorPullback G).functorPushforward G ∈ K (G.obj X) := by
  refine' K.superset_covering _ (K.bind_covering T.property
    fun Y f _ => G.is_cover_of_isCoverDense K Y)
  rintro Y _ ⟨Z, _, f, hf, ⟨W, g, f', ⟨rfl⟩⟩, rfl⟩
  use W; 

Proof state:
case h
C : Type u_1
inst✝⁵ : Category.{u_5, u_1} C
D : Type u_2
inst✝⁴ : Category.{u_6, u_2} D
E : Type u_3
inst✝³ : Category.{?u.7689, u_3} E
J : GrothendieckTopology C
K : GrothendieckTopology D
L : GrothendieckTopology E
A : Type u_4
inst✝² : Category.{?u.7741, u_4} A
G : C ⥤ D
inst✝¹ : IsCoverDense G K
inst✝ : Full G
X : C
T : ↑(GrothendieckTopology.sieves K (G.obj X))
Y Z : D
f : Z ⟶ G.obj X
hf : (↑T).arrows f
W : C
g : Y ⟶ G.obj W
f' : G.obj W ⟶ Z
⊢ ∃ g_1 h, (Sieve.functorPullback G ↑T).arrows g_1 ∧ (g ≫ f') ≫ f = h ≫ G.map g_1

Next tactic:
use G.preimage (f' ≫ f)
theorem functorPullback_pushforward_covering [Full G] {X : C}
    (T : K (G.obj X)) : (T.val.functorPullback G).functorPushforward G ∈ K (G.obj X) := by
  refine' K.superset_covering _ (K.bind_covering T.property
    fun Y f _ => G.is_cover_of_isCoverDense K Y)
  rintro Y _ ⟨Z, _, f, hf, ⟨W, g, f', ⟨rfl⟩⟩, rfl⟩
  use W; use G.preimage (f' ≫ f); 

Proof state:
case h
C : Type u_1
inst✝⁵ : Category.{u_5, u_1} C
D : Type u_2
inst✝⁴ : Category.{u_6, u_2} D
E : Type u_3
inst✝³ : Category.{?u.7689, u_3} E
J : GrothendieckTopology C
K : GrothendieckTopology D
L : GrothendieckTopology E
A : Type u_4
inst✝² : Category.{?u.7741, u_4} A
G : C ⥤ D
inst✝¹ : IsCoverDense G K
inst✝ : Full G
X : C
T : ↑(GrothendieckTopology.sieves K (G.obj X))
Y Z : D
f : Z ⟶ G.obj X
hf : (↑T).arrows f
W : C
g : Y ⟶ G.obj W
f' : G.obj W ⟶ Z
⊢ ∃ h, (Sieve.functorPullback G ↑T).arrows (G.preimage (f' ≫ f)) ∧ (g ≫ f') ≫ f = h ≫ G.map (G.preimage (f' ≫ f))

Next tactic:
use g
theorem functorPullback_pushforward_covering [Full G] {X : C}
    (T : K (G.obj X)) : (T.val.functorPullback G).functorPushforward G ∈ K (G.obj X) := by
  refine' K.superset_covering _ (K.bind_covering T.property
    fun Y f _ => G.is_cover_of_isCoverDense K Y)
  rintro Y _ ⟨Z, _, f, hf, ⟨W, g, f', ⟨rfl⟩⟩, rfl⟩
  use W; use G.preimage (f' ≫ f); use g
  

Proof state:
case h
C : Type u_1
inst✝⁵ : Category.{u_5, u_1} C
D : Type u_2
inst✝⁴ : Category.{u_6, u_2} D
E : Type u_3
inst✝³ : Category.{?u.7689, u_3} E
J : GrothendieckTopology C
K : GrothendieckTopology D
L : GrothendieckTopology E
A : Type u_4
inst✝² : Category.{?u.7741, u_4} A
G : C ⥤ D
inst✝¹ : IsCoverDense G K
inst✝ : Full G
X : C
T : ↑(GrothendieckTopology.sieves K (G.obj X))
Y Z : D
f : Z ⟶ G.obj X
hf : (↑T).arrows f
W : C
g : Y ⟶ G.obj W
f' : G.obj W ⟶ Z
⊢ (Sieve.functorPullback G ↑T).arrows (G.preimage (f' ≫ f)) ∧ (g ≫ f') ≫ f = g ≫ G.map (G.preimage (f' ≫ f))

Next tactic:
constructor
theorem functorPullback_pushforward_covering [Full G] {X : C}
    (T : K (G.obj X)) : (T.val.functorPullback G).functorPushforward G ∈ K (G.obj X) := by
  refine' K.superset_covering _ (K.bind_covering T.property
    fun Y f _ => G.is_cover_of_isCoverDense K Y)
  rintro Y _ ⟨Z, _, f, hf, ⟨W, g, f', ⟨rfl⟩⟩, rfl⟩
  use W; use G.preimage (f' ≫ f); use g
  constructor
  · 

Proof state:
case h.left
C : Type u_1
inst✝⁵ : Category.{u_5, u_1} C
D : Type u_2
inst✝⁴ : Category.{u_6, u_2} D
E : Type u_3
inst✝³ : Category.{?u.7689, u_3} E
J : GrothendieckTopology C
K : GrothendieckTopology D
L : GrothendieckTopology E
A : Type u_4
inst✝² : Category.{?u.7741, u_4} A
G : C ⥤ D
inst✝¹ : IsCoverDense G K
inst✝ : Full G
X : C
T : ↑(GrothendieckTopology.sieves K (G.obj X))
Y Z : D
f : Z ⟶ G.obj X
hf : (↑T).arrows f
W : C
g : Y ⟶ G.obj W
f' : G.obj W ⟶ Z
⊢ (Sieve.functorPullback G ↑T).arrows (G.preimage (f' ≫ f))

Next tactic:
simpa using T.val.downward_closed hf f'
theorem functorPullback_pushforward_covering [Full G] {X : C}
    (T : K (G.obj X)) : (T.val.functorPullback G).functorPushforward G ∈ K (G.obj X) := by
  refine' K.superset_covering _ (K.bind_covering T.property
    fun Y f _ => G.is_cover_of_isCoverDense K Y)
  rintro Y _ ⟨Z, _, f, hf, ⟨W, g, f', ⟨rfl⟩⟩, rfl⟩
  use W; use G.preimage (f' ≫ f); use g
  constructor
  · simpa using T.val.downward_closed hf f'
  · 

Proof state:
case h.right
C : Type u_1
inst✝⁵ : Category.{u_5, u_1} C
D : Type u_2
inst✝⁴ : Category.{u_6, u_2} D
E : Type u_3
inst✝³ : Category.{?u.7689, u_3} E
J : GrothendieckTopology C
K : GrothendieckTopology D
L : GrothendieckTopology E
A : Type u_4
inst✝² : Category.{?u.7741, u_4} A
G : C ⥤ D
inst✝¹ : IsCoverDense G K
inst✝ : Full G
X : C
T : ↑(GrothendieckTopology.sieves K (G.obj X))
Y Z : D
f : Z ⟶ G.obj X
hf : (↑T).arrows f
W : C
g : Y ⟶ G.obj W
f' : G.obj W ⟶ Z
⊢ (g ≫ f') ≫ f = g ≫ G.map (G.preimage (f' ≫ f))

Next tactic:
simp
/-- (Implementation). The `pushforwardFamily` defined is compatible. -/
theorem pushforwardFamily_compatible {X} (x : ℱ.obj (op X)) :
    (pushforwardFamily α x).Compatible := by
  

Proof state:
C : Type u_1
inst✝⁵ : Category.{u_6, u_1} C
D : Type u_2
inst✝⁴ : Category.{u_5, u_2} D
E : Type u_3
inst✝³ : Category.{?u.48000, u_3} E
J : GrothendieckTopology C
K : GrothendieckTopology D
L : GrothendieckTopology E
A : Type u_4
inst✝² : Category.{?u.48052, u_4} A
G : C ⥤ D
inst✝¹ : IsCoverDense G K
inst✝ : Full G
ℱ : Dᵒᵖ ⥤ Type v
ℱ' : SheafOfTypes K
α : G.op ⋙ ℱ ⟶ G.op ⋙ ℱ'.val
X : D
x : ℱ.obj (op X)
⊢ FamilyOfElements.Compatible (pushforwardFamily α x)

Next tactic:
intro Y₁ Y₂ Z g₁ g₂ f₁ f₂ h₁ h₂ e
/-- (Implementation). The `pushforwardFamily` defined is compatible. -/
theorem pushforwardFamily_compatible {X} (x : ℱ.obj (op X)) :
    (pushforwardFamily α x).Compatible := by
  intro Y₁ Y₂ Z g₁ g₂ f₁ f₂ h₁ h₂ e
  

Proof state:
C : Type u_1
inst✝⁵ : Category.{u_6, u_1} C
D : Type u_2
inst✝⁴ : Category.{u_5, u_2} D
E : Type u_3
inst✝³ : Category.{?u.48000, u_3} E
J : GrothendieckTopology C
K : GrothendieckTopology D
L : GrothendieckTopology E
A : Type u_4
inst✝² : Category.{?u.48052, u_4} A
G : C ⥤ D
inst✝¹ : IsCoverDense G K
inst✝ : Full G
ℱ : Dᵒᵖ ⥤ Type v
ℱ' : SheafOfTypes K
α : G.op ⋙ ℱ ⟶ G.op ⋙ ℱ'.val
X : D
x : ℱ.obj (op X)
Y₁ Y₂ Z : D
g₁ : Z ⟶ Y₁
g₂ : Z ⟶ Y₂
f₁ : Y₁ ⟶ X
f₂ : Y₂ ⟶ X
h₁ : coverByImage G X f₁
h₂ : coverByImage G X f₂
e : g₁ ≫ f₁ = g₂ ≫ f₂
⊢ ℱ'.val.map g₁.op (pushforwardFamily α x f₁ h₁) = ℱ'.val.map g₂.op (pushforwardFamily α x f₂ h₂)

Next tactic:
apply IsCoverDense.ext G
/-- (Implementation). The `pushforwardFamily` defined is compatible. -/
theorem pushforwardFamily_compatible {X} (x : ℱ.obj (op X)) :
    (pushforwardFamily α x).Compatible := by
  intro Y₁ Y₂ Z g₁ g₂ f₁ f₂ h₁ h₂ e
  apply IsCoverDense.ext G
  

Proof state:
case h
C : Type u_1
inst✝⁵ : Category.{u_6, u_1} C
D : Type u_2
inst✝⁴ : Category.{u_5, u_2} D
E : Type u_3
inst✝³ : Category.{?u.48000, u_3} E
J : GrothendieckTopology C
K : GrothendieckTopology D
L : GrothendieckTopology E
A : Type u_4
inst✝² : Category.{?u.48052, u_4} A
G : C ⥤ D
inst✝¹ : IsCoverDense G K
inst✝ : Full G
ℱ : Dᵒᵖ ⥤ Type v
ℱ' : SheafOfTypes K
α : G.op ⋙ ℱ ⟶ G.op ⋙ ℱ'.val
X : D
x : ℱ.obj (op X)
Y₁ Y₂ Z : D
g₁ : Z ⟶ Y₁
g₂ : Z ⟶ Y₂
f₁ : Y₁ ⟶ X
f₂ : Y₂ ⟶ X
h₁ : coverByImage G X f₁
h₂ : coverByImage G X f₂
e : g₁ ≫ f₁ = g₂ ≫ f₂
⊢ ∀ ⦃Y : C⦄ (f : G.obj Y ⟶ Z),
    ℱ'.val.map f.op (ℱ'.val.map g₁.op (pushforwardFamily α x f₁ h₁)) =
      ℱ'.val.map f.op (ℱ'.val.map g₂.op (pushforwardFamily α x f₂ h₂))

Next tactic:
intro Y f
/-- (Implementation). The `pushforwardFamily` defined is compatible. -/
theorem pushforwardFamily_compatible {X} (x : ℱ.obj (op X)) :
    (pushforwardFamily α x).Compatible := by
  intro Y₁ Y₂ Z g₁ g₂ f₁ f₂ h₁ h₂ e
  apply IsCoverDense.ext G
  intro Y f
  

Proof state:
case h
C : Type u_1
inst✝⁵ : Category.{u_6, u_1} C
D : Type u_2
inst✝⁴ : Category.{u_5, u_2} D
E : Type u_3
inst✝³ : Category.{?u.48000, u_3} E
J : GrothendieckTopology C
K : GrothendieckTopology D
L : GrothendieckTopology E
A : Type u_4
inst✝² : Category.{?u.48052, u_4} A
G : C ⥤ D
inst✝¹ : IsCoverDense G K
inst✝ : Full G
ℱ : Dᵒᵖ ⥤ Type v
ℱ' : SheafOfTypes K
α : G.op ⋙ ℱ ⟶ G.op ⋙ ℱ'.val
X : D
x : ℱ.obj (op X)
Y₁ Y₂ Z : D
g₁ : Z ⟶ Y₁
g₂ : Z ⟶ Y₂
f₁ : Y₁ ⟶ X
f₂ : Y₂ ⟶ X
h₁ : coverByImage G X f₁
h₂ : coverByImage G X f₂
e : g₁ ≫ f₁ = g₂ ≫ f₂
Y : C
f : G.obj Y ⟶ Z
⊢ ℱ'.val.map f.op (ℱ'.val.map g₁.op (pushforwardFamily α x f₁ h₁)) =
    ℱ'.val.map f.op (ℱ'.val.map g₂.op (pushforwardFamily α x f₂ h₂))

Next tactic:
simp only [pushforwardFamily, ← FunctorToTypes.map_comp_apply, ← op_comp]
/-- (Implementation). The `pushforwardFamily` defined is compatible. -/
theorem pushforwardFamily_compatible {X} (x : ℱ.obj (op X)) :
    (pushforwardFamily α x).Compatible := by
  intro Y₁ Y₂ Z g₁ g₂ f₁ f₂ h₁ h₂ e
  apply IsCoverDense.ext G
  intro Y f
  simp only [pushforwardFamily, ← FunctorToTypes.map_comp_apply, ← op_comp]
  

Proof state:
case h
C : Type u_1
inst✝⁵ : Category.{u_6, u_1} C
D : Type u_2
inst✝⁴ : Category.{u_5, u_2} D
E : Type u_3
inst✝³ : Category.{?u.48000, u_3} E
J : GrothendieckTopology C
K : GrothendieckTopology D
L : GrothendieckTopology E
A : Type u_4
inst✝² : Category.{?u.48052, u_4} A
G : C ⥤ D
inst✝¹ : IsCoverDense G K
inst✝ : Full G
ℱ : Dᵒᵖ ⥤ Type v
ℱ' : SheafOfTypes K
α : G.op ⋙ ℱ ⟶ G.op ⋙ ℱ'.val
X : D
x : ℱ.obj (op X)
Y₁ Y₂ Z : D
g₁ : Z ⟶ Y₁
g₂ : Z ⟶ Y₂
f₁ : Y₁ ⟶ X
f₂ : Y₂ ⟶ X
h₁ : coverByImage G X f₁
h₂ : coverByImage G X f₂
e : g₁ ≫ f₁ = g₂ ≫ f₂
Y : C
f : G.obj Y ⟶ Z
⊢ ℱ'.val.map (f ≫ g₁ ≫ (Nonempty.some h₁).lift).op
      (α.app (op (Nonempty.some h₁).1) (ℱ.map (Nonempty.some h₁).map.op x)) =
    ℱ'.val.map (f ≫ g₂ ≫ (Nonempty.some h₂).lift).op
      (α.app (op (Nonempty.some h₂).1) (ℱ.map (Nonempty.some h₂).map.op x))

Next tactic:
change (ℱ.map _ ≫ α.app (op _) ≫ ℱ'.val.map _) _ = (ℱ.map _ ≫ α.app (op _) ≫ ℱ'.val.map _) _
/-- (Implementation). The `pushforwardFamily` defined is compatible. -/
theorem pushforwardFamily_compatible {X} (x : ℱ.obj (op X)) :
    (pushforwardFamily α x).Compatible := by
  intro Y₁ Y₂ Z g₁ g₂ f₁ f₂ h₁ h₂ e
  apply IsCoverDense.ext G
  intro Y f
  simp only [pushforwardFamily, ← FunctorToTypes.map_comp_apply, ← op_comp]
  change (ℱ.map _ ≫ α.app (op _) ≫ ℱ'.val.map _) _ = (ℱ.map _ ≫ α.app (op _) ≫ ℱ'.val.map _) _
  

Proof state:
case h
C : Type u_1
inst✝⁵ : Category.{u_6, u_1} C
D : Type u_2
inst✝⁴ : Category.{u_5, u_2} D
E : Type u_3
inst✝³ : Category.{?u.48000, u_3} E
J : GrothendieckTopology C
K : GrothendieckTopology D
L : GrothendieckTopology E
A : Type u_4
inst✝² : Category.{?u.48052, u_4} A
G : C ⥤ D
inst✝¹ : IsCoverDense G K
inst✝ : Full G
ℱ : Dᵒᵖ ⥤ Type v
ℱ' : SheafOfTypes K
α : G.op ⋙ ℱ ⟶ G.op ⋙ ℱ'.val
X : D
x : ℱ.obj (op X)
Y₁ Y₂ Z : D
g₁ : Z ⟶ Y₁
g₂ : Z ⟶ Y₂
f₁ : Y₁ ⟶ X
f₂ : Y₂ ⟶ X
h₁ : coverByImage G X f₁
h₂ : coverByImage G X f₂
e : g₁ ≫ f₁ = g₂ ≫ f₂
Y : C
f : G.obj Y ⟶ Z
⊢ (ℱ.map (Nonempty.some h₁).map.op ≫ α.app (op (Nonempty.some h₁).1) ≫ ℱ'.val.map (f ≫ g₁ ≫ (Nonempty.some h₁).lift).op)
      x =
    (ℱ.map (Nonempty.some h₂).map.op ≫
        α.app (op (Nonempty.some h₂).1) ≫ ℱ'.val.map (f ≫ g₂ ≫ (Nonempty.some h₂).lift).op)
      x

Next tactic:
rw [← G.image_preimage (f ≫ g₁ ≫ _)]
/-- (Implementation). The `pushforwardFamily` defined is compatible. -/
theorem pushforwardFamily_compatible {X} (x : ℱ.obj (op X)) :
    (pushforwardFamily α x).Compatible := by
  intro Y₁ Y₂ Z g₁ g₂ f₁ f₂ h₁ h₂ e
  apply IsCoverDense.ext G
  intro Y f
  simp only [pushforwardFamily, ← FunctorToTypes.map_comp_apply, ← op_comp]
  change (ℱ.map _ ≫ α.app (op _) ≫ ℱ'.val.map _) _ = (ℱ.map _ ≫ α.app (op _) ≫ ℱ'.val.map _) _
  rw [← G.image_preimage (f ≫ g₁ ≫ _)]
  

Proof state:
case h
C : Type u_1
inst✝⁵ : Category.{u_6, u_1} C
D : Type u_2
inst✝⁴ : Category.{u_5, u_2} D
E : Type u_3
inst✝³ : Category.{?u.48000, u_3} E
J : GrothendieckTopology C
K : GrothendieckTopology D
L : GrothendieckTopology E
A : Type u_4
inst✝² : Category.{?u.48052, u_4} A
G : C ⥤ D
inst✝¹ : IsCoverDense G K
inst✝ : Full G
ℱ : Dᵒᵖ ⥤ Type v
ℱ' : SheafOfTypes K
α : G.op ⋙ ℱ ⟶ G.op ⋙ ℱ'.val
X : D
x : ℱ.obj (op X)
Y₁ Y₂ Z : D
g₁ : Z ⟶ Y₁
g₂ : Z ⟶ Y₂
f₁ : Y₁ ⟶ X
f₂ : Y₂ ⟶ X
h₁ : coverByImage G X f₁
h₂ : coverByImage G X f₂
e : g₁ ≫ f₁ = g₂ ≫ f₂
Y : C
f : G.obj Y ⟶ Z
⊢ (ℱ.map (Nonempty.some h₁).map.op ≫
        α.app (op (Nonempty.some h₁).1) ≫ ℱ'.val.map (G.map (G.preimage (f ≫ g₁ ≫ (Nonempty.some h₁).lift))).op)
      x =
    (ℱ.map (Nonempty.some h₂).map.op ≫
        α.app (op (Nonempty.some h₂).1) ≫ ℱ'.val.map (f ≫ g₂ ≫ (Nonempty.some h₂).lift).op)
      x

Next tactic:
rw [← G.image_preimage (f ≫ g₂ ≫ _)]
/-- (Implementation). The `pushforwardFamily` defined is compatible. -/
theorem pushforwardFamily_compatible {X} (x : ℱ.obj (op X)) :
    (pushforwardFamily α x).Compatible := by
  intro Y₁ Y₂ Z g₁ g₂ f₁ f₂ h₁ h₂ e
  apply IsCoverDense.ext G
  intro Y f
  simp only [pushforwardFamily, ← FunctorToTypes.map_comp_apply, ← op_comp]
  change (ℱ.map _ ≫ α.app (op _) ≫ ℱ'.val.map _) _ = (ℱ.map _ ≫ α.app (op _) ≫ ℱ'.val.map _) _
  rw [← G.image_preimage (f ≫ g₁ ≫ _)]
  rw [← G.image_preimage (f ≫ g₂ ≫ _)]
  

Proof state:
case h
C : Type u_1
inst✝⁵ : Category.{u_6, u_1} C
D : Type u_2
inst✝⁴ : Category.{u_5, u_2} D
E : Type u_3
inst✝³ : Category.{?u.48000, u_3} E
J : GrothendieckTopology C
K : GrothendieckTopology D
L : GrothendieckTopology E
A : Type u_4
inst✝² : Category.{?u.48052, u_4} A
G : C ⥤ D
inst✝¹ : IsCoverDense G K
inst✝ : Full G
ℱ : Dᵒᵖ ⥤ Type v
ℱ' : SheafOfTypes K
α : G.op ⋙ ℱ ⟶ G.op ⋙ ℱ'.val
X : D
x : ℱ.obj (op X)
Y₁ Y₂ Z : D
g₁ : Z ⟶ Y₁
g₂ : Z ⟶ Y₂
f₁ : Y₁ ⟶ X
f₂ : Y₂ ⟶ X
h₁ : coverByImage G X f₁
h₂ : coverByImage G X f₂
e : g₁ ≫ f₁ = g₂ ≫ f₂
Y : C
f : G.obj Y ⟶ Z
⊢ (ℱ.map (Nonempty.some h₁).map.op ≫
        α.app (op (Nonempty.some h₁).1) ≫ ℱ'.val.map (G.map (G.preimage (f ≫ g₁ ≫ (Nonempty.some h₁).lift))).op)
      x =
    (ℱ.map (Nonempty.some h₂).map.op ≫
        α.app (op (Nonempty.some h₂).1) ≫ ℱ'.val.map (G.map (G.preimage (f ≫ g₂ ≫ (Nonempty.some h₂).lift))).op)
      x

Next tactic:
erw [← α.naturality (G.preimage _).op]