l3lab/ntp-mathlib huggingface dataset:
@[simp]
lemma baseChange_span (s : Set M) :
    (span R s).baseChange A = span A (TensorProduct.mk R A M 1 '' s) := by
  simp only [baseChange, map_coe]
  refine le_antisymm (span_le.mpr ?_) (span_mono <| Set.image_subset _ subset_span)
  rintro - ⟨m : M, hm : m ∈ span R s, rfl⟩
  apply span_induction (p := fun m' ↦ (1 : A) ⊗ₜ[R] m' ∈ span A (TensorProduct.mk R A M 1 '' s)) hm
  · intro m hm
    exact subset_span ⟨m, hm, rfl⟩
  · 

Proof state:
case intro.intro.H0
R : Type u_1
M : Type u_2
A : Type u_3
inst✝⁴ : CommSemiring R
inst✝³ : Semiring A
inst✝² : Algebra R A
inst✝¹ : AddCommMonoid M
inst✝ : Module R M
p : Submodule R M
s : Set M
m : M
hm : m ∈ span R s
⊢ 1 ⊗ₜ[R] 0 ∈ span A (⇑((TensorProduct.mk R A M) 1) '' s)

Next tactic:
simp
@[simp]
lemma baseChange_span (s : Set M) :
    (span R s).baseChange A = span A (TensorProduct.mk R A M 1 '' s) := by
  simp only [baseChange, map_coe]
  refine le_antisymm (span_le.mpr ?_) (span_mono <| Set.image_subset _ subset_span)
  rintro - ⟨m : M, hm : m ∈ span R s, rfl⟩
  apply span_induction (p := fun m' ↦ (1 : A) ⊗ₜ[R] m' ∈ span A (TensorProduct.mk R A M 1 '' s)) hm
  · intro m hm
    exact subset_span ⟨m, hm, rfl⟩
  · simp
  · 

Proof state:
case intro.intro.H1
R : Type u_1
M : Type u_2
A : Type u_3
inst✝⁴ : CommSemiring R
inst✝³ : Semiring A
inst✝² : Algebra R A
inst✝¹ : AddCommMonoid M
inst✝ : Module R M
p : Submodule R M
s : Set M
m : M
hm : m ∈ span R s
⊢ ∀ (x y : M),
    1 ⊗ₜ[R] x ∈ span A (⇑((TensorProduct.mk R A M) 1) '' s) →
      1 ⊗ₜ[R] y ∈ span A (⇑((TensorProduct.mk R A M) 1) '' s) →
        1 ⊗ₜ[R] (x + y) ∈ span A (⇑((TensorProduct.mk R A M) 1) '' s)

Next tactic:
intro m₁ m₂ hm₁ hm₂
@[simp]
lemma baseChange_span (s : Set M) :
    (span R s).baseChange A = span A (TensorProduct.mk R A M 1 '' s) := by
  simp only [baseChange, map_coe]
  refine le_antisymm (span_le.mpr ?_) (span_mono <| Set.image_subset _ subset_span)
  rintro - ⟨m : M, hm : m ∈ span R s, rfl⟩
  apply span_induction (p := fun m' ↦ (1 : A) ⊗ₜ[R] m' ∈ span A (TensorProduct.mk R A M 1 '' s)) hm
  · intro m hm
    exact subset_span ⟨m, hm, rfl⟩
  · simp
  · intro m₁ m₂ hm₁ hm₂
    

Proof state:
case intro.intro.H1
R : Type u_1
M : Type u_2
A : Type u_3
inst✝⁴ : CommSemiring R
inst✝³ : Semiring A
inst✝² : Algebra R A
inst✝¹ : AddCommMonoid M
inst✝ : Module R M
p : Submodule R M
s : Set M
m : M
hm : m ∈ span R s
m₁ m₂ : M
hm₁ : 1 ⊗ₜ[R] m₁ ∈ span A (⇑((TensorProduct.mk R A M) 1) '' s)
hm₂ : 1 ⊗ₜ[R] m₂ ∈ span A (⇑((TensorProduct.mk R A M) 1) '' s)
⊢ 1 ⊗ₜ[R] (m₁ + m₂) ∈ span A (⇑((TensorProduct.mk R A M) 1) '' s)

Next tactic:
rw [tmul_add]
@[simp]
lemma baseChange_span (s : Set M) :
    (span R s).baseChange A = span A (TensorProduct.mk R A M 1 '' s) := by
  simp only [baseChange, map_coe]
  refine le_antisymm (span_le.mpr ?_) (span_mono <| Set.image_subset _ subset_span)
  rintro - ⟨m : M, hm : m ∈ span R s, rfl⟩
  apply span_induction (p := fun m' ↦ (1 : A) ⊗ₜ[R] m' ∈ span A (TensorProduct.mk R A M 1 '' s)) hm
  · intro m hm
    exact subset_span ⟨m, hm, rfl⟩
  · simp
  · intro m₁ m₂ hm₁ hm₂
    rw [tmul_add]
    

