l3lab/ntp-mathlib huggingface dataset:
theorem periodicOrbit_chain (r : α → α → Prop) {f : α → α} {x : α} :
    (periodicOrbit f x).Chain r ↔ ∀ n < minimalPeriod f x, r (f^[n] x) (f^[n + 1] x) := by
  by_cases hx : x ∈ periodicPts f
  · have hx' := minimalPeriod_pos_of_mem_periodicPts hx
    have hM := Nat.sub_add_cancel (succ_le_iff.2 hx')
    rw [periodicOrbit, ← Cycle.map_coe, Cycle.chain_map, ← hM, Cycle.chain_range_succ]
    refine' ⟨_, fun H => ⟨_, fun m hm => H _ (hm.trans (Nat.lt_succ_self _))⟩⟩
    · rintro ⟨hr, H⟩ n hn
      cases' eq_or_lt_of_le (lt_succ_iff.1 hn) with hM' hM'
      · rwa [hM', hM, iterate_minimalPeriod]
      · exact H _ hM'
    · rw [iterate_zero_apply]
      nth_rw 3 [← @iterate_minimalPeriod α f x]
      nth_rw 2 [← hM]
      

Proof state:
case pos.refine'_2
α : Type u_1
β : Type u_2
f✝ fa : α → α
fb : β → β
x✝ y : α
m n : ℕ
r : α → α → Prop
f : α → α
x : α
hx : x ∈ periodicPts f
hx' : 0 < minimalPeriod f x
hM : minimalPeriod f x - succ 0 + succ 0 = minimalPeriod f x
H : ∀ n < minimalPeriod f x - succ 0 + succ 0, r (f^[n] x) (f^[n + 1] x)
⊢ r (f^[minimalPeriod f x - succ 0] x) (f^[minimalPeriod f x - succ 0 + succ 0] x)

Next tactic:
exact H _ (Nat.lt_succ_self _)
theorem periodicOrbit_chain (r : α → α → Prop) {f : α → α} {x : α} :
    (periodicOrbit f x).Chain r ↔ ∀ n < minimalPeriod f x, r (f^[n] x) (f^[n + 1] x) := by
  by_cases hx : x ∈ periodicPts f
  · have hx' := minimalPeriod_pos_of_mem_periodicPts hx
    have hM := Nat.sub_add_cancel (succ_le_iff.2 hx')
    rw [periodicOrbit, ← Cycle.map_coe, Cycle.chain_map, ← hM, Cycle.chain_range_succ]
    refine' ⟨_, fun H => ⟨_, fun m hm => H _ (hm.trans (Nat.lt_succ_self _))⟩⟩
    · rintro ⟨hr, H⟩ n hn
      cases' eq_or_lt_of_le (lt_succ_iff.1 hn) with hM' hM'
      · rwa [hM', hM, iterate_minimalPeriod]
      · exact H _ hM'
    · rw [iterate_zero_apply]
      nth_rw 3 [← @iterate_minimalPeriod α f x]
      nth_rw 2 [← hM]
      exact H _ (Nat.lt_succ_self _)
  · 

Proof state:
case neg
α : Type u_1
β : Type u_2
f✝ fa : α → α
fb : β → β
x✝ y : α
m n : ℕ
r : α → α → Prop
f : α → α
x : α
hx : x ∉ periodicPts f
⊢ Cycle.Chain r (periodicOrbit f x) ↔ ∀ n < minimalPeriod f x, r (f^[n] x) (f^[n + 1] x)

Next tactic:
rw [periodicOrbit_eq_nil_of_not_periodic_pt hx, minimalPeriod_eq_zero_of_nmem_periodicPts hx]
theorem periodicOrbit_chain (r : α → α → Prop) {f : α → α} {x : α} :
    (periodicOrbit f x).Chain r ↔ ∀ n < minimalPeriod f x, r (f^[n] x) (f^[n + 1] x) := by
  by_cases hx : x ∈ periodicPts f
  · have hx' := minimalPeriod_pos_of_mem_periodicPts hx
    have hM := Nat.sub_add_cancel (succ_le_iff.2 hx')
    rw [periodicOrbit, ← Cycle.map_coe, Cycle.chain_map, ← hM, Cycle.chain_range_succ]
    refine' ⟨_, fun H => ⟨_, fun m hm => H _ (hm.trans (Nat.lt_succ_self _))⟩⟩
    · rintro ⟨hr, H⟩ n hn
      cases' eq_or_lt_of_le (lt_succ_iff.1 hn) with hM' hM'
      · rwa [hM', hM, iterate_minimalPeriod]
      · exact H _ hM'
    · rw [iterate_zero_apply]
      nth_rw 3 [← @iterate_minimalPeriod α f x]
      nth_rw 2 [← hM]
      exact H _ (Nat.lt_succ_self _)
  · rw [periodicOrbit_eq_nil_of_not_periodic_pt hx, minimalPeriod_eq_zero_of_nmem_periodicPts hx]
    

Proof state:
case neg
α : Type u_1
β : Type u_2
f✝ fa : α → α
fb : β → β
x✝ y : α
m n : ℕ
r : α → α → Prop
f : α → α
x : α
hx : x ∉ periodicPts f
⊢ Cycle.Chain r Cycle.nil ↔ ∀ n < 0, r (f^[n] x) (f^[n + 1] x)

Next tactic:
simp
theorem periodicOrbit_chain' (r : α → α → Prop) {f : α → α} {x : α} (hx : x ∈ periodicPts f) :
    (periodicOrbit f x).Chain r ↔ ∀ n, r (f^[n] x) (f^[n + 1] x) := by
  

Proof state:
α : Type u_1
β : Type u_2
f✝ fa : α → α
fb : β → β
x✝ y : α
m n : ℕ
r : α → α → Prop
f : α → α
x : α
hx : x ∈ periodicPts f
⊢ Cycle.Chain r (periodicOrbit f x) ↔ ∀ (n : ℕ), r (f^[n] x) (f^[n + 1] x)

Next tactic:
rw [periodicOrbit_chain r]
theorem periodicOrbit_chain' (r : α → α → Prop) {f : α → α} {x : α} (hx : x ∈ periodicPts f) :
    (periodicOrbit f x).Chain r ↔ ∀ n, r (f^[n] x) (f^[n + 1] x) := by
  rw [periodicOrbit_chain r]
  

Proof state:
α : Type u_1
β : Type u_2
f✝ fa : α → α
fb : β → β
x✝ y : α
m n : ℕ
r : α → α → Prop
f : α → α
x : α
hx : x ∈ periodicPts f
⊢ (∀ n < minimalPeriod f x, r (f^[n] x) (f^[n + 1] x)) ↔ ∀ (n : ℕ), r (f^[n] x) (f^[n + 1] x)

Next tactic:
refine' ⟨fun H n => _, fun H n _ => H n⟩
theorem periodicOrbit_chain' (r : α → α → Prop) {f : α → α} {x : α} (hx : x ∈ periodicPts f) :
    (periodicOrbit f x).Chain r ↔ ∀ n, r (f^[n] x) (f^[n + 1] x) := by
  rw [periodicOrbit_chain r]
  refine' ⟨fun H n => _, fun H n _ => H n⟩
  

Proof state:
α : Type u_1
β : Type u_2
f✝ fa : α → α
fb : β → β
x✝ y : α
m n✝ : ℕ
r : α → α → Prop
f : α → α
x : α
hx : x ∈ periodicPts f
H : ∀ n < minimalPeriod f x, r (f^[n] x) (f^[n + 1] x)
n : ℕ
⊢ r (f^[n] x) (f^[n + 1] x)

Next tactic:
rw [iterate_succ_apply, ← iterate_mod_minimalPeriod_eq, ← iterate_mod_minimalPeriod_eq (n := n),
    ← iterate_succ_apply, minimalPeriod_apply hx]
theorem periodicOrbit_chain' (r : α → α → Prop) {f : α → α} {x : α} (hx : x ∈ periodicPts f) :
    (periodicOrbit f x).Chain r ↔ ∀ n, r (f^[n] x) (f^[n + 1] x) := by
  rw [periodicOrbit_chain r]
  refine' ⟨fun H n => _, fun H n _ => H n⟩
  rw [iterate_succ_apply, ← iterate_mod_minimalPeriod_eq, ← iterate_mod_minimalPeriod_eq (n := n),
    ← iterate_succ_apply, minimalPeriod_apply hx]
  

Proof state:
α : Type u_1
β : Type u_2
f✝ fa : α → α
fb : β → β
x✝ y : α
m n✝ : ℕ
r : α → α → Prop
f : α → α
x : α
hx : x ∈ periodicPts f
H : ∀ n < minimalPeriod f x, r (f^[n] x) (f^[n + 1] x)
n : ℕ
⊢ r (f^[n % minimalPeriod f x] x) (f^[succ (n % minimalPeriod f x)] x)

Next tactic:
exact H _ (mod_lt _ (minimalPeriod_pos_of_mem_periodicPts hx))
@[simp]
theorem iterate_prod_map (f : α → α) (g : β → β) (n : ℕ) :
    (Prod.map f g)^[n] = Prod.map (f^[n]) (g^[n]) := by 

Proof state:
α : Type u_1
β : Type u_2
f✝ : α → α
g✝ : β → β
x : α × β
a : α
b : β
m n✝ : ℕ
f : α → α
g : β → β
n : ℕ
⊢ (Prod.map f g)^[n] = Prod.map f^[n] g^[n]

Next tactic:
induction n
@[simp]
theorem iterate_prod_map (f : α → α) (g : β → β) (n : ℕ) :
    (Prod.map f g)^[n] = Prod.map (f^[n]) (g^[n]) := by induction n <;> 

Proof state:
case zero
α : Type u_1
β : Type u_2
f✝ : α → α
g✝ : β → β
x : α × β
a : α
b : β
m n : ℕ
f : α → α
g : β → β
⊢ (Prod.map f g)^[Nat.zero] = Prod.map f^[Nat.zero] g^[Nat.zero]

Next tactic:
simp [*, Prod.map_comp_map]
@[simp]
theorem iterate_prod_map (f : α → α) (g : β → β) (n : ℕ) :
    (Prod.map f g)^[n] = Prod.map (f^[n]) (g^[n]) := by induction n <;> 

Proof state:
case succ
α : Type u_1
β : Type u_2
f✝ : α → α
g✝ : β → β
x : α × β
a : α
b : β
m n : ℕ
f : α → α
g : β → β
n✝ : ℕ
n_ih✝ : (Prod.map f g)^[n✝] = Prod.map f^[n✝] g^[n✝]
⊢ (Prod.map f g)^[Nat.succ n✝] = Prod.map f^[Nat.succ n✝] g^[Nat.succ n✝]

Next tactic:
simp [*, Prod.map_comp_map]
@[simp]
theorem isPeriodicPt_prod_map (x : α × β) :
    IsPeriodicPt (Prod.map f g) n x ↔ IsPeriodicPt f n x.1 ∧ IsPeriodicPt g n x.2 := by
  

Proof state:
α : Type u_1
β : Type u_2
f : α → α
g : β → β
x✝ : α × β
a : α
b : β
m n : ℕ
x : α × β
⊢ IsPeriodicPt (Prod.map f g) n x ↔ IsPeriodicPt f n x.1 ∧ IsPeriodicPt g n x.2

Next tactic:
simp [IsPeriodicPt]
theorem minimalPeriod_prod_map (f : α → α) (g : β → β) (x : α × β) :
    minimalPeriod (Prod.map f g) x = (minimalPeriod f x.1).lcm (minimalPeriod g x.2) :=
  eq_of_forall_dvd <| by 

Proof state:
α : Type u_1
β : Type u_2
f✝ : α → α
g✝ : β → β
x✝ : α × β
a : α
b : β
m n : ℕ
f : α → α
g : β → β
x : α × β
⊢ ∀ (c : ℕ), minimalPeriod (Prod.map f g) x ∣ c ↔ Nat.lcm (minimalPeriod f x.1) (minimalPeriod g x.2) ∣ c

Next tactic:
cases x
theorem minimalPeriod_prod_map (f : α → α) (g : β → β) (x : α × β) :
    minimalPeriod (Prod.map f g) x = (minimalPeriod f x.1).lcm (minimalPeriod g x.2) :=
  eq_of_forall_dvd <| by cases x; 

Proof state:
case mk
α : Type u_1
β : Type u_2
f✝ : α → α
g✝ : β → β
x : α × β
a : α
b : β
m n : ℕ
f : α → α
g : β → β
fst✝ : α
snd✝ : β
⊢ ∀ (c : ℕ),
    minimalPeriod (Prod.map f g) (fst✝, snd✝) ∣ c ↔
      Nat.lcm (minimalPeriod f (fst✝, snd✝).1) (minimalPeriod g (fst✝, snd✝).2) ∣ c

Next tactic:
simp [← isPeriodicPt_iff_minimalPeriod_dvd, Nat.lcm_dvd_iff]
theorem minimalPeriod_fst_dvd : minimalPeriod f x.1 ∣ minimalPeriod (Prod.map f g) x := by
  

Proof state:
α : Type u_1
β : Type u_2
f : α → α
g : β → β
x : α × β
a : α
b : β
m n : ℕ
⊢ minimalPeriod f x.1 ∣ minimalPeriod (Prod.map f g) x

Next tactic:
rw [minimalPeriod_prod_map]
theorem minimalPeriod_fst_dvd : minimalPeriod f x.1 ∣ minimalPeriod (Prod.map f g) x := by
  rw [minimalPeriod_prod_map]; 

Proof state:
α : Type u_1
β : Type u_2
f : α → α
g : β → β
x : α × β
a : α
b : β
m n : ℕ
⊢ minimalPeriod f x.1 ∣ Nat.lcm (minimalPeriod f x.1) (minimalPeriod g x.2)

Next tactic:
exact Nat.dvd_lcm_left _ _
theorem minimalPeriod_snd_dvd : minimalPeriod g x.2 ∣ minimalPeriod (Prod.map f g) x := by
  

Proof state:
α : Type u_1
β : Type u_2
f : α → α
g : β → β
x : α × β
a : α
b : β
m n : ℕ
⊢ minimalPeriod g x.2 ∣ minimalPeriod (Prod.map f g) x

Next tactic:
rw [minimalPeriod_prod_map]
theorem minimalPeriod_snd_dvd : minimalPeriod g x.2 ∣ minimalPeriod (Prod.map f g) x := by
  rw [minimalPeriod_prod_map]; 

Proof state:
α : Type u_1
β : Type u_2
f : α → α
g : β → β
x : α × β
a : α
b : β
m n : ℕ
⊢ minimalPeriod g x.2 ∣ Nat.lcm (minimalPeriod f x.1) (minimalPeriod g x.2)

Next tactic:
exact Nat.dvd_lcm_right _ _
@[to_additive]
theorem pow_smul_eq_iff_minimalPeriod_dvd {n : ℕ} :
    a ^ n • b = b ↔ Function.minimalPeriod (a • ·) b ∣ n := by
  

Proof state:
α : Type u_1
β : Type u_2
inst✝¹ : Group α
inst✝ : MulAction α β
a : α
b : β
n : ℕ
⊢ a ^ n • b = b ↔ minimalPeriod (fun x => a • x) b ∣ n

Next tactic:
rw [← isPeriodicPt_iff_minimalPeriod_dvd, IsPeriodicPt, IsFixedPt, smul_iterate]
@[to_additive]
theorem zpow_smul_eq_iff_minimalPeriod_dvd {n : ℤ} :
    a ^ n • b = b ↔ (Function.minimalPeriod (a • ·) b : ℤ) ∣ n := by
  

Proof state:
α : Type u_1
β : Type u_2
inst✝¹ : Group α
inst✝ : MulAction α β
a : α
b : β
n : ℤ
⊢ a ^ n • b = b ↔ ↑(minimalPeriod (fun x => a • x) b) ∣ n

Next tactic:
cases n
@[to_additive]
theorem zpow_smul_eq_iff_minimalPeriod_dvd {n : ℤ} :
    a ^ n • b = b ↔ (Function.minimalPeriod (a • ·) b : ℤ) ∣ n := by
  cases n
  · 

Proof state:
case ofNat
α : Type u_1
β : Type u_2
inst✝¹ : Group α
inst✝ : MulAction α β
a : α
b : β
a✝ : ℕ
⊢ a ^ Int.ofNat a✝ • b = b ↔ ↑(minimalPeriod (fun x => a • x) b) ∣ Int.ofNat a✝

Next tactic:
rw [Int.ofNat_eq_coe, zpow_ofNat, Int.coe_nat_dvd, pow_smul_eq_iff_minimalPeriod_dvd]
@[to_additive]
theorem zpow_smul_eq_iff_minimalPeriod_dvd {n : ℤ} :
    a ^ n • b = b ↔ (Function.minimalPeriod (a • ·) b : ℤ) ∣ n := by
  cases n
  · rw [Int.ofNat_eq_coe, zpow_ofNat, Int.coe_nat_dvd, pow_smul_eq_iff_minimalPeriod_dvd]
  · 

Proof state:
case negSucc
α : Type u_1
β : Type u_2
inst✝¹ : Group α
inst✝ : MulAction α β
a : α
b : β
a✝ : ℕ
⊢ a ^ Int.negSucc a✝ • b = b ↔ ↑(minimalPeriod (fun x => a • x) b) ∣ Int.negSucc a✝

Next tactic:
rw [Int.negSucc_coe, zpow_neg, zpow_ofNat, inv_smul_eq_iff, eq_comm, dvd_neg, Int.coe_nat_dvd,
      pow_smul_eq_iff_minimalPeriod_dvd]
@[to_additive (attr := simp)]
theorem pow_smul_mod_minimalPeriod (n : ℕ) :
    a ^ (n % Function.minimalPeriod (a • ·) b) • b = a ^ n • b := by
  

Proof state:
α : Type u_1
β : Type u_2
inst✝¹ : Group α
inst✝ : MulAction α β
a : α
b : β
n : ℕ
⊢ a ^ (n % minimalPeriod (fun x => a • x) b) • b = a ^ n • b

Next tactic:
conv_rhs =>
    rw [← Nat.mod_add_div n (minimalPeriod (a • ·) b), pow_add, mul_smul,
      pow_smul_eq_iff_minimalPeriod_dvd.mpr (dvd_mul_right _ _)]
@[to_additive (attr := simp)]
theorem pow_smul_mod_minimalPeriod (n : ℕ) :
    a ^ (n % Function.minimalPeriod (a • ·) b) • b = a ^ n • b := by
  conv_rhs =>
    

Proof state:
α : Type u_1
β : Type u_2
inst✝¹ : Group α
inst✝ : MulAction α β
a : α
b : β
n : ℕ
| a ^ n • b

Next tactic:
rw [← Nat.mod_add_div n (minimalPeriod (a • ·) b), pow_add, mul_smul,
      pow_smul_eq_iff_minimalPeriod_dvd.mpr (dvd_mul_right _ _)]
@[to_additive (attr := simp)]
theorem zpow_smul_mod_minimalPeriod (n : ℤ) :
    a ^ (n % (Function.minimalPeriod (a • ·) b : ℤ)) • b = a ^ n • b := by
  

Proof state:
α : Type u_1
β : Type u_2
inst✝¹ : Group α
inst✝ : MulAction α β
a : α
b : β
n : ℤ
⊢ a ^ (n % ↑(minimalPeriod (fun x => a • x) b)) • b = a ^ n • b

Next tactic:
conv_rhs =>
    rw [← Int.emod_add_ediv n (minimalPeriod ((a • ·)) b), zpow_add, mul_smul,
      zpow_smul_eq_iff_minimalPeriod_dvd.mpr (dvd_mul_right _ _)]
@[to_additive (attr := simp)]
theorem zpow_smul_mod_minimalPeriod (n : ℤ) :
    a ^ (n % (Function.minimalPeriod (a • ·) b : ℤ)) • b = a ^ n • b := by
  conv_rhs =>
    

Proof state:
α : Type u_1
β : Type u_2
inst✝¹ : Group α
inst✝ : MulAction α β
a : α
b : β
n : ℤ
| a ^ n • b

Next tactic:
rw [← Int.emod_add_ediv n (minimalPeriod ((a • ·)) b), zpow_add, mul_smul,
      zpow_smul_eq_iff_minimalPeriod_dvd.mpr (dvd_mul_right _ _)]
/-- An auxiliary definition to be used below.

Whenever `E` is a cone of shape `K` of sheaves, and `S` is the multifork associated to a
covering `W` of an object `X`, with respect to the cone point `E.X`, this provides a cone of
shape `K` of objects in `D`, with cone point `S.X`.

See `isLimitMultiforkOfIsLimit` for more on how this definition is used.
-/
def multiforkEvaluationCone (F : K ⥤ Sheaf J D) (E : Cone (F ⋙ sheafToPresheaf J D)) (X : C)
    (W : J.Cover X) (S : Multifork (W.index E.pt)) :
    Cone (F ⋙ sheafToPresheaf J D ⋙ (evaluation Cᵒᵖ D).obj (op X)) where
  pt := S.pt
  π :=
    { app := fun k => (Presheaf.isLimitOfIsSheaf J (F.obj k).1 W (F.obj k).2).lift <|
        Multifork.ofι _ S.pt (fun i => S.ι i ≫ (E.π.app k).app (op i.Y))
          (by
            

Proof state:
C : Type u
inst✝² : Category.{v, u} C
J : GrothendieckTopology C
D : Type w
inst✝¹ : Category.{max v u, w} D
K : Type z
inst✝ : Category.{z', z} K
F : K ⥤ Sheaf J D
E : Cone (F ⋙ sheafToPresheaf J D)
X : C
W : GrothendieckTopology.Cover J X
S : Multifork (GrothendieckTopology.Cover.index W E.pt)
k : K
⊢ ∀ (b : (GrothendieckTopology.Cover.index W (F.obj k).val).R),
    (fun i => Multifork.ι S i ≫ (E.π.app k).app (op i.Y))
          (MulticospanIndex.fstTo (GrothendieckTopology.Cover.index W (F.obj k).val) b) ≫
        MulticospanIndex.fst (GrothendieckTopology.Cover.index W (F.obj k).val) b =
      (fun i => Multifork.ι S i ≫ (E.π.app k).app (op i.Y))
          (MulticospanIndex.sndTo (GrothendieckTopology.Cover.index W (F.obj k).val) b) ≫
        MulticospanIndex.snd (GrothendieckTopology.Cover.index W (F.obj k).val) b

Next tactic:
intro i
/-- An auxiliary definition to be used below.

Whenever `E` is a cone of shape `K` of sheaves, and `S` is the multifork associated to a
covering `W` of an object `X`, with respect to the cone point `E.X`, this provides a cone of
shape `K` of objects in `D`, with cone point `S.X`.

See `isLimitMultiforkOfIsLimit` for more on how this definition is used.
-/
def multiforkEvaluationCone (F : K ⥤ Sheaf J D) (E : Cone (F ⋙ sheafToPresheaf J D)) (X : C)
    (W : J.Cover X) (S : Multifork (W.index E.pt)) :
    Cone (F ⋙ sheafToPresheaf J D ⋙ (evaluation Cᵒᵖ D).obj (op X)) where
  pt := S.pt
  π :=
    { app := fun k => (Presheaf.isLimitOfIsSheaf J (F.obj k).1 W (F.obj k).2).lift <|
        Multifork.ofι _ S.pt (fun i => S.ι i ≫ (E.π.app k).app (op i.Y))
          (by
            intro i
            

Proof state:
C : Type u
inst✝² : Category.{v, u} C
J : GrothendieckTopology C
D : Type w
inst✝¹ : Category.{max v u, w} D
K : Type z
inst✝ : Category.{z', z} K
F : K ⥤ Sheaf J D
E : Cone (F ⋙ sheafToPresheaf J D)
X : C
W : GrothendieckTopology.Cover J X
S : Multifork (GrothendieckTopology.Cover.index W E.pt)
k : K
i : (GrothendieckTopology.Cover.index W (F.obj k).val).R
⊢ (fun i => Multifork.ι S i ≫ (E.π.app k).app (op i.Y))
        (MulticospanIndex.fstTo (GrothendieckTopology.Cover.index W (F.obj k).val) i) ≫
      MulticospanIndex.fst (GrothendieckTopology.Cover.index W (F.obj k).val) i =
    (fun i => Multifork.ι S i ≫ (E.π.app k).app (op i.Y))
        (MulticospanIndex.sndTo (GrothendieckTopology.Cover.index W (F.obj k).val) i) ≫
      MulticospanIndex.snd (GrothendieckTopology.Cover.index W (F.obj k).val) i

Next tactic:
simp only [Category.assoc]
/-- An auxiliary definition to be used below.

Whenever `E` is a cone of shape `K` of sheaves, and `S` is the multifork associated to a
covering `W` of an object `X`, with respect to the cone point `E.X`, this provides a cone of
shape `K` of objects in `D`, with cone point `S.X`.

See `isLimitMultiforkOfIsLimit` for more on how this definition is used.
-/
def multiforkEvaluationCone (F : K ⥤ Sheaf J D) (E : Cone (F ⋙ sheafToPresheaf J D)) (X : C)
    (W : J.Cover X) (S : Multifork (W.index E.pt)) :
    Cone (F ⋙ sheafToPresheaf J D ⋙ (evaluation Cᵒᵖ D).obj (op X)) where
  pt := S.pt
  π :=
    { app := fun k => (Presheaf.isLimitOfIsSheaf J (F.obj k).1 W (F.obj k).2).lift <|
        Multifork.ofι _ S.pt (fun i => S.ι i ≫ (E.π.app k).app (op i.Y))
          (by
            intro i
            simp only [Category.assoc]
            

Proof state:
C : Type u
inst✝² : Category.{v, u} C
J : GrothendieckTopology C
D : Type w
inst✝¹ : Category.{max v u, w} D
K : Type z
inst✝ : Category.{z', z} K
F : K ⥤ Sheaf J D
E : Cone (F ⋙ sheafToPresheaf J D)
X : C
W : GrothendieckTopology.Cover J X
S : Multifork (GrothendieckTopology.Cover.index W E.pt)
k : K
i : (GrothendieckTopology.Cover.index W (F.obj k).val).R
⊢ Multifork.ι S (MulticospanIndex.fstTo (GrothendieckTopology.Cover.index W (F.obj k).val) i) ≫
      (E.π.app k).app (op (MulticospanIndex.fstTo (GrothendieckTopology.Cover.index W (F.obj k).val) i).Y) ≫
        MulticospanIndex.fst (GrothendieckTopology.Cover.index W (F.obj k).val) i =
    Multifork.ι S (MulticospanIndex.sndTo (GrothendieckTopology.Cover.index W (F.obj k).val) i) ≫
      (E.π.app k).app (op (MulticospanIndex.sndTo (GrothendieckTopology.Cover.index W (F.obj k).val) i).Y) ≫
        MulticospanIndex.snd (GrothendieckTopology.Cover.index W (F.obj k).val) i

Next tactic:
erw [← (E.π.app k).naturality, ← (E.π.app k).naturality]
/-- An auxiliary definition to be used below.

Whenever `E` is a cone of shape `K` of sheaves, and `S` is the multifork associated to a
covering `W` of an object `X`, with respect to the cone point `E.X`, this provides a cone of
shape `K` of objects in `D`, with cone point `S.X`.

See `isLimitMultiforkOfIsLimit` for more on how this definition is used.
-/
def multiforkEvaluationCone (F : K ⥤ Sheaf J D) (E : Cone (F ⋙ sheafToPresheaf J D)) (X : C)
    (W : J.Cover X) (S : Multifork (W.index E.pt)) :
    Cone (F ⋙ sheafToPresheaf J D ⋙ (evaluation Cᵒᵖ D).obj (op X)) where
  pt := S.pt
  π :=
    { app := fun k => (Presheaf.isLimitOfIsSheaf J (F.obj k).1 W (F.obj k).2).lift <|
        Multifork.ofι _ S.pt (fun i => S.ι i ≫ (E.π.app k).app (op i.Y))
          (by
            intro i
            simp only [Category.assoc]
            erw [← (E.π.app k).naturality, ← (E.π.app k).naturality]
            

Proof state:
C : Type u
inst✝² : Category.{v, u} C
J : GrothendieckTopology C
D : Type w
inst✝¹ : Category.{max v u, w} D
K : Type z
inst✝ : Category.{z', z} K
F : K ⥤ Sheaf J D
E : Cone (F ⋙ sheafToPresheaf J D)
X : C
W : GrothendieckTopology.Cover J X
S : Multifork (GrothendieckTopology.Cover.index W E.pt)
k : K
i : (GrothendieckTopology.Cover.index W (F.obj k).val).R
⊢ Multifork.ι S (MulticospanIndex.fstTo (GrothendieckTopology.Cover.index W (F.obj k).val) i) ≫
      (((Functor.const K).obj E.pt).obj k).map i.g₁.op ≫ (E.π.app k).app (op i.Z) =
    Multifork.ι S (MulticospanIndex.sndTo (GrothendieckTopology.Cover.index W (F.obj k).val) i) ≫
      (((Functor.const K).obj E.pt).obj k).map i.g₂.op ≫ (E.π.app k).app (op i.Z)

Next tactic:
dsimp
/-- An auxiliary definition to be used below.

Whenever `E` is a cone of shape `K` of sheaves, and `S` is the multifork associated to a
covering `W` of an object `X`, with respect to the cone point `E.X`, this provides a cone of
shape `K` of objects in `D`, with cone point `S.X`.

See `isLimitMultiforkOfIsLimit` for more on how this definition is used.
-/
def multiforkEvaluationCone (F : K ⥤ Sheaf J D) (E : Cone (F ⋙ sheafToPresheaf J D)) (X : C)
    (W : J.Cover X) (S : Multifork (W.index E.pt)) :
    Cone (F ⋙ sheafToPresheaf J D ⋙ (evaluation Cᵒᵖ D).obj (op X)) where
  pt := S.pt
  π :=
    { app := fun k => (Presheaf.isLimitOfIsSheaf J (F.obj k).1 W (F.obj k).2).lift <|
        Multifork.ofι _ S.pt (fun i => S.ι i ≫ (E.π.app k).app (op i.Y))
          (by
            intro i
            simp only [Category.assoc]
            erw [← (E.π.app k).naturality, ← (E.π.app k).naturality]
            dsimp
            

Proof state:
C : Type u
inst✝² : Category.{v, u} C
J : GrothendieckTopology C
D : Type w
inst✝¹ : Category.{max v u, w} D
K : Type z
inst✝ : Category.{z', z} K
F : K ⥤ Sheaf J D
E : Cone (F ⋙ sheafToPresheaf J D)
X : C
W : GrothendieckTopology.Cover J X
S : Multifork (GrothendieckTopology.Cover.index W E.pt)
k : K
i : (GrothendieckTopology.Cover.index W (F.obj k).val).R
⊢ Multifork.ι S (MulticospanIndex.fstTo (GrothendieckTopology.Cover.index W (F.obj k).val) i) ≫
      E.pt.map i.g₁.op ≫ (E.π.app k).app (op i.Z) =
    Multifork.ι S (MulticospanIndex.sndTo (GrothendieckTopology.Cover.index W (F.obj k).val) i) ≫
      E.pt.map i.g₂.op ≫ (E.π.app k).app (op i.Z)

Next tactic:
simp only [← Category.assoc]
/-- An auxiliary definition to be used below.

Whenever `E` is a cone of shape `K` of sheaves, and `S` is the multifork associated to a
covering `W` of an object `X`, with respect to the cone point `E.X`, this provides a cone of
shape `K` of objects in `D`, with cone point `S.X`.

See `isLimitMultiforkOfIsLimit` for more on how this definition is used.
-/
def multiforkEvaluationCone (F : K ⥤ Sheaf J D) (E : Cone (F ⋙ sheafToPresheaf J D)) (X : C)
    (W : J.Cover X) (S : Multifork (W.index E.pt)) :
    Cone (F ⋙ sheafToPresheaf J D ⋙ (evaluation Cᵒᵖ D).obj (op X)) where
  pt := S.pt
  π :=
    { app := fun k => (Presheaf.isLimitOfIsSheaf J (F.obj k).1 W (F.obj k).2).lift <|
        Multifork.ofι _ S.pt (fun i => S.ι i ≫ (E.π.app k).app (op i.Y))
          (by
            intro i
            simp only [Category.assoc]
            erw [← (E.π.app k).naturality, ← (E.π.app k).naturality]
            dsimp
            simp only [← Category.assoc]
            

Proof state:
C : Type u
inst✝² : Category.{v, u} C
J : GrothendieckTopology C
D : Type w
inst✝¹ : Category.{max v u, w} D
K : Type z
inst✝ : Category.{z', z} K
F : K ⥤ Sheaf J D
E : Cone (F ⋙ sheafToPresheaf J D)
X : C
W : GrothendieckTopology.Cover J X
S : Multifork (GrothendieckTopology.Cover.index W E.pt)
k : K
i : (GrothendieckTopology.Cover.index W (F.obj k).val).R
⊢ (Multifork.ι S (MulticospanIndex.fstTo (GrothendieckTopology.Cover.index W (F.obj k).val) i) ≫ E.pt.map i.g₁.op) ≫
      (E.π.app k).app (op i.Z) =
    (Multifork.ι S (MulticospanIndex.sndTo (GrothendieckTopology.Cover.index W (F.obj k).val) i) ≫ E.pt.map i.g₂.op) ≫
      (E.π.app k).app (op i.Z)

Next tactic:
congr 1