l3lab/ntp-mathlib huggingface dataset:
theorem det_vandermonde_eq_zero_iff [IsDomain R] {n : ℕ} {v : Fin n → R} :
    det (vandermonde v) = 0 ↔ ∃ i j : Fin n, v i = v j ∧ i ≠ j := by
  constructor
  · simp only [det_vandermonde v, Finset.prod_eq_zero_iff, sub_eq_zero, forall_exists_index]
    rintro i ⟨_, j, h₁, h₂⟩
    exact ⟨j, i, h₂, (mem_Ioi.mp h₁).ne'⟩
  · simp only [Ne.def, forall_exists_index, and_imp]
    refine' fun i j h₁ h₂ => Matrix.det_zero_of_row_eq h₂ (funext fun k => _)
    

Proof state:
case mpr
R : Type u_1
inst✝¹ : CommRing R
inst✝ : IsDomain R
n : ℕ
v : Fin n → R
i j : Fin n
h₁ : v i = v j
h₂ : ¬i = j
k : Fin n
⊢ vandermonde v i k = vandermonde v j k

Next tactic:
rw [vandermonde_apply, vandermonde_apply, h₁]
theorem det_vandermonde_ne_zero_iff [IsDomain R] {n : ℕ} {v : Fin n → R} :
    det (vandermonde v) ≠ 0 ↔ Function.Injective v := by
  

Proof state:
R : Type u_1
inst✝¹ : CommRing R
inst✝ : IsDomain R
n : ℕ
v : Fin n → R
⊢ det (vandermonde v) ≠ 0 ↔ Function.Injective v

Next tactic:
unfold Function.Injective
theorem det_vandermonde_ne_zero_iff [IsDomain R] {n : ℕ} {v : Fin n → R} :
    det (vandermonde v) ≠ 0 ↔ Function.Injective v := by
  unfold Function.Injective
  

Proof state:
R : Type u_1
inst✝¹ : CommRing R
inst✝ : IsDomain R
n : ℕ
v : Fin n → R
⊢ det (vandermonde v) ≠ 0 ↔ ∀ ⦃a₁ a₂ : Fin n⦄, v a₁ = v a₂ → a₁ = a₂

Next tactic:
simp only [det_vandermonde_eq_zero_iff, Ne.def, not_exists, not_and, Classical.not_not]
@[simp]
theorem det_vandermonde_add {n : ℕ} (v : Fin n → R) (a : R) :
    (Matrix.vandermonde fun i ↦ v i + a).det = (Matrix.vandermonde v).det := by
  

Proof state:
R : Type u_1
inst✝ : CommRing R
n : ℕ
v : Fin n → R
a : R
⊢ det (vandermonde fun i => v i + a) = det (vandermonde v)

Next tactic:
simp [Matrix.det_vandermonde]
@[simp]
theorem det_vandermonde_sub {n : ℕ} (v : Fin n → R) (a : R) :
    (Matrix.vandermonde fun i ↦ v i - a).det = (Matrix.vandermonde v).det := by
  

Proof state:
R : Type u_1
inst✝ : CommRing R
n : ℕ
v : Fin n → R
a : R
⊢ det (vandermonde fun i => v i - a) = det (vandermonde v)

Next tactic:
rw [← det_vandermonde_add v (- a)]
@[simp]
theorem det_vandermonde_sub {n : ℕ} (v : Fin n → R) (a : R) :
    (Matrix.vandermonde fun i ↦ v i - a).det = (Matrix.vandermonde v).det := by
  rw [← det_vandermonde_add v (- a)]
  

Proof state:
R : Type u_1
inst✝ : CommRing R
n : ℕ
v : Fin n → R
a : R
⊢ det (vandermonde fun i => v i - a) = det (vandermonde fun i => v i + -a)

Next tactic:
simp only [← sub_eq_add_neg]
theorem eq_zero_of_forall_index_sum_mul_pow_eq_zero {R : Type*} [CommRing R] [IsDomain R] {n : ℕ}
    {f v : Fin n → R} (hf : Function.Injective f) (hfv : ∀ j, (∑ i, v i * f j ^ (i : ℕ)) = 0) :
    v = 0 := by
  

Proof state:
R✝ : Type u_1
inst✝² : CommRing R✝
R : Type u_2
inst✝¹ : CommRing R
inst✝ : IsDomain R
n : ℕ
f v : Fin n → R
hf : Function.Injective f
hfv : ∀ (j : Fin n), ∑ i : Fin n, v i * f j ^ ↑i = 0
⊢ v = 0