Proof state:
case intro.intro.H1
R : Type u_1
M : Type u_2
A : Type u_3
inst✝⁴ : CommSemiring R
inst✝³ : Semiring A
inst✝² : Algebra R A
inst✝¹ : AddCommMonoid M
inst✝ : Module R M
p : Submodule R M
s : Set M
m : M
hm : m ∈ span R s
m₁ m₂ : M
hm₁ : 1 ⊗ₜ[R] m₁ ∈ span A (⇑((TensorProduct.mk R A M) 1) '' s)
hm₂ : 1 ⊗ₜ[R] m₂ ∈ span A (⇑((TensorProduct.mk R A M) 1) '' s)
⊢ 1 ⊗ₜ[R] m₁ + 1 ⊗ₜ[R] m₂ ∈ span A (⇑((TensorProduct.mk R A M) 1) '' s)

Next tactic:
exact Submodule.add_mem _ hm₁ hm₂
@[simp]
lemma baseChange_span (s : Set M) :
    (span R s).baseChange A = span A (TensorProduct.mk R A M 1 '' s) := by
  simp only [baseChange, map_coe]
  refine le_antisymm (span_le.mpr ?_) (span_mono <| Set.image_subset _ subset_span)
  rintro - ⟨m : M, hm : m ∈ span R s, rfl⟩
  apply span_induction (p := fun m' ↦ (1 : A) ⊗ₜ[R] m' ∈ span A (TensorProduct.mk R A M 1 '' s)) hm
  · intro m hm
    exact subset_span ⟨m, hm, rfl⟩
  · simp
  · intro m₁ m₂ hm₁ hm₂
    rw [tmul_add]
    exact Submodule.add_mem _ hm₁ hm₂
  · 

Proof state:
case intro.intro.H2
R : Type u_1
M : Type u_2
A : Type u_3
inst✝⁴ : CommSemiring R
inst✝³ : Semiring A
inst✝² : Algebra R A
inst✝¹ : AddCommMonoid M
inst✝ : Module R M
p : Submodule R M
s : Set M
m : M
hm : m ∈ span R s
⊢ ∀ (a : R) (x : M),
    1 ⊗ₜ[R] x ∈ span A (⇑((TensorProduct.mk R A M) 1) '' s) →
      1 ⊗ₜ[R] (a • x) ∈ span A (⇑((TensorProduct.mk R A M) 1) '' s)

Next tactic:
intro r m' hm'
@[simp]
lemma baseChange_span (s : Set M) :
    (span R s).baseChange A = span A (TensorProduct.mk R A M 1 '' s) := by
  simp only [baseChange, map_coe]
  refine le_antisymm (span_le.mpr ?_) (span_mono <| Set.image_subset _ subset_span)
  rintro - ⟨m : M, hm : m ∈ span R s, rfl⟩
  apply span_induction (p := fun m' ↦ (1 : A) ⊗ₜ[R] m' ∈ span A (TensorProduct.mk R A M 1 '' s)) hm
  · intro m hm
    exact subset_span ⟨m, hm, rfl⟩
  · simp
  · intro m₁ m₂ hm₁ hm₂
    rw [tmul_add]
    exact Submodule.add_mem _ hm₁ hm₂
  · intro r m' hm'
    

