l3lab/ntp-mathlib huggingface dataset:
/-- The constructed binary fan is indeed a limit -/
def prodBinaryFanIsLimit (X Y : TopCat.{u}) : IsLimit (prodBinaryFan X Y) where
  lift := fun S : BinaryFan X Y => {
    toFun := fun s => (S.fst s, S.snd s)
    -- Porting note: continuity failed again here. Lean cannot infer
    -- ContinuousMapClass (X ⟶ Y) X Y for X Y : TopCat which may be one of the problems
    continuous_toFun := (Continuous.prod_mk)
      (BinaryFan.fst S).continuous_toFun (BinaryFan.snd S).continuous_toFun }
  fac := by
    rintro S (_ | _) <;> {dsimp; ext; rfl}
  uniq := by
    intro S m h
    -- porting note: used to be `ext x`
    refine' ContinuousMap.ext (fun (x : ↥(S.pt)) => Prod.ext _ _)
    · specialize h ⟨WalkingPair.left⟩
      apply_fun fun e => e x at h
      exact h
    · specialize h ⟨WalkingPair.right⟩
      apply_fun fun e => e x at h
      

Proof state:
case refine'_2
J : Type v
inst✝ : SmallCategory J
X Y : TopCat
S : Cone (pair X Y)
m : S.pt ⟶ (prodBinaryFan X Y).pt
x : ↑S.pt
h : (m ≫ (prodBinaryFan X Y).π.app { as := WalkingPair.right }) x = (S.π.app { as := WalkingPair.right }) x
⊢ (m x).2 = (((fun S => ContinuousMap.mk fun s => ((BinaryFan.fst S) s, (BinaryFan.snd S) s)) S) x).2

Next tactic:
exact h
@[reassoc (attr := simp)]
theorem prodIsoProd_hom_fst (X Y : TopCat.{u}) :
    (prodIsoProd X Y).hom ≫ prodFst = Limits.prod.fst := by
  

Proof state:
J : Type v
inst✝ : SmallCategory J
X Y : TopCat
⊢ (prodIsoProd X Y).hom ≫ prodFst = prod.fst

Next tactic:
simp [← Iso.eq_inv_comp, prodIsoProd]
@[reassoc (attr := simp)]
theorem prodIsoProd_hom_fst (X Y : TopCat.{u}) :
    (prodIsoProd X Y).hom ≫ prodFst = Limits.prod.fst := by
  simp [← Iso.eq_inv_comp, prodIsoProd]
  

Proof state:
J : Type v
inst✝ : SmallCategory J
X Y : TopCat
⊢ prodFst = BinaryFan.fst (prodBinaryFan X Y)

Next tactic:
rfl
@[reassoc (attr := simp)]
theorem prodIsoProd_hom_snd (X Y : TopCat.{u}) :
    (prodIsoProd X Y).hom ≫ prodSnd = Limits.prod.snd := by
  

Proof state:
J : Type v
inst✝ : SmallCategory J
X Y : TopCat
⊢ (prodIsoProd X Y).hom ≫ prodSnd = prod.snd

Next tactic:
simp [← Iso.eq_inv_comp, prodIsoProd]
@[reassoc (attr := simp)]
theorem prodIsoProd_hom_snd (X Y : TopCat.{u}) :
    (prodIsoProd X Y).hom ≫ prodSnd = Limits.prod.snd := by
  simp [← Iso.eq_inv_comp, prodIsoProd]
  

Proof state:
J : Type v
inst✝ : SmallCategory J
X Y : TopCat
⊢ prodSnd = BinaryFan.snd (prodBinaryFan X Y)

Next tactic:
rfl
@[simp]
theorem prodIsoProd_hom_apply {X Y : TopCat.{u}} (x : ↑ (X ⨯ Y)) :
    (prodIsoProd X Y).hom x = ((Limits.prod.fst : X ⨯ Y ⟶ _) x,
    (Limits.prod.snd : X ⨯ Y ⟶ _) x) := by
  -- Porting note: ext didn't pick this up
  

Proof state:
J : Type v
inst✝ : SmallCategory J
X Y : TopCat
x : ↑(X ⨯ Y)
⊢ (prodIsoProd X Y).hom x = (prod.fst x, prod.snd x)

Next tactic:
apply Prod.ext
@[simp]
theorem prodIsoProd_hom_apply {X Y : TopCat.{u}} (x : ↑ (X ⨯ Y)) :
    (prodIsoProd X Y).hom x = ((Limits.prod.fst : X ⨯ Y ⟶ _) x,
    (Limits.prod.snd : X ⨯ Y ⟶ _) x) := by
  -- Porting note: ext didn't pick this up
  apply Prod.ext
  · 

Proof state:
case a
J : Type v
inst✝ : SmallCategory J
X Y : TopCat
x : ↑(X ⨯ Y)
⊢ ((prodIsoProd X Y).hom x).1 = (prod.fst x, prod.snd x).1