Next tactic:
apply eq_zero_of_forall_index_sum_pow_mul_eq_zero hf
theorem eq_zero_of_forall_index_sum_mul_pow_eq_zero {R : Type*} [CommRing R] [IsDomain R] {n : ℕ}
    {f v : Fin n → R} (hf : Function.Injective f) (hfv : ∀ j, (∑ i, v i * f j ^ (i : ℕ)) = 0) :
    v = 0 := by
  apply eq_zero_of_forall_index_sum_pow_mul_eq_zero hf
  

Proof state:
R✝ : Type u_1
inst✝² : CommRing R✝
R : Type u_2
inst✝¹ : CommRing R
inst✝ : IsDomain R
n : ℕ
f v : Fin n → R
hf : Function.Injective f
hfv : ∀ (j : Fin n), ∑ i : Fin n, v i * f j ^ ↑i = 0
⊢ ∀ (j : Fin n), ∑ i : Fin n, f j ^ ↑i * v i = 0

Next tactic:
simp_rw [mul_comm]
theorem eq_zero_of_forall_index_sum_mul_pow_eq_zero {R : Type*} [CommRing R] [IsDomain R] {n : ℕ}
    {f v : Fin n → R} (hf : Function.Injective f) (hfv : ∀ j, (∑ i, v i * f j ^ (i : ℕ)) = 0) :
    v = 0 := by
  apply eq_zero_of_forall_index_sum_pow_mul_eq_zero hf
  simp_rw [mul_comm]
  

Proof state:
R✝ : Type u_1
inst✝² : CommRing R✝
R : Type u_2
inst✝¹ : CommRing R
inst✝ : IsDomain R
n : ℕ
f v : Fin n → R
hf : Function.Injective f
hfv : ∀ (j : Fin n), ∑ i : Fin n, v i * f j ^ ↑i = 0
⊢ ∀ (j : Fin n), ∑ x : Fin n, v x * f j ^ ↑x = 0

Next tactic:
exact hfv
theorem eval_matrixOfPolynomials_eq_vandermonde_mul_matrixOfPolynomials {n : ℕ}
    (v : Fin n → R) (p : Fin n → R[X]) (h_deg : ∀ i, (p i).natDegree ≤ i) :
    Matrix.of (fun i j => ((p j).eval (v i))) =
    (Matrix.vandermonde v) * (Matrix.of (fun (i j : Fin n) => (p j).coeff i)) := by
  

Proof state:
R : Type u_1
inst✝ : CommRing R
n : ℕ
v : Fin n → R
p : Fin n → R[X]
h_deg : ∀ (i : Fin n), natDegree (p i) ≤ ↑i
⊢ (of fun i j => eval (v i) (p j)) = vandermonde v * of fun i j => coeff (p j) ↑i

Next tactic:
ext i j
theorem eval_matrixOfPolynomials_eq_vandermonde_mul_matrixOfPolynomials {n : ℕ}
    (v : Fin n → R) (p : Fin n → R[X]) (h_deg : ∀ i, (p i).natDegree ≤ i) :
    Matrix.of (fun i j => ((p j).eval (v i))) =
    (Matrix.vandermonde v) * (Matrix.of (fun (i j : Fin n) => (p j).coeff i)) := by
  ext i j
  

Proof state:
case a.h
R : Type u_1
inst✝ : CommRing R
n : ℕ
v : Fin n → R
p : Fin n → R[X]
h_deg : ∀ (i : Fin n), natDegree (p i) ≤ ↑i
i j : Fin n
⊢ of (fun i j => eval (v i) (p j)) i j = (vandermonde v * of fun i j => coeff (p j) ↑i) i j

Next tactic:
rw [Matrix.mul_apply, eval, Matrix.of_apply, eval₂]
theorem eval_matrixOfPolynomials_eq_vandermonde_mul_matrixOfPolynomials {n : ℕ}
    (v : Fin n → R) (p : Fin n → R[X]) (h_deg : ∀ i, (p i).natDegree ≤ i) :
    Matrix.of (fun i j => ((p j).eval (v i))) =
    (Matrix.vandermonde v) * (Matrix.of (fun (i j : Fin n) => (p j).coeff i)) := by
  ext i j
  rw [Matrix.mul_apply, eval, Matrix.of_apply, eval₂]
  