Proof state:
case intro.intro.H2
R : Type u_1
M : Type u_2
A : Type u_3
inst✝⁴ : CommSemiring R
inst✝³ : Semiring A
inst✝² : Algebra R A
inst✝¹ : AddCommMonoid M
inst✝ : Module R M
p : Submodule R M
s : Set M
m : M
hm : m ∈ span R s
r : R
m' : M
hm' : 1 ⊗ₜ[R] m' ∈ span A (⇑((TensorProduct.mk R A M) 1) '' s)
⊢ 1 ⊗ₜ[R] (r • m') ∈ span A (⇑((TensorProduct.mk R A M) 1) '' s)

Next tactic:
rw [tmul_smul, ← one_smul A ((1 : A) ⊗ₜ[R] m'), ← smul_assoc]
@[simp]
lemma baseChange_span (s : Set M) :
    (span R s).baseChange A = span A (TensorProduct.mk R A M 1 '' s) := by
  simp only [baseChange, map_coe]
  refine le_antisymm (span_le.mpr ?_) (span_mono <| Set.image_subset _ subset_span)
  rintro - ⟨m : M, hm : m ∈ span R s, rfl⟩
  apply span_induction (p := fun m' ↦ (1 : A) ⊗ₜ[R] m' ∈ span A (TensorProduct.mk R A M 1 '' s)) hm
  · intro m hm
    exact subset_span ⟨m, hm, rfl⟩
  · simp
  · intro m₁ m₂ hm₁ hm₂
    rw [tmul_add]
    exact Submodule.add_mem _ hm₁ hm₂
  · intro r m' hm'
    rw [tmul_smul, ← one_smul A ((1 : A) ⊗ₜ[R] m'), ← smul_assoc]
    

Proof state:
case intro.intro.H2
R : Type u_1
M : Type u_2
A : Type u_3
inst✝⁴ : CommSemiring R
inst✝³ : Semiring A
inst✝² : Algebra R A
inst✝¹ : AddCommMonoid M
inst✝ : Module R M
p : Submodule R M
s : Set M
m : M
hm : m ∈ span R s
r : R
m' : M
hm' : 1 ⊗ₜ[R] m' ∈ span A (⇑((TensorProduct.mk R A M) 1) '' s)
⊢ (r • 1) • 1 ⊗ₜ[R] m' ∈ span A (⇑((TensorProduct.mk R A M) 1) '' s)

Next tactic:
exact smul_mem _ (r • 1) hm'
/-- If `f(p(t) = g(q(t))` for two paths `p` and `q`, then the induced path homotopy classes
`f(p)` and `g(p)` are the same as well, despite having a priori different types -/
theorem heq_path_of_eq_image : HEq ((πₘ f).map ⟦p⟧) ((πₘ g).map ⟦q⟧) := by
  

Proof state:
X₁ X₂ Y : TopCat
f : C(↑X₁, ↑Y)
g : C(↑X₂, ↑Y)
x₀ x₁ : ↑X₁
x₂ x₃ : ↑X₂
p : Path x₀ x₁
q : Path x₂ x₃
hfg : ∀ (t : ↑I), f (p t) = g (q t)
⊢ HEq ((π.map f).map ⟦p⟧) ((π.map g).map ⟦q⟧)

Next tactic:
simp only [map_eq, ← Path.Homotopic.map_lift]
/-- If `f(p(t) = g(q(t))` for two paths `p` and `q`, then the induced path homotopy classes
`f(p)` and `g(p)` are the same as well, despite having a priori different types -/
theorem heq_path_of_eq_image : HEq ((πₘ f).map ⟦p⟧) ((πₘ g).map ⟦q⟧) := by
  simp only [map_eq, ← Path.Homotopic.map_lift]; 

Proof state:
X₁ X₂ Y : TopCat
f : C(↑X₁, ↑Y)
g : C(↑X₂, ↑Y)
x₀ x₁ : ↑X₁
x₂ x₃ : ↑X₂
p : Path x₀ x₁
q : Path x₂ x₃
hfg : ∀ (t : ↑I), f (p t) = g (q t)
⊢ HEq ⟦Path.map p (_ : Continuous ⇑f)⟧ ⟦Path.map q (_ : Continuous ⇑g)⟧

Next tactic:
apply Path.Homotopic.hpath_hext
/-- If `f(p(t) = g(q(t))` for two paths `p` and `q`, then the induced path homotopy classes
`f(p)` and `g(p)` are the same as well, despite having a priori different types -/
theorem heq_path_of_eq_image : HEq ((πₘ f).map ⟦p⟧) ((πₘ g).map ⟦q⟧) := by
  simp only [map_eq, ← Path.Homotopic.map_lift]; apply Path.Homotopic.hpath_hext; 

Proof state:
case hp
X₁ X₂ Y : TopCat
f : C(↑X₁, ↑Y)
g : C(↑X₂, ↑Y)
x₀ x₁ : ↑X₁
x₂ x₃ : ↑X₂
p : Path x₀ x₁
q : Path x₂ x₃
hfg : ∀ (t : ↑I), f (p t) = g (q t)
⊢ ∀ (t : ↑I), (Path.map p (_ : Continuous ⇑f)) t = (Path.map q (_ : Continuous ⇑g)) t

Next tactic:
exact hfg
private theorem start_path : f x₀ = g x₂ := by 

Proof state:
X₁ X₂ Y : TopCat
f : C(↑X₁, ↑Y)
g : C(↑X₂, ↑Y)
x₀ x₁ : ↑X₁
x₂ x₃ : ↑X₂
p : Path x₀ x₁
q : Path x₂ x₃
hfg : ∀ (t : ↑I), f (p t) = g (q t)
⊢ f x₀ = g x₂

Next tactic:
convert hfg 0
private theorem start_path : f x₀ = g x₂ := by convert hfg 0 <;> 

Proof state:
case h.e'_2.h.e'_6
X₁ X₂ Y : TopCat
f : C(↑X₁, ↑Y)
g : C(↑X₂, ↑Y)
x₀ x₁ : ↑X₁
x₂ x₃ : ↑X₂
p : Path x₀ x₁
q : Path x₂ x₃
hfg : ∀ (t : ↑I), f (p t) = g (q t)
⊢ x₀ = p 0

Next tactic:
simp only [Path.source]
private theorem start_path : f x₀ = g x₂ := by convert hfg 0 <;> 

Proof state:
case h.e'_3.h.e'_6
X₁ X₂ Y : TopCat
f : C(↑X₁, ↑Y)
g : C(↑X₂, ↑Y)
x₀ x₁ : ↑X₁
x₂ x₃ : ↑X₂
p : Path x₀ x₁
q : Path x₂ x₃
hfg : ∀ (t : ↑I), f (p t) = g (q t)
⊢ x₂ = q 0

Next tactic:
simp only [Path.source]
private theorem end_path : f x₁ = g x₃ := by 

Proof state:
X₁ X₂ Y : TopCat
f : C(↑X₁, ↑Y)
g : C(↑X₂, ↑Y)
x₀ x₁ : ↑X₁
x₂ x₃ : ↑X₂
p : Path x₀ x₁
q : Path x₂ x₃
hfg : ∀ (t : ↑I), f (p t) = g (q t)
⊢ f x₁ = g x₃

Next tactic:
convert hfg 1
private theorem end_path : f x₁ = g x₃ := by convert hfg 1 <;> 

Proof state:
case h.e'_2.h.e'_6
X₁ X₂ Y : TopCat
f : C(↑X₁, ↑Y)
g : C(↑X₂, ↑Y)
x₀ x₁ : ↑X₁
x₂ x₃ : ↑X₂
p : Path x₀ x₁
q : Path x₂ x₃
hfg : ∀ (t : ↑I), f (p t) = g (q t)
⊢ x₁ = p 1

Next tactic:
simp only [Path.target]
private theorem end_path : f x₁ = g x₃ := by convert hfg 1 <;> 

Proof state:
case h.e'_3.h.e'_6
X₁ X₂ Y : TopCat
f : C(↑X₁, ↑Y)
g : C(↑X₂, ↑Y)
x₀ x₁ : ↑X₁
x₂ x₃ : ↑X₂
p : Path x₀ x₁
q : Path x₂ x₃
hfg : ∀ (t : ↑I), f (p t) = g (q t)
⊢ x₃ = q 1

Next tactic:
simp only [Path.target]
theorem eq_path_of_eq_image :
    (πₘ f).map ⟦p⟧ = hcast (start_path hfg) ≫ (πₘ g).map ⟦q⟧ ≫ hcast (end_path hfg).symm := by
  

Proof state:
X₁ X₂ Y : TopCat
f : C(↑X₁, ↑Y)
g : C(↑X₂, ↑Y)
x₀ x₁ : ↑X₁
x₂ x₃ : ↑X₂
p : Path x₀ x₁
q : Path x₂ x₃
hfg : ∀ (t : ↑I), f (p t) = g (q t)
⊢ (π.map f).map ⟦p⟧ = hcast (_ : f x₀ = g x₂) ≫ (π.map g).map ⟦q⟧ ≫ hcast (_ : g x₃ = f x₁)

Next tactic:
rw [Functor.conj_eqToHom_iff_heq
    ((πₘ f).map ⟦p⟧) ((πₘ g).map ⟦q⟧)
    (FundamentalGroupoid.ext _ _ <| start_path hfg)
    (FundamentalGroupoid.ext _ _ <| end_path hfg)]
theorem eq_path_of_eq_image :
    (πₘ f).map ⟦p⟧ = hcast (start_path hfg) ≫ (πₘ g).map ⟦q⟧ ≫ hcast (end_path hfg).symm := by
  rw [Functor.conj_eqToHom_iff_heq
    ((πₘ f).map ⟦p⟧) ((πₘ g).map ⟦q⟧)
    (FundamentalGroupoid.ext _ _ <| start_path hfg)
    (FundamentalGroupoid.ext _ _ <| end_path hfg)]
  

Proof state:
X₁ X₂ Y : TopCat
f : C(↑X₁, ↑Y)
g : C(↑X₂, ↑Y)
x₀ x₁ : ↑X₁
x₂ x₃ : ↑X₂
p : Path x₀ x₁
q : Path x₂ x₃
hfg : ∀ (t : ↑I), f (p t) = g (q t)
⊢ HEq ((π.map f).map ⟦p⟧) ((π.map g).map ⟦q⟧)

Next tactic:
exact heq_path_of_eq_image hfg
/-- Proof that `f(p) = H(0 ⟶ 0, p)`, with the appropriate casts -/
theorem apply_zero_path : (πₘ f).map p = hcast (H.apply_zero x₀).symm ≫
    (πₘ H.uliftMap).map (prodToProdTopI (𝟙 (@fromTop (TopCat.of _) (ULift.up 0))) p) ≫
    hcast (H.apply_zero x₁) :=
  Quotient.inductionOn p fun p' => by
    

Proof state:
X Y : TopCat
f g : C(↑X, ↑Y)
H : Homotopy f g
x₀ x₁ : ↑X
p : fromTop x₀ ⟶ fromTop x₁
p' : Path (fromTop x₀).as (fromTop x₁).as
⊢ (π.map f).map ⟦p'⟧ =
    hcast (_ : f x₀ = H (0, x₀)) ≫
      (π.map (uliftMap H)).map (prodToProdTopI (𝟙 (fromTop { down := 0 })) ⟦p'⟧) ≫ hcast (_ : H (0, x₁) = f x₁)

Next tactic:
apply @eq_path_of_eq_image _ _ _ _ H.uliftMap _ _ _ _ _ ((Path.refl (ULift.up _)).prod p')
/-- Proof that `f(p) = H(0 ⟶ 0, p)`, with the appropriate casts -/
theorem apply_zero_path : (πₘ f).map p = hcast (H.apply_zero x₀).symm ≫
    (πₘ H.uliftMap).map (prodToProdTopI (𝟙 (@fromTop (TopCat.of _) (ULift.up 0))) p) ≫
    hcast (H.apply_zero x₁) :=
  Quotient.inductionOn p fun p' => by
    apply @eq_path_of_eq_image _ _ _ _ H.uliftMap _ _ _ _ _ ((Path.refl (ULift.up _)).prod p')
    -- This used to be `rw`, but we need `erw` after leanprover/lean4#2644
    

Proof state:
X Y : TopCat
f g : C(↑X, ↑Y)
H : Homotopy f g
x₀ x₁ : ↑X
p : fromTop x₀ ⟶ fromTop x₁
p' : Path (fromTop x₀).as (fromTop x₁).as
⊢ ∀ (t : ↑I), f (p' t) = (uliftMap H) ((Path.prod (Path.refl { down := 0 }) p') t)

Next tactic:
erw [Path.prod_coe]
/-- Proof that `f(p) = H(0 ⟶ 0, p)`, with the appropriate casts -/
theorem apply_zero_path : (πₘ f).map p = hcast (H.apply_zero x₀).symm ≫
    (πₘ H.uliftMap).map (prodToProdTopI (𝟙 (@fromTop (TopCat.of _) (ULift.up 0))) p) ≫
    hcast (H.apply_zero x₁) :=
  Quotient.inductionOn p fun p' => by
    apply @eq_path_of_eq_image _ _ _ _ H.uliftMap _ _ _ _ _ ((Path.refl (ULift.up _)).prod p')
    -- This used to be `rw`, but we need `erw` after leanprover/lean4#2644
    erw [Path.prod_coe]; 

Proof state:
X Y : TopCat
f g : C(↑X, ↑Y)
H : Homotopy f g
x₀ x₁ : ↑X
p : fromTop x₀ ⟶ fromTop x₁
p' : Path (fromTop x₀).as (fromTop x₁).as
⊢ ∀ (t : ↑I), f (p' t) = (uliftMap H) ((fun t => ((Path.refl { down := 0 }) t, p' t)) t)

Next tactic:
simp_rw [ulift_apply]
/-- Proof that `f(p) = H(0 ⟶ 0, p)`, with the appropriate casts -/
theorem apply_zero_path : (πₘ f).map p = hcast (H.apply_zero x₀).symm ≫
    (πₘ H.uliftMap).map (prodToProdTopI (𝟙 (@fromTop (TopCat.of _) (ULift.up 0))) p) ≫
    hcast (H.apply_zero x₁) :=
  Quotient.inductionOn p fun p' => by
    apply @eq_path_of_eq_image _ _ _ _ H.uliftMap _ _ _ _ _ ((Path.refl (ULift.up _)).prod p')
    -- This used to be `rw`, but we need `erw` after leanprover/lean4#2644
    erw [Path.prod_coe]; simp_rw [ulift_apply]; 

Proof state:
X Y : TopCat
f g : C(↑X, ↑Y)
H : Homotopy f g
x₀ x₁ : ↑X
p : fromTop x₀ ⟶ fromTop x₁
p' : Path (fromTop x₀).as (fromTop x₁).as
⊢ ∀ (t : ↑I), f (p' t) = H (((Path.refl { down := 0 }) t).down, p' t)

Next tactic:
simp
/-- Proof that `g(p) = H(1 ⟶ 1, p)`, with the appropriate casts -/
theorem apply_one_path : (πₘ g).map p = hcast (H.apply_one x₀).symm ≫
    (πₘ H.uliftMap).map (prodToProdTopI (𝟙 (@fromTop (TopCat.of _) (ULift.up 1))) p) ≫
    hcast (H.apply_one x₁) :=
  Quotient.inductionOn p fun p' => by
    

Proof state:
X Y : TopCat
f g : C(↑X, ↑Y)
H : Homotopy f g
x₀ x₁ : ↑X
p : fromTop x₀ ⟶ fromTop x₁
p' : Path (fromTop x₀).as (fromTop x₁).as
⊢ (π.map g).map ⟦p'⟧ =
    hcast (_ : g x₀ = H (1, x₀)) ≫
      (π.map (uliftMap H)).map (prodToProdTopI (𝟙 (fromTop { down := 1 })) ⟦p'⟧) ≫ hcast (_ : H (1, x₁) = g x₁)

Next tactic:
apply @eq_path_of_eq_image _ _ _ _ H.uliftMap _ _ _ _ _ ((Path.refl (ULift.up _)).prod p')
/-- Proof that `g(p) = H(1 ⟶ 1, p)`, with the appropriate casts -/
theorem apply_one_path : (πₘ g).map p = hcast (H.apply_one x₀).symm ≫
    (πₘ H.uliftMap).map (prodToProdTopI (𝟙 (@fromTop (TopCat.of _) (ULift.up 1))) p) ≫
    hcast (H.apply_one x₁) :=
  Quotient.inductionOn p fun p' => by
    apply @eq_path_of_eq_image _ _ _ _ H.uliftMap _ _ _ _ _ ((Path.refl (ULift.up _)).prod p')
    -- This used to be `rw`, but we need `erw` after leanprover/lean4#2644
    

Proof state:
X Y : TopCat
f g : C(↑X, ↑Y)
H : Homotopy f g
x₀ x₁ : ↑X
p : fromTop x₀ ⟶ fromTop x₁
p' : Path (fromTop x₀).as (fromTop x₁).as
⊢ ∀ (t : ↑I), g (p' t) = (uliftMap H) ((Path.prod (Path.refl { down := 1 }) p') t)

Next tactic:
erw [Path.prod_coe]
/-- Proof that `g(p) = H(1 ⟶ 1, p)`, with the appropriate casts -/
theorem apply_one_path : (πₘ g).map p = hcast (H.apply_one x₀).symm ≫
    (πₘ H.uliftMap).map (prodToProdTopI (𝟙 (@fromTop (TopCat.of _) (ULift.up 1))) p) ≫
    hcast (H.apply_one x₁) :=
  Quotient.inductionOn p fun p' => by
    apply @eq_path_of_eq_image _ _ _ _ H.uliftMap _ _ _ _ _ ((Path.refl (ULift.up _)).prod p')
    -- This used to be `rw`, but we need `erw` after leanprover/lean4#2644
    erw [Path.prod_coe]; 

Proof state:
X Y : TopCat
f g : C(↑X, ↑Y)
H : Homotopy f g
x₀ x₁ : ↑X
p : fromTop x₀ ⟶ fromTop x₁
p' : Path (fromTop x₀).as (fromTop x₁).as
⊢ ∀ (t : ↑I), g (p' t) = (uliftMap H) ((fun t => ((Path.refl { down := 1 }) t, p' t)) t)

Next tactic:
simp_rw [ulift_apply]
/-- Proof that `g(p) = H(1 ⟶ 1, p)`, with the appropriate casts -/
theorem apply_one_path : (πₘ g).map p = hcast (H.apply_one x₀).symm ≫
    (πₘ H.uliftMap).map (prodToProdTopI (𝟙 (@fromTop (TopCat.of _) (ULift.up 1))) p) ≫
    hcast (H.apply_one x₁) :=
  Quotient.inductionOn p fun p' => by
    apply @eq_path_of_eq_image _ _ _ _ H.uliftMap _ _ _ _ _ ((Path.refl (ULift.up _)).prod p')
    -- This used to be `rw`, but we need `erw` after leanprover/lean4#2644
    erw [Path.prod_coe]; simp_rw [ulift_apply]; 

Proof state:
X Y : TopCat
f g : C(↑X, ↑Y)
H : Homotopy f g
x₀ x₁ : ↑X
p : fromTop x₀ ⟶ fromTop x₁
p' : Path (fromTop x₀).as (fromTop x₁).as
⊢ ∀ (t : ↑I), g (p' t) = H (((Path.refl { down := 1 }) t).down, p' t)

Next tactic:
simp
/-- Proof that `H.evalAt x = H(0 ⟶ 1, x ⟶ x)`, with the appropriate casts -/
theorem evalAt_eq (x : X) : ⟦H.evalAt x⟧ = hcast (H.apply_zero x).symm ≫
    (πₘ H.uliftMap).map (prodToProdTopI uhpath01 (𝟙 (fromTop x))) ≫
      hcast (H.apply_one x).symm.symm := by
  

Proof state:
X Y : TopCat
f g : C(↑X, ↑Y)
H : Homotopy f g
x₀ x₁ : ↑X
p : fromTop x₀ ⟶ fromTop x₁
x : ↑X
⊢ ⟦evalAt H x⟧ =
    hcast (_ : f x = H (0, x)) ≫
      (π.map (uliftMap H)).map (prodToProdTopI uhpath01 (𝟙 (fromTop x))) ≫ hcast (_ : H (1, x) = g x)

Next tactic:
dsimp only [prodToProdTopI, uhpath01, hcast]
/-- Proof that `H.evalAt x = H(0 ⟶ 1, x ⟶ x)`, with the appropriate casts -/
theorem evalAt_eq (x : X) : ⟦H.evalAt x⟧ = hcast (H.apply_zero x).symm ≫
    (πₘ H.uliftMap).map (prodToProdTopI uhpath01 (𝟙 (fromTop x))) ≫
      hcast (H.apply_one x).symm.symm := by
  dsimp only [prodToProdTopI, uhpath01, hcast]
  

Proof state:
X Y : TopCat
f g : C(↑X, ↑Y)
H : Homotopy f g
x₀ x₁ : ↑X
p : fromTop x₀ ⟶ fromTop x₁
x : ↑X
⊢ ⟦evalAt H x⟧ =
    eqToHom (_ : fromTop (f x) = fromTop (H (0, x))) ≫
      (π.map (uliftMap H)).map
          ((prodToProdTop (TopCat.of (ULift.{u, 0} ↑I)) X).map (⟦unitInterval.upath01⟧, 𝟙 (fromTop x))) ≫
        eqToHom
          (_ :
            fromTop
                ((uliftMap H)
                  ((prodToProdTop (TopCat.of (ULift.{u, 0} ↑I)) X).obj ({ as := { down := 1 } }, { as := x })).as) =
              fromTop (g x))

Next tactic:
refine' (@Functor.conj_eqToHom_iff_heq (πₓ Y) _ _ _ _ _ _ _ _
    (FundamentalGroupoid.ext _ _ <| H.apply_one x).symm).mpr _
/-- Proof that `H.evalAt x = H(0 ⟶ 1, x ⟶ x)`, with the appropriate casts -/
theorem evalAt_eq (x : X) : ⟦H.evalAt x⟧ = hcast (H.apply_zero x).symm ≫
    (πₘ H.uliftMap).map (prodToProdTopI uhpath01 (𝟙 (fromTop x))) ≫
      hcast (H.apply_one x).symm.symm := by
  dsimp only [prodToProdTopI, uhpath01, hcast]
  refine' (@Functor.conj_eqToHom_iff_heq (πₓ Y) _ _ _ _ _ _ _ _
    (FundamentalGroupoid.ext _ _ <| H.apply_one x).symm).mpr _
  

Proof state:
X Y : TopCat
f g : C(↑X, ↑Y)
H : Homotopy f g
x₀ x₁ : ↑X
p : fromTop x₀ ⟶ fromTop x₁
x : ↑X
⊢ HEq ⟦evalAt H x⟧
    ((π.map (uliftMap H)).map
      ((prodToProdTop (TopCat.of (ULift.{u, 0} ↑I)) X).map (⟦unitInterval.upath01⟧, 𝟙 (fromTop x))))

Next tactic:
simp only [id_eq_path_refl, prodToProdTop_map, Path.Homotopic.prod_lift, map_eq, ←
    Path.Homotopic.map_lift]
/-- Proof that `H.evalAt x = H(0 ⟶ 1, x ⟶ x)`, with the appropriate casts -/
theorem evalAt_eq (x : X) : ⟦H.evalAt x⟧ = hcast (H.apply_zero x).symm ≫
    (πₘ H.uliftMap).map (prodToProdTopI uhpath01 (𝟙 (fromTop x))) ≫
      hcast (H.apply_one x).symm.symm := by
  dsimp only [prodToProdTopI, uhpath01, hcast]
  refine' (@Functor.conj_eqToHom_iff_heq (πₓ Y) _ _ _ _ _ _ _ _
    (FundamentalGroupoid.ext _ _ <| H.apply_one x).symm).mpr _
  simp only [id_eq_path_refl, prodToProdTop_map, Path.Homotopic.prod_lift, map_eq, ←
    Path.Homotopic.map_lift]
  

Proof state:
X Y : TopCat
f g : C(↑X, ↑Y)
H : Homotopy f g
x₀ x₁ : ↑X
p : fromTop x₀ ⟶ fromTop x₁
x : ↑X
⊢ HEq ⟦evalAt H x⟧
    (Path.Homotopic.Quotient.mapFn
      ((prodToProdTop (TopCat.of (ULift.{u, 0} ↑I)) X).map (⟦unitInterval.upath01⟧, 𝟙 (fromTop x))) (uliftMap H))

Next tactic:
apply Path.Homotopic.hpath_hext
/-- Proof that `H.evalAt x = H(0 ⟶ 1, x ⟶ x)`, with the appropriate casts -/
theorem evalAt_eq (x : X) : ⟦H.evalAt x⟧ = hcast (H.apply_zero x).symm ≫
    (πₘ H.uliftMap).map (prodToProdTopI uhpath01 (𝟙 (fromTop x))) ≫
      hcast (H.apply_one x).symm.symm := by
  dsimp only [prodToProdTopI, uhpath01, hcast]
  refine' (@Functor.conj_eqToHom_iff_heq (πₓ Y) _ _ _ _ _ _ _ _
    (FundamentalGroupoid.ext _ _ <| H.apply_one x).symm).mpr _
  simp only [id_eq_path_refl, prodToProdTop_map, Path.Homotopic.prod_lift, map_eq, ←
    Path.Homotopic.map_lift]
  apply Path.Homotopic.hpath_hext; 

Proof state:
case hp
X Y : TopCat
f g : C(↑X, ↑Y)
H : Homotopy f g
x₀ x₁ : ↑X
p : fromTop x₀ ⟶ fromTop x₁
x : ↑X
⊢ ∀ (t : ↑I),
    (evalAt H x) t =
      ((fun q => Path.map q (_ : Continuous ⇑(uliftMap H))) (Path.prod unitInterval.upath01 (Path.refl (fromTop x).as)))
        t

Next tactic:
intro
/-- Proof that `H.evalAt x = H(0 ⟶ 1, x ⟶ x)`, with the appropriate casts -/
theorem evalAt_eq (x : X) : ⟦H.evalAt x⟧ = hcast (H.apply_zero x).symm ≫
    (πₘ H.uliftMap).map (prodToProdTopI uhpath01 (𝟙 (fromTop x))) ≫
      hcast (H.apply_one x).symm.symm := by
  dsimp only [prodToProdTopI, uhpath01, hcast]
  refine' (@Functor.conj_eqToHom_iff_heq (πₓ Y) _ _ _ _ _ _ _ _
    (FundamentalGroupoid.ext _ _ <| H.apply_one x).symm).mpr _
  simp only [id_eq_path_refl, prodToProdTop_map, Path.Homotopic.prod_lift, map_eq, ←
    Path.Homotopic.map_lift]
  apply Path.Homotopic.hpath_hext; intro; 

Proof state:
case hp
X Y : TopCat
f g : C(↑X, ↑Y)
H : Homotopy f g
x₀ x₁ : ↑X
p : fromTop x₀ ⟶ fromTop x₁
x : ↑X
t✝ : ↑I
⊢ (evalAt H x) t✝ =
    ((fun q => Path.map q (_ : Continuous ⇑(uliftMap H))) (Path.prod unitInterval.upath01 (Path.refl (fromTop x).as)))
      t✝

Next tactic:
rfl
theorem eq_diag_path : (πₘ f).map p ≫ ⟦H.evalAt x₁⟧ = H.diagonalPath' p ∧
    (⟦H.evalAt x₀⟧ ≫ (πₘ g).map p : fromTop (f x₀) ⟶ fromTop (g x₁)) = H.diagonalPath' p := by
  

Proof state:
X Y : TopCat
f g : C(↑X, ↑Y)
H : Homotopy f g
x₀ x₁ : ↑X
p : fromTop x₀ ⟶ fromTop x₁
⊢ (π.map f).map p ≫ ⟦evalAt H x₁⟧ = diagonalPath' H p ∧ ⟦evalAt H x₀⟧ ≫ (π.map g).map p = diagonalPath' H p

Next tactic:
rw [H.apply_zero_path, H.apply_one_path, H.evalAt_eq]
theorem eq_diag_path : (πₘ f).map p ≫ ⟦H.evalAt x₁⟧ = H.diagonalPath' p ∧
    (⟦H.evalAt x₀⟧ ≫ (πₘ g).map p : fromTop (f x₀) ⟶ fromTop (g x₁)) = H.diagonalPath' p := by
  rw [H.apply_zero_path, H.apply_one_path, H.evalAt_eq]
  

Proof state:
X Y : TopCat
f g : C(↑X, ↑Y)
H : Homotopy f g
x₀ x₁ : ↑X
p : fromTop x₀ ⟶ fromTop x₁
⊢ (hcast (_ : f x₀ = H (0, x₀)) ≫
          (π.map (uliftMap H)).map (prodToProdTopI (𝟙 (fromTop { down := 0 })) p) ≫ hcast (_ : H (0, x₁) = f x₁)) ≫
        ⟦evalAt H x₁⟧ =
      diagonalPath' H p ∧
    (hcast (_ : f x₀ = H (0, x₀)) ≫
          (π.map (uliftMap H)).map (prodToProdTopI uhpath01 (𝟙 (fromTop x₀))) ≫ hcast (_ : H (1, x₀) = g x₀)) ≫
        hcast (_ : g x₀ = H (1, x₀)) ≫
          (π.map (uliftMap H)).map (prodToProdTopI (𝟙 (fromTop { down := 1 })) p) ≫ hcast (_ : H (1, x₁) = g x₁) =
      diagonalPath' H p

Next tactic:
erw [H.evalAt_eq]
theorem eq_diag_path : (πₘ f).map p ≫ ⟦H.evalAt x₁⟧ = H.diagonalPath' p ∧
    (⟦H.evalAt x₀⟧ ≫ (πₘ g).map p : fromTop (f x₀) ⟶ fromTop (g x₁)) = H.diagonalPath' p := by
  rw [H.apply_zero_path, H.apply_one_path, H.evalAt_eq]
  erw [H.evalAt_eq] -- Porting note: `rw` didn't work, so using `erw`
  

Proof state:
X Y : TopCat
f g : C(↑X, ↑Y)
H : Homotopy f g
x₀ x₁ : ↑X
p : fromTop x₀ ⟶ fromTop x₁
⊢ (hcast (_ : f x₀ = H (0, x₀)) ≫
          (π.map (uliftMap H)).map (prodToProdTopI (𝟙 (fromTop { down := 0 })) p) ≫ hcast (_ : H (0, x₁) = f x₁)) ≫
        hcast (_ : f (fromTop x₁).as = H (0, (fromTop x₁).as)) ≫
          (π.map (uliftMap H)).map (prodToProdTopI uhpath01 (𝟙 (fromTop (fromTop x₁).as))) ≫
            hcast (_ : H (1, (fromTop x₁).as) = g (fromTop x₁).as) =
      diagonalPath' H p ∧
    (hcast (_ : f x₀ = H (0, x₀)) ≫
          (π.map (uliftMap H)).map (prodToProdTopI uhpath01 (𝟙 (fromTop x₀))) ≫ hcast (_ : H (1, x₀) = g x₀)) ≫
        hcast (_ : g x₀ = H (1, x₀)) ≫
          (π.map (uliftMap H)).map (prodToProdTopI (𝟙 (fromTop { down := 1 })) p) ≫ hcast (_ : H (1, x₁) = g x₁) =
      diagonalPath' H p

Next tactic:
dsimp only [prodToProdTopI]