Next tactic:
exact ConcreteCategory.congr_hom (prodIsoProd_hom_fst X Y) x
@[simp]
theorem prodIsoProd_hom_apply {X Y : TopCat.{u}} (x : ↑ (X ⨯ Y)) :
    (prodIsoProd X Y).hom x = ((Limits.prod.fst : X ⨯ Y ⟶ _) x,
    (Limits.prod.snd : X ⨯ Y ⟶ _) x) := by
  -- Porting note: ext didn't pick this up
  apply Prod.ext
  · exact ConcreteCategory.congr_hom (prodIsoProd_hom_fst X Y) x
  · 

Proof state:
case a
J : Type v
inst✝ : SmallCategory J
X Y : TopCat
x : ↑(X ⨯ Y)
⊢ ((prodIsoProd X Y).hom x).2 = (prod.fst x, prod.snd x).2

Next tactic:
exact ConcreteCategory.congr_hom (prodIsoProd_hom_snd X Y) x
@[reassoc (attr := simp), elementwise]
theorem prodIsoProd_inv_fst (X Y : TopCat.{u}) :
    (prodIsoProd X Y).inv ≫ Limits.prod.fst = prodFst := by 

Proof state:
J : Type v
inst✝ : SmallCategory J
X Y : TopCat
⊢ (prodIsoProd X Y).inv ≫ prod.fst = prodFst

Next tactic:
simp [Iso.inv_comp_eq]
@[reassoc (attr := simp), elementwise]
theorem prodIsoProd_inv_snd (X Y : TopCat.{u}) :
    (prodIsoProd X Y).inv ≫ Limits.prod.snd = prodSnd := by 

Proof state:
J : Type v
inst✝ : SmallCategory J
X Y : TopCat
⊢ (prodIsoProd X Y).inv ≫ prod.snd = prodSnd

Next tactic:
simp [Iso.inv_comp_eq]
theorem prod_topology {X Y : TopCat.{u}} :
    (X ⨯ Y).str =
      induced (Limits.prod.fst : X ⨯ Y ⟶ _) X.str ⊓
        induced (Limits.prod.snd : X ⨯ Y ⟶ _) Y.str := by
  

Proof state:
J : Type v
inst✝ : SmallCategory J
X Y : TopCat
⊢ (X ⨯ Y).str = induced (⇑prod.fst) X.str ⊓ induced (⇑prod.snd) Y.str

Next tactic:
let homeo := homeoOfIso (prodIsoProd X Y)
theorem prod_topology {X Y : TopCat.{u}} :
    (X ⨯ Y).str =
      induced (Limits.prod.fst : X ⨯ Y ⟶ _) X.str ⊓
        induced (Limits.prod.snd : X ⨯ Y ⟶ _) Y.str := by
  let homeo := homeoOfIso (prodIsoProd X Y)
  

Proof state:
J : Type v
inst✝ : SmallCategory J
X Y : TopCat
homeo : ↑(X ⨯ Y) ≃ₜ ↑(of (↑X × ↑Y)) := homeoOfIso (prodIsoProd X Y)
⊢ (X ⨯ Y).str = induced (⇑prod.fst) X.str ⊓ induced (⇑prod.snd) Y.str

Next tactic:
refine' homeo.inducing.induced.trans _
theorem prod_topology {X Y : TopCat.{u}} :
    (X ⨯ Y).str =
      induced (Limits.prod.fst : X ⨯ Y ⟶ _) X.str ⊓
        induced (Limits.prod.snd : X ⨯ Y ⟶ _) Y.str := by
  let homeo := homeoOfIso (prodIsoProd X Y)
  refine' homeo.inducing.induced.trans _
  

Proof state:
J : Type v
inst✝ : SmallCategory J
X Y : TopCat
homeo : ↑(X ⨯ Y) ≃ₜ ↑(of (↑X × ↑Y)) := homeoOfIso (prodIsoProd X Y)
⊢ induced (⇑homeo) (topologicalSpace_coe (of (↑X × ↑Y))) = induced (⇑prod.fst) X.str ⊓ induced (⇑prod.snd) Y.str

Next tactic:
change induced homeo (_ ⊓ _) = _
theorem prod_topology {X Y : TopCat.{u}} :
    (X ⨯ Y).str =
      induced (Limits.prod.fst : X ⨯ Y ⟶ _) X.str ⊓
        induced (Limits.prod.snd : X ⨯ Y ⟶ _) Y.str := by
  let homeo := homeoOfIso (prodIsoProd X Y)
  refine' homeo.inducing.induced.trans _
  change induced homeo (_ ⊓ _) = _
  

Proof state:
J : Type v
inst✝ : SmallCategory J
X Y : TopCat
homeo : ↑(X ⨯ Y) ≃ₜ ↑(of (↑X × ↑Y)) := homeoOfIso (prodIsoProd X Y)
⊢ induced (⇑homeo) (induced Prod.fst (topologicalSpace_coe X) ⊓ induced Prod.snd (topologicalSpace_coe Y)) =
    induced (⇑prod.fst) X.str ⊓ induced (⇑prod.snd) Y.str