Proof state:
case a.h
R : Type u_1
inst✝ : CommRing R
n : ℕ
v : Fin n → R
p : Fin n → R[X]
h_deg : ∀ (i : Fin n), natDegree (p i) ≤ ↑i
i j : Fin n
⊢ (sum (p j) fun e a => (RingHom.id R) a * v i ^ e) =
    ∑ j_1 : Fin n, vandermonde v i j_1 * of (fun i j => coeff (p j) ↑i) j_1 j

Next tactic:
simp only [eq_intCast, Int.cast_id, Matrix.vandermonde]
theorem eval_matrixOfPolynomials_eq_vandermonde_mul_matrixOfPolynomials {n : ℕ}
    (v : Fin n → R) (p : Fin n → R[X]) (h_deg : ∀ i, (p i).natDegree ≤ i) :
    Matrix.of (fun i j => ((p j).eval (v i))) =
    (Matrix.vandermonde v) * (Matrix.of (fun (i j : Fin n) => (p j).coeff i)) := by
  ext i j
  rw [Matrix.mul_apply, eval, Matrix.of_apply, eval₂]
  simp only [eq_intCast, Int.cast_id, Matrix.vandermonde]
  

Proof state:
case a.h
R : Type u_1
inst✝ : CommRing R
n : ℕ
v : Fin n → R
p : Fin n → R[X]
h_deg : ∀ (i : Fin n), natDegree (p i) ≤ ↑i
i j : Fin n
⊢ (sum (p j) fun e a => (RingHom.id R) a * v i ^ e) = ∑ x : Fin n, v i ^ ↑x * of (fun i j => coeff (p j) ↑i) x j

Next tactic:
have : (p j).support ⊆ range n := supp_subset_range <| Nat.lt_of_le_of_lt (h_deg j) <| Fin.prop j
theorem eval_matrixOfPolynomials_eq_vandermonde_mul_matrixOfPolynomials {n : ℕ}
    (v : Fin n → R) (p : Fin n → R[X]) (h_deg : ∀ i, (p i).natDegree ≤ i) :
    Matrix.of (fun i j => ((p j).eval (v i))) =
    (Matrix.vandermonde v) * (Matrix.of (fun (i j : Fin n) => (p j).coeff i)) := by
  ext i j
  rw [Matrix.mul_apply, eval, Matrix.of_apply, eval₂]
  simp only [eq_intCast, Int.cast_id, Matrix.vandermonde]
  have : (p j).support ⊆ range n := supp_subset_range <| Nat.lt_of_le_of_lt (h_deg j) <| Fin.prop j
  

Proof state:
case a.h
R : Type u_1
inst✝ : CommRing R
n : ℕ
v : Fin n → R
p : Fin n → R[X]
h_deg : ∀ (i : Fin n), natDegree (p i) ≤ ↑i
i j : Fin n
this : support (p j) ⊆ range n
⊢ (sum (p j) fun e a => (RingHom.id R) a * v i ^ e) = ∑ x : Fin n, v i ^ ↑x * of (fun i j => coeff (p j) ↑i) x j

Next tactic:
rw [sum_eq_of_subset _ (fun j => zero_mul ((v i) ^ j)) this, ← Fin.sum_univ_eq_sum_range]
theorem eval_matrixOfPolynomials_eq_vandermonde_mul_matrixOfPolynomials {n : ℕ}
    (v : Fin n → R) (p : Fin n → R[X]) (h_deg : ∀ i, (p i).natDegree ≤ i) :
    Matrix.of (fun i j => ((p j).eval (v i))) =
    (Matrix.vandermonde v) * (Matrix.of (fun (i j : Fin n) => (p j).coeff i)) := by
  ext i j
  rw [Matrix.mul_apply, eval, Matrix.of_apply, eval₂]
  simp only [eq_intCast, Int.cast_id, Matrix.vandermonde]
  have : (p j).support ⊆ range n := supp_subset_range <| Nat.lt_of_le_of_lt (h_deg j) <| Fin.prop j
  rw [sum_eq_of_subset _ (fun j => zero_mul ((v i) ^ j)) this, ← Fin.sum_univ_eq_sum_range]
  

Proof state:
case a.h
R : Type u_1
inst✝ : CommRing R
n : ℕ
v : Fin n → R
p : Fin n → R[X]
h_deg : ∀ (i : Fin n), natDegree (p i) ≤ ↑i
i j : Fin n
this : support (p j) ⊆ range n
⊢ ∑ i_1 : Fin n, (RingHom.id R) (coeff (p j) ↑i_1) * v i ^ ↑i_1 =
    ∑ x : Fin n, v i ^ ↑x * of (fun i j => coeff (p j) ↑i) x j