Next tactic:
simp [induced_compose]
theorem prod_topology {X Y : TopCat.{u}} :
    (X ⨯ Y).str =
      induced (Limits.prod.fst : X ⨯ Y ⟶ _) X.str ⊓
        induced (Limits.prod.snd : X ⨯ Y ⟶ _) Y.str := by
  let homeo := homeoOfIso (prodIsoProd X Y)
  refine' homeo.inducing.induced.trans _
  change induced homeo (_ ⊓ _) = _
  simp [induced_compose]
  

Proof state:
J : Type v
inst✝ : SmallCategory J
X Y : TopCat
homeo : ↑(X ⨯ Y) ≃ₜ ↑(of (↑X × ↑Y)) := homeoOfIso (prodIsoProd X Y)
⊢ induced (Prod.fst ∘ ⇑(homeoOfIso (prodIsoProd X Y))) (topologicalSpace_coe X) ⊓
      induced (Prod.snd ∘ ⇑(homeoOfIso (prodIsoProd X Y))) (topologicalSpace_coe Y) =
    induced (⇑prod.fst) X.str ⊓ induced (⇑prod.snd) Y.str

Next tactic:
rfl
theorem range_prod_map {W X Y Z : TopCat.{u}} (f : W ⟶ Y) (g : X ⟶ Z) :
    Set.range (Limits.prod.map f g) =
      (Limits.prod.fst : Y ⨯ Z ⟶ _) ⁻¹' Set.range f ∩
        (Limits.prod.snd : Y ⨯ Z ⟶ _) ⁻¹' Set.range g := by
  

Proof state:
J : Type v
inst✝ : SmallCategory J
W X Y Z : TopCat
f : W ⟶ Y
g : X ⟶ Z
⊢ Set.range ⇑(prod.map f g) = ⇑prod.fst ⁻¹' Set.range ⇑f ∩ ⇑prod.snd ⁻¹' Set.range ⇑g

Next tactic:
ext x
theorem range_prod_map {W X Y Z : TopCat.{u}} (f : W ⟶ Y) (g : X ⟶ Z) :
    Set.range (Limits.prod.map f g) =
      (Limits.prod.fst : Y ⨯ Z ⟶ _) ⁻¹' Set.range f ∩
        (Limits.prod.snd : Y ⨯ Z ⟶ _) ⁻¹' Set.range g := by
  ext x
  

Proof state:
case h
J : Type v
inst✝ : SmallCategory J
W X Y Z : TopCat
f : W ⟶ Y
g : X ⟶ Z
x : (forget TopCat).obj (Y ⨯ Z)
⊢ x ∈ Set.range ⇑(prod.map f g) ↔ x ∈ ⇑prod.fst ⁻¹' Set.range ⇑f ∩ ⇑prod.snd ⁻¹' Set.range ⇑g

Next tactic:
constructor
theorem range_prod_map {W X Y Z : TopCat.{u}} (f : W ⟶ Y) (g : X ⟶ Z) :
    Set.range (Limits.prod.map f g) =
      (Limits.prod.fst : Y ⨯ Z ⟶ _) ⁻¹' Set.range f ∩
        (Limits.prod.snd : Y ⨯ Z ⟶ _) ⁻¹' Set.range g := by
  ext x
  constructor
  · 

Proof state:
case h.mp
J : Type v
inst✝ : SmallCategory J
W X Y Z : TopCat
f : W ⟶ Y
g : X ⟶ Z
x : (forget TopCat).obj (Y ⨯ Z)
⊢ x ∈ Set.range ⇑(prod.map f g) → x ∈ ⇑prod.fst ⁻¹' Set.range ⇑f ∩ ⇑prod.snd ⁻¹' Set.range ⇑g

Next tactic:
rintro ⟨y, rfl⟩
theorem range_prod_map {W X Y Z : TopCat.{u}} (f : W ⟶ Y) (g : X ⟶ Z) :
    Set.range (Limits.prod.map f g) =
      (Limits.prod.fst : Y ⨯ Z ⟶ _) ⁻¹' Set.range f ∩
        (Limits.prod.snd : Y ⨯ Z ⟶ _) ⁻¹' Set.range g := by
  ext x
  constructor
  · rintro ⟨y, rfl⟩
    

Proof state:
case h.mp.intro
J : Type v
inst✝ : SmallCategory J
W X Y Z : TopCat
f : W ⟶ Y
g : X ⟶ Z
y : (forget TopCat).obj (W ⨯ X)
⊢ (prod.map f g) y ∈ ⇑prod.fst ⁻¹' Set.range ⇑f ∩ ⇑prod.snd ⁻¹' Set.range ⇑g

Next tactic:
simp only [Set.mem_preimage, Set.mem_range, Set.mem_inter_iff, ← comp_apply]
theorem range_prod_map {W X Y Z : TopCat.{u}} (f : W ⟶ Y) (g : X ⟶ Z) :
    Set.range (Limits.prod.map f g) =
      (Limits.prod.fst : Y ⨯ Z ⟶ _) ⁻¹' Set.range f ∩
        (Limits.prod.snd : Y ⨯ Z ⟶ _) ⁻¹' Set.range g := by
  ext x
  constructor
  · rintro ⟨y, rfl⟩
    simp only [Set.mem_preimage, Set.mem_range, Set.mem_inter_iff, ← comp_apply]
    

Proof state:
case h.mp.intro
J : Type v
inst✝ : SmallCategory J
W X Y Z : TopCat
f : W ⟶ Y
g : X ⟶ Z
y : (forget TopCat).obj (W ⨯ X)
⊢ (∃ y_1, f y_1 = (prod.map f g ≫ prod.fst) y) ∧ ∃ y_1, g y_1 = (prod.map f g ≫ prod.snd) y

Next tactic:
simp only [Limits.prod.map_fst, Limits.prod.map_snd, exists_apply_eq_apply, comp_apply,
      and_self_iff]
theorem range_prod_map {W X Y Z : TopCat.{u}} (f : W ⟶ Y) (g : X ⟶ Z) :
    Set.range (Limits.prod.map f g) =
      (Limits.prod.fst : Y ⨯ Z ⟶ _) ⁻¹' Set.range f ∩
        (Limits.prod.snd : Y ⨯ Z ⟶ _) ⁻¹' Set.range g := by
  ext x
  constructor
  · rintro ⟨y, rfl⟩
    simp only [Set.mem_preimage, Set.mem_range, Set.mem_inter_iff, ← comp_apply]
    simp only [Limits.prod.map_fst, Limits.prod.map_snd, exists_apply_eq_apply, comp_apply,
      and_self_iff]
  · 

Proof state:
case h.mpr
J : Type v
inst✝ : SmallCategory J
W X Y Z : TopCat
f : W ⟶ Y
g : X ⟶ Z
x : (forget TopCat).obj (Y ⨯ Z)
⊢ x ∈ ⇑prod.fst ⁻¹' Set.range ⇑f ∩ ⇑prod.snd ⁻¹' Set.range ⇑g → x ∈ Set.range ⇑(prod.map f g)

Next tactic:
rintro ⟨⟨x₁, hx₁⟩, ⟨x₂, hx₂⟩⟩
theorem range_prod_map {W X Y Z : TopCat.{u}} (f : W ⟶ Y) (g : X ⟶ Z) :
    Set.range (Limits.prod.map f g) =
      (Limits.prod.fst : Y ⨯ Z ⟶ _) ⁻¹' Set.range f ∩
        (Limits.prod.snd : Y ⨯ Z ⟶ _) ⁻¹' Set.range g := by
  ext x
  constructor
  · rintro ⟨y, rfl⟩
    simp only [Set.mem_preimage, Set.mem_range, Set.mem_inter_iff, ← comp_apply]
    simp only [Limits.prod.map_fst, Limits.prod.map_snd, exists_apply_eq_apply, comp_apply,
      and_self_iff]
  · rintro ⟨⟨x₁, hx₁⟩, ⟨x₂, hx₂⟩⟩
    

Proof state:
case h.mpr.intro.intro.intro
J : Type v
inst✝ : SmallCategory J
W X Y Z : TopCat
f : W ⟶ Y
g : X ⟶ Z
x : (forget TopCat).obj (Y ⨯ Z)
x₁ : (forget TopCat).obj W
hx₁ : f x₁ = prod.fst x
x₂ : (forget TopCat).obj X
hx₂ : g x₂ = prod.snd x
⊢ x ∈ Set.range ⇑(prod.map f g)

Next tactic:
use (prodIsoProd W X).inv (x₁, x₂)
theorem range_prod_map {W X Y Z : TopCat.{u}} (f : W ⟶ Y) (g : X ⟶ Z) :
    Set.range (Limits.prod.map f g) =
      (Limits.prod.fst : Y ⨯ Z ⟶ _) ⁻¹' Set.range f ∩
        (Limits.prod.snd : Y ⨯ Z ⟶ _) ⁻¹' Set.range g := by
  ext x
  constructor
  · rintro ⟨y, rfl⟩
    simp only [Set.mem_preimage, Set.mem_range, Set.mem_inter_iff, ← comp_apply]
    simp only [Limits.prod.map_fst, Limits.prod.map_snd, exists_apply_eq_apply, comp_apply,
      and_self_iff]
  · rintro ⟨⟨x₁, hx₁⟩, ⟨x₂, hx₂⟩⟩
    use (prodIsoProd W X).inv (x₁, x₂)
    

Proof state:
case h
J : Type v
inst✝ : SmallCategory J
W X Y Z : TopCat
f : W ⟶ Y
g : X ⟶ Z
x : (forget TopCat).obj (Y ⨯ Z)
x₁ : (forget TopCat).obj W
hx₁ : f x₁ = prod.fst x
x₂ : (forget TopCat).obj X
hx₂ : g x₂ = prod.snd x
⊢ (prod.map f g) ((prodIsoProd W X).inv (x₁, x₂)) = x