Next tactic:
congr
theorem eval_matrixOfPolynomials_eq_vandermonde_mul_matrixOfPolynomials {n : ℕ}
    (v : Fin n → R) (p : Fin n → R[X]) (h_deg : ∀ i, (p i).natDegree ≤ i) :
    Matrix.of (fun i j => ((p j).eval (v i))) =
    (Matrix.vandermonde v) * (Matrix.of (fun (i j : Fin n) => (p j).coeff i)) := by
  ext i j
  rw [Matrix.mul_apply, eval, Matrix.of_apply, eval₂]
  simp only [eq_intCast, Int.cast_id, Matrix.vandermonde]
  have : (p j).support ⊆ range n := supp_subset_range <| Nat.lt_of_le_of_lt (h_deg j) <| Fin.prop j
  rw [sum_eq_of_subset _ (fun j => zero_mul ((v i) ^ j)) this, ← Fin.sum_univ_eq_sum_range]
  congr
  

Proof state:
case a.h.e_f
R : Type u_1
inst✝ : CommRing R
n : ℕ
v : Fin n → R
p : Fin n → R[X]
h_deg : ∀ (i : Fin n), natDegree (p i) ≤ ↑i
i j : Fin n
this : support (p j) ⊆ range n
⊢ (fun i_1 => (RingHom.id R) (coeff (p j) ↑i_1) * v i ^ ↑i_1) = fun x => v i ^ ↑x * of (fun i j => coeff (p j) ↑i) x j

Next tactic:
ext k
theorem eval_matrixOfPolynomials_eq_vandermonde_mul_matrixOfPolynomials {n : ℕ}
    (v : Fin n → R) (p : Fin n → R[X]) (h_deg : ∀ i, (p i).natDegree ≤ i) :
    Matrix.of (fun i j => ((p j).eval (v i))) =
    (Matrix.vandermonde v) * (Matrix.of (fun (i j : Fin n) => (p j).coeff i)) := by
  ext i j
  rw [Matrix.mul_apply, eval, Matrix.of_apply, eval₂]
  simp only [eq_intCast, Int.cast_id, Matrix.vandermonde]
  have : (p j).support ⊆ range n := supp_subset_range <| Nat.lt_of_le_of_lt (h_deg j) <| Fin.prop j
  rw [sum_eq_of_subset _ (fun j => zero_mul ((v i) ^ j)) this, ← Fin.sum_univ_eq_sum_range]
  congr
  ext k
  

Proof state:
case a.h.e_f.h
R : Type u_1
inst✝ : CommRing R
n : ℕ
v : Fin n → R
p : Fin n → R[X]
h_deg : ∀ (i : Fin n), natDegree (p i) ≤ ↑i
i j : Fin n
this : support (p j) ⊆ range n
k : Fin n
⊢ (RingHom.id R) (coeff (p j) ↑k) * v i ^ ↑k = v i ^ ↑k * of (fun i j => coeff (p j) ↑i) k j

Next tactic:
rw [mul_comm, Matrix.of_apply, RingHom.id_apply]
theorem det_eval_matrixOfPolynomials_eq_det_vandermonde {n : ℕ} (v : Fin n → R) (p : Fin n → R[X])
    (h_deg : ∀ i, (p i).natDegree = i) (h_monic : ∀ i, Monic <| p i) :
    (Matrix.vandermonde v).det = (Matrix.of (fun i j => ((p j).eval (v i)))).det := by
  

Proof state:
R : Type u_1
inst✝ : CommRing R
n : ℕ
v : Fin n → R
p : Fin n → R[X]
h_deg : ∀ (i : Fin n), natDegree (p i) = ↑i
h_monic : ∀ (i : Fin n), Monic (p i)
⊢ det (vandermonde v) = det (of fun i j => eval (v i) (p j))

Next tactic:
rw [Matrix.eval_matrixOfPolynomials_eq_vandermonde_mul_matrixOfPolynomials v p (fun i ↦
      Nat.le_of_eq (h_deg i)), Matrix.det_mul,
      Matrix.det_matrixOfPolynomials p h_deg h_monic, mul_one]
/-- The first projection from the pullback. -/
abbrev pullbackFst (f : X ⟶ Z) (g : Y ⟶ Z) : TopCat.of { p : X × Y // f p.1 = g p.2 } ⟶ X :=
  ⟨Prod.fst ∘ Subtype.val, by 

Proof state:
J : Type v
inst✝ : SmallCategory J
X Y Z : TopCat
f : X ⟶ Z
g : Y ⟶ Z
⊢ Continuous (Prod.fst ∘ Subtype.val)

Next tactic:
apply Continuous.comp
/-- The first projection from the pullback. -/
abbrev pullbackFst (f : X ⟶ Z) (g : Y ⟶ Z) : TopCat.of { p : X × Y // f p.1 = g p.2 } ⟶ X :=
  ⟨Prod.fst ∘ Subtype.val, by apply Continuous.comp <;> 

Proof state:
case hg
J : Type v
inst✝ : SmallCategory J
X Y Z : TopCat
f : X ⟶ Z
g : Y ⟶ Z
⊢ Continuous Prod.fst

Next tactic:
continuity
/-- The first projection from the pullback. -/
abbrev pullbackFst (f : X ⟶ Z) (g : Y ⟶ Z) : TopCat.of { p : X × Y // f p.1 = g p.2 } ⟶ X :=
  ⟨Prod.fst ∘ Subtype.val, by apply Continuous.comp <;> 

Proof state:
case hf
J : Type v
inst✝ : SmallCategory J
X Y Z : TopCat
f : X ⟶ Z
g : Y ⟶ Z
⊢ Continuous Subtype.val

Next tactic:
continuity
/-- The second projection from the pullback. -/
abbrev pullbackSnd (f : X ⟶ Z) (g : Y ⟶ Z) : TopCat.of { p : X × Y // f p.1 = g p.2 } ⟶ Y :=
  ⟨Prod.snd ∘ Subtype.val, by 

Proof state:
J : Type v
inst✝ : SmallCategory J
X Y Z : TopCat
f : X ⟶ Z
g : Y ⟶ Z
⊢ Continuous (Prod.snd ∘ Subtype.val)

Next tactic:
apply Continuous.comp
/-- The second projection from the pullback. -/
abbrev pullbackSnd (f : X ⟶ Z) (g : Y ⟶ Z) : TopCat.of { p : X × Y // f p.1 = g p.2 } ⟶ Y :=
  ⟨Prod.snd ∘ Subtype.val, by apply Continuous.comp <;> 

Proof state:
case hg
J : Type v
inst✝ : SmallCategory J
X Y Z : TopCat
f : X ⟶ Z
g : Y ⟶ Z
⊢ Continuous Prod.snd

Next tactic:
continuity
/-- The second projection from the pullback. -/
abbrev pullbackSnd (f : X ⟶ Z) (g : Y ⟶ Z) : TopCat.of { p : X × Y // f p.1 = g p.2 } ⟶ Y :=
  ⟨Prod.snd ∘ Subtype.val, by apply Continuous.comp <;> 

Proof state:
case hf
J : Type v
inst✝ : SmallCategory J
X Y Z : TopCat
f : X ⟶ Z
g : Y ⟶ Z
⊢ Continuous Subtype.val

Next tactic:
continuity
/-- The explicit pullback cone of `X, Y` given by `{ p : X × Y // f p.1 = g p.2 }`. -/
def pullbackCone (f : X ⟶ Z) (g : Y ⟶ Z) : PullbackCone f g :=
  PullbackCone.mk (pullbackFst f g) (pullbackSnd f g)
    (by
      

Proof state:
J : Type v
inst✝ : SmallCategory J
X Y Z : TopCat
f : X ⟶ Z
g : Y ⟶ Z
⊢ pullbackFst f g ≫ f = pullbackSnd f g ≫ g

Next tactic:
dsimp [pullbackFst, pullbackSnd, Function.comp_def]
/-- The explicit pullback cone of `X, Y` given by `{ p : X × Y // f p.1 = g p.2 }`. -/
def pullbackCone (f : X ⟶ Z) (g : Y ⟶ Z) : PullbackCone f g :=
  PullbackCone.mk (pullbackFst f g) (pullbackSnd f g)
    (by
      dsimp [pullbackFst, pullbackSnd, Function.comp_def]
      

Proof state:
J : Type v
inst✝ : SmallCategory J
X Y Z : TopCat
f : X ⟶ Z
g : Y ⟶ Z
⊢ (ContinuousMap.mk fun x => (↑x).1) ≫ f = (ContinuousMap.mk fun x => (↑x).2) ≫ g

Next tactic:
ext ⟨x, h⟩
/-- The explicit pullback cone of `X, Y` given by `{ p : X × Y // f p.1 = g p.2 }`. -/
def pullbackCone (f : X ⟶ Z) (g : Y ⟶ Z) : PullbackCone f g :=
  PullbackCone.mk (pullbackFst f g) (pullbackSnd f g)
    (by
      dsimp [pullbackFst, pullbackSnd, Function.comp_def]
      ext ⟨x, h⟩
      -- Next 2 lines were
      -- `rw [comp_apply, ContinuousMap.coe_mk, comp_apply, ContinuousMap.coe_mk]`
      -- `exact h` before leanprover/lean4#2644
      

Proof state:
case w.mk
J : Type v
inst✝ : SmallCategory J
X Y Z : TopCat
f : X ⟶ Z
g : Y ⟶ Z
x : ↑X × ↑Y
h : f x.1 = g x.2
⊢ ((ContinuousMap.mk fun x => (↑x).1) ≫ f) { val := x, property := h } =
    ((ContinuousMap.mk fun x => (↑x).2) ≫ g) { val := x, property := h }

Next tactic:
rw [comp_apply, comp_apply]
/-- The explicit pullback cone of `X, Y` given by `{ p : X × Y // f p.1 = g p.2 }`. -/
def pullbackCone (f : X ⟶ Z) (g : Y ⟶ Z) : PullbackCone f g :=
  PullbackCone.mk (pullbackFst f g) (pullbackSnd f g)
    (by
      dsimp [pullbackFst, pullbackSnd, Function.comp_def]
      ext ⟨x, h⟩
      -- Next 2 lines were
      -- `rw [comp_apply, ContinuousMap.coe_mk, comp_apply, ContinuousMap.coe_mk]`
      -- `exact h` before leanprover/lean4#2644
      rw [comp_apply, comp_apply]
      

Proof state:
case w.mk
J : Type v
inst✝ : SmallCategory J
X Y Z : TopCat
f : X ⟶ Z
g : Y ⟶ Z
x : ↑X × ↑Y
h : f x.1 = g x.2
⊢ f ((ContinuousMap.mk fun x => (↑x).1) { val := x, property := h }) =
    g ((ContinuousMap.mk fun x => (↑x).2) { val := x, property := h })

Next tactic:
congr!
/-- The constructed cone is a limit. -/
def pullbackConeIsLimit (f : X ⟶ Z) (g : Y ⟶ Z) : IsLimit (pullbackCone f g) :=
  PullbackCone.isLimitAux' _
    (by
      

Proof state:
J : Type v
inst✝ : SmallCategory J
X Y Z : TopCat
f : X ⟶ Z
g : Y ⟶ Z
⊢ (s : PullbackCone f g) →
    { l //
      l ≫ PullbackCone.fst (pullbackCone f g) = PullbackCone.fst s ∧
        l ≫ PullbackCone.snd (pullbackCone f g) = PullbackCone.snd s ∧
          ∀ {m : s.pt ⟶ (pullbackCone f g).pt},
            m ≫ PullbackCone.fst (pullbackCone f g) = PullbackCone.fst s →
              m ≫ PullbackCone.snd (pullbackCone f g) = PullbackCone.snd s → m = l }

Next tactic:
intro S
/-- The constructed cone is a limit. -/
def pullbackConeIsLimit (f : X ⟶ Z) (g : Y ⟶ Z) : IsLimit (pullbackCone f g) :=
  PullbackCone.isLimitAux' _
    (by
      intro S
      

Proof state:
J : Type v
inst✝ : SmallCategory J
X Y Z : TopCat
f : X ⟶ Z
g : Y ⟶ Z
S : PullbackCone f g
⊢ { l //
    l ≫ PullbackCone.fst (pullbackCone f g) = PullbackCone.fst S ∧
      l ≫ PullbackCone.snd (pullbackCone f g) = PullbackCone.snd S ∧
        ∀ {m : S.pt ⟶ (pullbackCone f g).pt},
          m ≫ PullbackCone.fst (pullbackCone f g) = PullbackCone.fst S →
            m ≫ PullbackCone.snd (pullbackCone f g) = PullbackCone.snd S → m = l }

Next tactic:
constructor
/-- The constructed cone is a limit. -/
def pullbackConeIsLimit (f : X ⟶ Z) (g : Y ⟶ Z) : IsLimit (pullbackCone f g) :=
  PullbackCone.isLimitAux' _
    (by
      intro S
      constructor; 

Proof state:
case property
J : Type v
inst✝ : SmallCategory J
X Y Z : TopCat
f : X ⟶ Z
g : Y ⟶ Z
S : PullbackCone f g
⊢ ?val ≫ PullbackCone.fst (pullbackCone f g) = PullbackCone.fst S ∧
    ?val ≫ PullbackCone.snd (pullbackCone f g) = PullbackCone.snd S ∧
      ∀ {m : S.pt ⟶ (pullbackCone f g).pt},
        m ≫ PullbackCone.fst (pullbackCone f g) = PullbackCone.fst S →
          m ≫ PullbackCone.snd (pullbackCone f g) = PullbackCone.snd S → m = ?val
case val
J : Type v
inst✝ : SmallCategory J
X Y Z : TopCat
f : X ⟶ Z
g : Y ⟶ Z
S : PullbackCone f g
⊢ S.pt ⟶ (pullbackCone f g).pt

Next tactic:
swap
/-- The constructed cone is a limit. -/
def pullbackConeIsLimit (f : X ⟶ Z) (g : Y ⟶ Z) : IsLimit (pullbackCone f g) :=
  PullbackCone.isLimitAux' _
    (by
      intro S
      constructor; swap
      

Proof state:
case val
J : Type v
inst✝ : SmallCategory J
X Y Z : TopCat
f : X ⟶ Z
g : Y ⟶ Z
S : PullbackCone f g
⊢ S.pt ⟶ (pullbackCone f g).pt
case property
J : Type v
inst✝ : SmallCategory J
X Y Z : TopCat
f : X ⟶ Z
g : Y ⟶ Z
S : PullbackCone f g
⊢ ?val ≫ PullbackCone.fst (pullbackCone f g) = PullbackCone.fst S ∧
    ?val ≫ PullbackCone.snd (pullbackCone f g) = PullbackCone.snd S ∧
      ∀ {m : S.pt ⟶ (pullbackCone f g).pt},
        m ≫ PullbackCone.fst (pullbackCone f g) = PullbackCone.fst S →
          m ≫ PullbackCone.snd (pullbackCone f g) = PullbackCone.snd S → m = ?val

Next tactic:
exact
        { toFun := fun x =>
            ⟨⟨S.fst x, S.snd x⟩, by simpa using ConcreteCategory.congr_hom S.condition x⟩
          continuous_toFun := by
            apply Continuous.subtype_mk <| Continuous.prod_mk ?_ ?_
            · exact (PullbackCone.fst S)|>.continuous_toFun
            · exact (PullbackCone.snd S)|>.continuous_toFun
        }
/-- The constructed cone is a limit. -/
def pullbackConeIsLimit (f : X ⟶ Z) (g : Y ⟶ Z) : IsLimit (pullbackCone f g) :=
  PullbackCone.isLimitAux' _
    (by
      intro S
      constructor; swap
      exact
        { toFun := fun x =>
            ⟨⟨S.fst x, S.snd x⟩, by 

Proof state:
J : Type v
inst✝ : SmallCategory J
X Y Z : TopCat
f : X ⟶ Z
g : Y ⟶ Z
S : PullbackCone f g
x : ↑S.pt
⊢ f ((PullbackCone.fst S) x, (PullbackCone.snd S) x).1 = g ((PullbackCone.fst S) x, (PullbackCone.snd S) x).2

Next tactic:
simpa using ConcreteCategory.congr_hom S.condition x
/-- The constructed cone is a limit. -/
def pullbackConeIsLimit (f : X ⟶ Z) (g : Y ⟶ Z) : IsLimit (pullbackCone f g) :=
  PullbackCone.isLimitAux' _
    (by
      intro S
      constructor; swap
      exact
        { toFun := fun x =>
            ⟨⟨S.fst x, S.snd x⟩, by simpa using ConcreteCategory.congr_hom S.condition x⟩
          continuous_toFun := by
            

Proof state:
J : Type v
inst✝ : SmallCategory J
X Y Z : TopCat
f : X ⟶ Z
g : Y ⟶ Z
S : PullbackCone f g
⊢ Continuous fun x =>
    { val := ((PullbackCone.fst S) x, (PullbackCone.snd S) x),
      property :=
        (_ :
          f ((PullbackCone.fst S) x, (PullbackCone.snd S) x).1 = g ((PullbackCone.fst S) x, (PullbackCone.snd S) x).2) }

Next tactic:
apply Continuous.subtype_mk <| Continuous.prod_mk ?_ ?_
/-- The constructed cone is a limit. -/
def pullbackConeIsLimit (f : X ⟶ Z) (g : Y ⟶ Z) : IsLimit (pullbackCone f g) :=
  PullbackCone.isLimitAux' _
    (by
      intro S
      constructor; swap
      exact
        { toFun := fun x =>
            ⟨⟨S.fst x, S.snd x⟩, by simpa using ConcreteCategory.congr_hom S.condition x⟩
          continuous_toFun := by
            apply Continuous.subtype_mk <| Continuous.prod_mk ?_ ?_
            · 

Proof state:
J : Type v
inst✝ : SmallCategory J
X Y Z : TopCat
f : X ⟶ Z
g : Y ⟶ Z
S : PullbackCone f g
⊢ Continuous fun x => (PullbackCone.fst S) x

Next tactic:
exact (PullbackCone.fst S)|>.continuous_toFun
/-- The constructed cone is a limit. -/
def pullbackConeIsLimit (f : X ⟶ Z) (g : Y ⟶ Z) : IsLimit (pullbackCone f g) :=
  PullbackCone.isLimitAux' _
    (by
      intro S
      constructor; swap
      exact
        { toFun := fun x =>
            ⟨⟨S.fst x, S.snd x⟩, by simpa using ConcreteCategory.congr_hom S.condition x⟩
          continuous_toFun := by
            apply Continuous.subtype_mk <| Continuous.prod_mk ?_ ?_
            · exact (PullbackCone.fst S)|>.continuous_toFun
            · 

Proof state:
J : Type v
inst✝ : SmallCategory J
X Y Z : TopCat
f : X ⟶ Z
g : Y ⟶ Z
S : PullbackCone f g
⊢ Continuous fun x => (PullbackCone.snd S) x

Next tactic:
exact (PullbackCone.snd S)|>.continuous_toFun
/-- The constructed cone is a limit. -/
def pullbackConeIsLimit (f : X ⟶ Z) (g : Y ⟶ Z) : IsLimit (pullbackCone f g) :=
  PullbackCone.isLimitAux' _
    (by
      intro S
      constructor; swap
      exact
        { toFun := fun x =>
            ⟨⟨S.fst x, S.snd x⟩, by simpa using ConcreteCategory.congr_hom S.condition x⟩
          continuous_toFun := by
            apply Continuous.subtype_mk <| Continuous.prod_mk ?_ ?_
            · exact (PullbackCone.fst S)|>.continuous_toFun
            · exact (PullbackCone.snd S)|>.continuous_toFun
        }
      

Proof state:
case property
J : Type v
inst✝ : SmallCategory J
X Y Z : TopCat
f : X ⟶ Z
g : Y ⟶ Z
S : PullbackCone f g
⊢ (ContinuousMap.mk fun x =>
          { val := ((PullbackCone.fst S) x, (PullbackCone.snd S) x),
            property :=
              (_ :
                f ((PullbackCone.fst S) x, (PullbackCone.snd S) x).1 =
                  g ((PullbackCone.fst S) x, (PullbackCone.snd S) x).2) }) ≫
        PullbackCone.fst (pullbackCone f g) =
      PullbackCone.fst S ∧
    (ContinuousMap.mk fun x =>
            { val := ((PullbackCone.fst S) x, (PullbackCone.snd S) x),
              property :=
                (_ :
                  f ((PullbackCone.fst S) x, (PullbackCone.snd S) x).1 =
                    g ((PullbackCone.fst S) x, (PullbackCone.snd S) x).2) }) ≫
          PullbackCone.snd (pullbackCone f g) =
        PullbackCone.snd S ∧
      ∀ {m : S.pt ⟶ (pullbackCone f g).pt},
        m ≫ PullbackCone.fst (pullbackCone f g) = PullbackCone.fst S →
          m ≫ PullbackCone.snd (pullbackCone f g) = PullbackCone.snd S →
            m =
              ContinuousMap.mk fun x =>
                { val := ((PullbackCone.fst S) x, (PullbackCone.snd S) x),
                  property :=
                    (_ :
                      f ((PullbackCone.fst S) x, (PullbackCone.snd S) x).1 =
                        g ((PullbackCone.fst S) x, (PullbackCone.snd S) x).2) }

Next tactic:
refine' ⟨_, _, _⟩