Next tactic:
apply Concrete.limit_ext
theorem range_prod_map {W X Y Z : TopCat.{u}} (f : W ⟶ Y) (g : X ⟶ Z) :
    Set.range (Limits.prod.map f g) =
      (Limits.prod.fst : Y ⨯ Z ⟶ _) ⁻¹' Set.range f ∩
        (Limits.prod.snd : Y ⨯ Z ⟶ _) ⁻¹' Set.range g := by
  ext x
  constructor
  · rintro ⟨y, rfl⟩
    simp only [Set.mem_preimage, Set.mem_range, Set.mem_inter_iff, ← comp_apply]
    simp only [Limits.prod.map_fst, Limits.prod.map_snd, exists_apply_eq_apply, comp_apply,
      and_self_iff]
  · rintro ⟨⟨x₁, hx₁⟩, ⟨x₂, hx₂⟩⟩
    use (prodIsoProd W X).inv (x₁, x₂)
    apply Concrete.limit_ext
    

Proof state:
case h.a
J : Type v
inst✝ : SmallCategory J
W X Y Z : TopCat
f : W ⟶ Y
g : X ⟶ Z
x : (forget TopCat).obj (Y ⨯ Z)
x₁ : (forget TopCat).obj W
hx₁ : f x₁ = prod.fst x
x₂ : (forget TopCat).obj X
hx₂ : g x₂ = prod.snd x
⊢ ∀ (j : Discrete WalkingPair),
    (limit.π (pair Y Z) j) ((prod.map f g) ((prodIsoProd W X).inv (x₁, x₂))) = (limit.π (pair Y Z) j) x

Next tactic:
rintro ⟨⟨⟩⟩
theorem range_prod_map {W X Y Z : TopCat.{u}} (f : W ⟶ Y) (g : X ⟶ Z) :
    Set.range (Limits.prod.map f g) =
      (Limits.prod.fst : Y ⨯ Z ⟶ _) ⁻¹' Set.range f ∩
        (Limits.prod.snd : Y ⨯ Z ⟶ _) ⁻¹' Set.range g := by
  ext x
  constructor
  · rintro ⟨y, rfl⟩
    simp only [Set.mem_preimage, Set.mem_range, Set.mem_inter_iff, ← comp_apply]
    simp only [Limits.prod.map_fst, Limits.prod.map_snd, exists_apply_eq_apply, comp_apply,
      and_self_iff]
  · rintro ⟨⟨x₁, hx₁⟩, ⟨x₂, hx₂⟩⟩
    use (prodIsoProd W X).inv (x₁, x₂)
    apply Concrete.limit_ext
    rintro ⟨⟨⟩⟩
    · 

Proof state:
case h.a.mk.left
J : Type v
inst✝ : SmallCategory J
W X Y Z : TopCat
f : W ⟶ Y
g : X ⟶ Z
x : (forget TopCat).obj (Y ⨯ Z)
x₁ : (forget TopCat).obj W
hx₁ : f x₁ = prod.fst x
x₂ : (forget TopCat).obj X
hx₂ : g x₂ = prod.snd x
⊢ (limit.π (pair Y Z) { as := WalkingPair.left }) ((prod.map f g) ((prodIsoProd W X).inv (x₁, x₂))) =
    (limit.π (pair Y Z) { as := WalkingPair.left }) x

Next tactic:
simp only [← comp_apply, Category.assoc]
theorem range_prod_map {W X Y Z : TopCat.{u}} (f : W ⟶ Y) (g : X ⟶ Z) :
    Set.range (Limits.prod.map f g) =
      (Limits.prod.fst : Y ⨯ Z ⟶ _) ⁻¹' Set.range f ∩
        (Limits.prod.snd : Y ⨯ Z ⟶ _) ⁻¹' Set.range g := by
  ext x
  constructor
  · rintro ⟨y, rfl⟩
    simp only [Set.mem_preimage, Set.mem_range, Set.mem_inter_iff, ← comp_apply]
    simp only [Limits.prod.map_fst, Limits.prod.map_snd, exists_apply_eq_apply, comp_apply,
      and_self_iff]
  · rintro ⟨⟨x₁, hx₁⟩, ⟨x₂, hx₂⟩⟩
    use (prodIsoProd W X).inv (x₁, x₂)
    apply Concrete.limit_ext
    rintro ⟨⟨⟩⟩
    · simp only [← comp_apply, Category.assoc]
      

Proof state:
case h.a.mk.left
J : Type v
inst✝ : SmallCategory J
W X Y Z : TopCat
f : W ⟶ Y
g : X ⟶ Z
x : (forget TopCat).obj (Y ⨯ Z)
x₁ : (forget TopCat).obj W
hx₁ : f x₁ = prod.fst x
x₂ : (forget TopCat).obj X
hx₂ : g x₂ = prod.snd x
⊢ ((prodIsoProd W X).inv ≫ prod.map f g ≫ limit.π (pair Y Z) { as := WalkingPair.left }) (x₁, x₂) =
    (limit.π (pair Y Z) { as := WalkingPair.left }) x

Next tactic:
erw [Limits.prod.map_fst]
theorem range_prod_map {W X Y Z : TopCat.{u}} (f : W ⟶ Y) (g : X ⟶ Z) :
    Set.range (Limits.prod.map f g) =
      (Limits.prod.fst : Y ⨯ Z ⟶ _) ⁻¹' Set.range f ∩
        (Limits.prod.snd : Y ⨯ Z ⟶ _) ⁻¹' Set.range g := by
  ext x
  constructor
  · rintro ⟨y, rfl⟩
    simp only [Set.mem_preimage, Set.mem_range, Set.mem_inter_iff, ← comp_apply]
    simp only [Limits.prod.map_fst, Limits.prod.map_snd, exists_apply_eq_apply, comp_apply,
      and_self_iff]
  · rintro ⟨⟨x₁, hx₁⟩, ⟨x₂, hx₂⟩⟩
    use (prodIsoProd W X).inv (x₁, x₂)
    apply Concrete.limit_ext
    rintro ⟨⟨⟩⟩
    · simp only [← comp_apply, Category.assoc]
      erw [Limits.prod.map_fst]
      

Proof state:
case h.a.mk.left
J : Type v
inst✝ : SmallCategory J
W X Y Z : TopCat
f : W ⟶ Y
g : X ⟶ Z
x : (forget TopCat).obj (Y ⨯ Z)
x₁ : (forget TopCat).obj W
hx₁ : f x₁ = prod.fst x
x₂ : (forget TopCat).obj X
hx₂ : g x₂ = prod.snd x
⊢ ((prodIsoProd W X).inv ≫ prod.fst ≫ f) (x₁, x₂) = (limit.π (pair Y Z) { as := WalkingPair.left }) x

Next tactic:
rw [TopCat.prodIsoProd_inv_fst_assoc,TopCat.comp_app]
theorem range_prod_map {W X Y Z : TopCat.{u}} (f : W ⟶ Y) (g : X ⟶ Z) :
    Set.range (Limits.prod.map f g) =
      (Limits.prod.fst : Y ⨯ Z ⟶ _) ⁻¹' Set.range f ∩
        (Limits.prod.snd : Y ⨯ Z ⟶ _) ⁻¹' Set.range g := by
  ext x
  constructor
  · rintro ⟨y, rfl⟩
    simp only [Set.mem_preimage, Set.mem_range, Set.mem_inter_iff, ← comp_apply]
    simp only [Limits.prod.map_fst, Limits.prod.map_snd, exists_apply_eq_apply, comp_apply,
      and_self_iff]
  · rintro ⟨⟨x₁, hx₁⟩, ⟨x₂, hx₂⟩⟩
    use (prodIsoProd W X).inv (x₁, x₂)
    apply Concrete.limit_ext
    rintro ⟨⟨⟩⟩
    · simp only [← comp_apply, Category.assoc]
      erw [Limits.prod.map_fst]
      rw [TopCat.prodIsoProd_inv_fst_assoc,TopCat.comp_app]
      

Proof state:
case h.a.mk.left
J : Type v
inst✝ : SmallCategory J
W X Y Z : TopCat
f : W ⟶ Y
g : X ⟶ Z
x : (forget TopCat).obj (Y ⨯ Z)
x₁ : (forget TopCat).obj W
hx₁ : f x₁ = prod.fst x
x₂ : (forget TopCat).obj X
hx₂ : g x₂ = prod.snd x
⊢ f (prodFst (x₁, x₂)) = (limit.π (pair Y Z) { as := WalkingPair.left }) x

Next tactic:
exact hx₁
theorem range_prod_map {W X Y Z : TopCat.{u}} (f : W ⟶ Y) (g : X ⟶ Z) :
    Set.range (Limits.prod.map f g) =
      (Limits.prod.fst : Y ⨯ Z ⟶ _) ⁻¹' Set.range f ∩
        (Limits.prod.snd : Y ⨯ Z ⟶ _) ⁻¹' Set.range g := by
  ext x
  constructor
  · rintro ⟨y, rfl⟩
    simp only [Set.mem_preimage, Set.mem_range, Set.mem_inter_iff, ← comp_apply]
    simp only [Limits.prod.map_fst, Limits.prod.map_snd, exists_apply_eq_apply, comp_apply,
      and_self_iff]
  · rintro ⟨⟨x₁, hx₁⟩, ⟨x₂, hx₂⟩⟩
    use (prodIsoProd W X).inv (x₁, x₂)
    apply Concrete.limit_ext
    rintro ⟨⟨⟩⟩
    · simp only [← comp_apply, Category.assoc]
      erw [Limits.prod.map_fst]
      rw [TopCat.prodIsoProd_inv_fst_assoc,TopCat.comp_app]
      exact hx₁
    · 

Proof state:
case h.a.mk.right
J : Type v
inst✝ : SmallCategory J
W X Y Z : TopCat
f : W ⟶ Y
g : X ⟶ Z
x : (forget TopCat).obj (Y ⨯ Z)
x₁ : (forget TopCat).obj W
hx₁ : f x₁ = prod.fst x
x₂ : (forget TopCat).obj X
hx₂ : g x₂ = prod.snd x
⊢ (limit.π (pair Y Z) { as := WalkingPair.right }) ((prod.map f g) ((prodIsoProd W X).inv (x₁, x₂))) =
    (limit.π (pair Y Z) { as := WalkingPair.right }) x

Next tactic:
simp only [← comp_apply, Category.assoc]
theorem range_prod_map {W X Y Z : TopCat.{u}} (f : W ⟶ Y) (g : X ⟶ Z) :
    Set.range (Limits.prod.map f g) =
      (Limits.prod.fst : Y ⨯ Z ⟶ _) ⁻¹' Set.range f ∩
        (Limits.prod.snd : Y ⨯ Z ⟶ _) ⁻¹' Set.range g := by
  ext x
  constructor
  · rintro ⟨y, rfl⟩
    simp only [Set.mem_preimage, Set.mem_range, Set.mem_inter_iff, ← comp_apply]
    simp only [Limits.prod.map_fst, Limits.prod.map_snd, exists_apply_eq_apply, comp_apply,
      and_self_iff]
  · rintro ⟨⟨x₁, hx₁⟩, ⟨x₂, hx₂⟩⟩
    use (prodIsoProd W X).inv (x₁, x₂)
    apply Concrete.limit_ext
    rintro ⟨⟨⟩⟩
    · simp only [← comp_apply, Category.assoc]
      erw [Limits.prod.map_fst]
      rw [TopCat.prodIsoProd_inv_fst_assoc,TopCat.comp_app]
      exact hx₁
    · simp only [← comp_apply, Category.assoc]
      

Proof state:
case h.a.mk.right
J : Type v
inst✝ : SmallCategory J
W X Y Z : TopCat
f : W ⟶ Y
g : X ⟶ Z
x : (forget TopCat).obj (Y ⨯ Z)
x₁ : (forget TopCat).obj W
hx₁ : f x₁ = prod.fst x
x₂ : (forget TopCat).obj X
hx₂ : g x₂ = prod.snd x
⊢ ((prodIsoProd W X).inv ≫ prod.map f g ≫ limit.π (pair Y Z) { as := WalkingPair.right }) (x₁, x₂) =
    (limit.π (pair Y Z) { as := WalkingPair.right }) x

Next tactic:
erw [Limits.prod.map_snd]
theorem range_prod_map {W X Y Z : TopCat.{u}} (f : W ⟶ Y) (g : X ⟶ Z) :
    Set.range (Limits.prod.map f g) =
      (Limits.prod.fst : Y ⨯ Z ⟶ _) ⁻¹' Set.range f ∩
        (Limits.prod.snd : Y ⨯ Z ⟶ _) ⁻¹' Set.range g := by
  ext x
  constructor
  · rintro ⟨y, rfl⟩
    simp only [Set.mem_preimage, Set.mem_range, Set.mem_inter_iff, ← comp_apply]
    simp only [Limits.prod.map_fst, Limits.prod.map_snd, exists_apply_eq_apply, comp_apply,
      and_self_iff]
  · rintro ⟨⟨x₁, hx₁⟩, ⟨x₂, hx₂⟩⟩
    use (prodIsoProd W X).inv (x₁, x₂)
    apply Concrete.limit_ext
    rintro ⟨⟨⟩⟩
    · simp only [← comp_apply, Category.assoc]
      erw [Limits.prod.map_fst]
      rw [TopCat.prodIsoProd_inv_fst_assoc,TopCat.comp_app]
      exact hx₁
    · simp only [← comp_apply, Category.assoc]
      erw [Limits.prod.map_snd]
      

Proof state:
case h.a.mk.right
J : Type v
inst✝ : SmallCategory J
W X Y Z : TopCat
f : W ⟶ Y
g : X ⟶ Z
x : (forget TopCat).obj (Y ⨯ Z)
x₁ : (forget TopCat).obj W
hx₁ : f x₁ = prod.fst x
x₂ : (forget TopCat).obj X
hx₂ : g x₂ = prod.snd x
⊢ ((prodIsoProd W X).inv ≫ prod.snd ≫ g) (x₁, x₂) = (limit.π (pair Y Z) { as := WalkingPair.right }) x

Next tactic:
rw [TopCat.prodIsoProd_inv_snd_assoc,TopCat.comp_app]
theorem range_prod_map {W X Y Z : TopCat.{u}} (f : W ⟶ Y) (g : X ⟶ Z) :
    Set.range (Limits.prod.map f g) =
      (Limits.prod.fst : Y ⨯ Z ⟶ _) ⁻¹' Set.range f ∩
        (Limits.prod.snd : Y ⨯ Z ⟶ _) ⁻¹' Set.range g := by
  ext x
  constructor
  · rintro ⟨y, rfl⟩
    simp only [Set.mem_preimage, Set.mem_range, Set.mem_inter_iff, ← comp_apply]
    simp only [Limits.prod.map_fst, Limits.prod.map_snd, exists_apply_eq_apply, comp_apply,
      and_self_iff]
  · rintro ⟨⟨x₁, hx₁⟩, ⟨x₂, hx₂⟩⟩
    use (prodIsoProd W X).inv (x₁, x₂)
    apply Concrete.limit_ext
    rintro ⟨⟨⟩⟩
    · simp only [← comp_apply, Category.assoc]
      erw [Limits.prod.map_fst]
      rw [TopCat.prodIsoProd_inv_fst_assoc,TopCat.comp_app]
      exact hx₁
    · simp only [← comp_apply, Category.assoc]
      erw [Limits.prod.map_snd]
      rw [TopCat.prodIsoProd_inv_snd_assoc,TopCat.comp_app]
      

Proof state:
case h.a.mk.right
J : Type v
inst✝ : SmallCategory J
W X Y Z : TopCat
f : W ⟶ Y
g : X ⟶ Z
x : (forget TopCat).obj (Y ⨯ Z)
x₁ : (forget TopCat).obj W
hx₁ : f x₁ = prod.fst x
x₂ : (forget TopCat).obj X
hx₂ : g x₂ = prod.snd x
⊢ g (prodSnd (x₁, x₂)) = (limit.π (pair Y Z) { as := WalkingPair.right }) x

Next tactic:
exact hx₂
theorem inducing_prod_map {W X Y Z : TopCat.{u}} {f : W ⟶ X} {g : Y ⟶ Z} (hf : Inducing f)
    (hg : Inducing g) : Inducing (Limits.prod.map f g) := by
  

Proof state:
J : Type v
inst✝ : SmallCategory J
W X Y Z : TopCat
f : W ⟶ X
g : Y ⟶ Z
hf : Inducing ⇑f
hg : Inducing ⇑g
⊢ Inducing ⇑(prod.map f g)

Next tactic:
constructor
theorem inducing_prod_map {W X Y Z : TopCat.{u}} {f : W ⟶ X} {g : Y ⟶ Z} (hf : Inducing f)
    (hg : Inducing g) : Inducing (Limits.prod.map f g) := by
  constructor
  

Proof state:
case induced
J : Type v
inst✝ : SmallCategory J
W X Y Z : TopCat
f : W ⟶ X
g : Y ⟶ Z
hf : Inducing ⇑f
hg : Inducing ⇑g
⊢ topologicalSpace_forget (W ⨯ Y) = induced (⇑(prod.map f g)) (topologicalSpace_forget (X ⨯ Z))

Next tactic:
simp only [prod_topology, induced_compose, ← coe_comp, Limits.prod.map_fst, Limits.prod.map_snd,
    induced_inf]
theorem inducing_prod_map {W X Y Z : TopCat.{u}} {f : W ⟶ X} {g : Y ⟶ Z} (hf : Inducing f)
    (hg : Inducing g) : Inducing (Limits.prod.map f g) := by
  constructor
  simp only [prod_topology, induced_compose, ← coe_comp, Limits.prod.map_fst, Limits.prod.map_snd,
    induced_inf]
  

Proof state:
case induced
J : Type v
inst✝ : SmallCategory J
W X Y Z : TopCat
f : W ⟶ X
g : Y ⟶ Z
hf : Inducing ⇑f
hg : Inducing ⇑g
⊢ induced (⇑prod.fst) W.str ⊓ induced (⇑prod.snd) Y.str =
    induced (⇑(prod.fst ≫ f)) X.str ⊓ induced (⇑(prod.snd ≫ g)) Z.str

Next tactic:
simp only [coe_comp]
theorem inducing_prod_map {W X Y Z : TopCat.{u}} {f : W ⟶ X} {g : Y ⟶ Z} (hf : Inducing f)
    (hg : Inducing g) : Inducing (Limits.prod.map f g) := by
  constructor
  simp only [prod_topology, induced_compose, ← coe_comp, Limits.prod.map_fst, Limits.prod.map_snd,
    induced_inf]
  simp only [coe_comp]
  

Proof state:
case induced
J : Type v
inst✝ : SmallCategory J
W X Y Z : TopCat
f : W ⟶ X
g : Y ⟶ Z
hf : Inducing ⇑f
hg : Inducing ⇑g
⊢ induced (⇑prod.fst) W.str ⊓ induced (⇑prod.snd) Y.str =
    induced (⇑f ∘ ⇑prod.fst) X.str ⊓ induced (⇑g ∘ ⇑prod.snd) Z.str

Next tactic:
rw [← @induced_compose _ _ _ _ _ f, ← @induced_compose _ _ _ _ _ g, ← hf.induced, ← hg.induced]