l3lab/ntp-mathlib huggingface dataset:
theorem matPolyEquiv_charmatrix (M : Matrix n n R) : matPolyEquiv (charmatrix M) = X - C M := by
  ext k i j
  simp only [matPolyEquiv_coeff_apply, coeff_sub, Pi.sub_apply]
  by_cases h : i = j
  · subst h
    rw [charmatrix_apply_eq, coeff_sub]
    simp only [coeff_X, coeff_C]
    split_ifs <;> simp
  · 

Proof state:
case neg
R : Type u
inst✝² : CommRing R
n : Type w
inst✝¹ : DecidableEq n
inst✝ : Fintype n
M : Matrix n n R
k : ℕ
i j : n
h : ¬i = j
⊢ coeff (charmatrix M i j) k = (coeff X k - coeff (C M) k) i j

Next tactic:
rw [charmatrix_apply_ne _ _ _ h, coeff_X, coeff_neg, coeff_C, coeff_C]
theorem matPolyEquiv_charmatrix (M : Matrix n n R) : matPolyEquiv (charmatrix M) = X - C M := by
  ext k i j
  simp only [matPolyEquiv_coeff_apply, coeff_sub, Pi.sub_apply]
  by_cases h : i = j
  · subst h
    rw [charmatrix_apply_eq, coeff_sub]
    simp only [coeff_X, coeff_C]
    split_ifs <;> simp
  · rw [charmatrix_apply_ne _ _ _ h, coeff_X, coeff_neg, coeff_C, coeff_C]
    

Proof state:
case neg
R : Type u
inst✝² : CommRing R
n : Type w
inst✝¹ : DecidableEq n
inst✝ : Fintype n
M : Matrix n n R
k : ℕ
i j : n
h : ¬i = j
⊢ (-if k = 0 then M i j else 0) = ((if 1 = k then 1 else 0) - if k = 0 then M else 0) i j

Next tactic:
split_ifs
theorem matPolyEquiv_charmatrix (M : Matrix n n R) : matPolyEquiv (charmatrix M) = X - C M := by
  ext k i j
  simp only [matPolyEquiv_coeff_apply, coeff_sub, Pi.sub_apply]
  by_cases h : i = j
  · subst h
    rw [charmatrix_apply_eq, coeff_sub]
    simp only [coeff_X, coeff_C]
    split_ifs <;> simp
  · rw [charmatrix_apply_ne _ _ _ h, coeff_X, coeff_neg, coeff_C, coeff_C]
    split_ifs <;> 

Proof state:
case pos
R : Type u
inst✝² : CommRing R
n : Type w
inst✝¹ : DecidableEq n
inst✝ : Fintype n
M : Matrix n n R
k : ℕ
i j : n
h : ¬i = j
h✝¹ : k = 0
h✝ : 1 = k
⊢ -M i j = (1 - M) i j

Next tactic:
simp [h]
theorem matPolyEquiv_charmatrix (M : Matrix n n R) : matPolyEquiv (charmatrix M) = X - C M := by
  ext k i j
  simp only [matPolyEquiv_coeff_apply, coeff_sub, Pi.sub_apply]
  by_cases h : i = j
  · subst h
    rw [charmatrix_apply_eq, coeff_sub]
    simp only [coeff_X, coeff_C]
    split_ifs <;> simp
  · rw [charmatrix_apply_ne _ _ _ h, coeff_X, coeff_neg, coeff_C, coeff_C]
    split_ifs <;> 

Proof state:
case neg
R : Type u
inst✝² : CommRing R
n : Type w
inst✝¹ : DecidableEq n
inst✝ : Fintype n
M : Matrix n n R
k : ℕ
i j : n
h : ¬i = j
h✝¹ : k = 0
h✝ : ¬1 = k
⊢ -M i j = (0 - M) i j

Next tactic:
simp [h]
theorem matPolyEquiv_charmatrix (M : Matrix n n R) : matPolyEquiv (charmatrix M) = X - C M := by
  ext k i j
  simp only [matPolyEquiv_coeff_apply, coeff_sub, Pi.sub_apply]
  by_cases h : i = j
  · subst h
    rw [charmatrix_apply_eq, coeff_sub]
    simp only [coeff_X, coeff_C]
    split_ifs <;> simp
  · rw [charmatrix_apply_ne _ _ _ h, coeff_X, coeff_neg, coeff_C, coeff_C]
    split_ifs <;> 

Proof state:
case pos
R : Type u
inst✝² : CommRing R
n : Type w
inst✝¹ : DecidableEq n
inst✝ : Fintype n
M : Matrix n n R
k : ℕ
i j : n
h : ¬i = j
h✝¹ : ¬k = 0
h✝ : 1 = k
⊢ -0 = (1 - 0) i j

Next tactic:
simp [h]
theorem matPolyEquiv_charmatrix (M : Matrix n n R) : matPolyEquiv (charmatrix M) = X - C M := by
  ext k i j
  simp only [matPolyEquiv_coeff_apply, coeff_sub, Pi.sub_apply]
  by_cases h : i = j
  · subst h
    rw [charmatrix_apply_eq, coeff_sub]
    simp only [coeff_X, coeff_C]
    split_ifs <;> simp
  · rw [charmatrix_apply_ne _ _ _ h, coeff_X, coeff_neg, coeff_C, coeff_C]
    split_ifs <;> 

Proof state:
case neg
R : Type u
inst✝² : CommRing R
n : Type w
inst✝¹ : DecidableEq n
inst✝ : Fintype n
M : Matrix n n R
k : ℕ
i j : n
h : ¬i = j
h✝¹ : ¬k = 0
h✝ : ¬1 = k
⊢ -0 = (0 - 0) i j

Next tactic:
simp [h]
theorem charmatrix_reindex {m : Type v} [DecidableEq m] [Fintype m] (e : n ≃ m) (M : Matrix n n R) :
    charmatrix (reindex e e M) = reindex e e (charmatrix M) := by
  

Proof state:
R : Type u
inst✝⁴ : CommRing R
n : Type w
inst✝³ : DecidableEq n
inst✝² : Fintype n
m : Type v
inst✝¹ : DecidableEq m
inst✝ : Fintype m
e : n ≃ m
M : Matrix n n R
⊢ charmatrix ((reindex e e) M) = (reindex e e) (charmatrix M)

Next tactic:
ext i j x
theorem charmatrix_reindex {m : Type v} [DecidableEq m] [Fintype m] (e : n ≃ m) (M : Matrix n n R) :
    charmatrix (reindex e e M) = reindex e e (charmatrix M) := by
  ext i j x
  

Proof state:
case a.h.a
R : Type u
inst✝⁴ : CommRing R
n : Type w
inst✝³ : DecidableEq n
inst✝² : Fintype n
m : Type v
inst✝¹ : DecidableEq m
inst✝ : Fintype m
e : n ≃ m
M : Matrix n n R
i j : m
x : ℕ
⊢ coeff (charmatrix ((reindex e e) M) i j) x = coeff ((reindex e e) (charmatrix M) i j) x

Next tactic:
by_cases h : i = j
theorem charmatrix_reindex {m : Type v} [DecidableEq m] [Fintype m] (e : n ≃ m) (M : Matrix n n R) :
    charmatrix (reindex e e M) = reindex e e (charmatrix M) := by
  ext i j x
  by_cases h : i = j
  

Proof state:
case pos
R : Type u
inst✝⁴ : CommRing R
n : Type w
inst✝³ : DecidableEq n
inst✝² : Fintype n
m : Type v
inst✝¹ : DecidableEq m
inst✝ : Fintype m
e : n ≃ m
M : Matrix n n R
i j : m
x : ℕ
h : i = j
⊢ coeff (charmatrix ((reindex e e) M) i j) x = coeff ((reindex e e) (charmatrix M) i j) x
case neg
R : Type u
inst✝⁴ : CommRing R
n : Type w
inst✝³ : DecidableEq n
inst✝² : Fintype n
m : Type v
inst✝¹ : DecidableEq m
inst✝ : Fintype m
e : n ≃ m
M : Matrix n n R
i j : m
x : ℕ
h : ¬i = j
⊢ coeff (charmatrix ((reindex e e) M) i j) x = coeff ((reindex e e) (charmatrix M) i j) x

Next tactic:
all_goals simp [h]
theorem charmatrix_reindex {m : Type v} [DecidableEq m] [Fintype m] (e : n ≃ m) (M : Matrix n n R) :
    charmatrix (reindex e e M) = reindex e e (charmatrix M) := by
  ext i j x
  by_cases h : i = j
  all_goals 

Proof state:
case pos
R : Type u
inst✝⁴ : CommRing R
n : Type w
inst✝³ : DecidableEq n
inst✝² : Fintype n
m : Type v
inst✝¹ : DecidableEq m
inst✝ : Fintype m
e : n ≃ m
M : Matrix n n R
i j : m
x : ℕ
h : i = j
⊢ coeff (charmatrix ((reindex e e) M) i j) x = coeff ((reindex e e) (charmatrix M) i j) x

Next tactic:
simp [h]
theorem charmatrix_reindex {m : Type v} [DecidableEq m] [Fintype m] (e : n ≃ m) (M : Matrix n n R) :
    charmatrix (reindex e e M) = reindex e e (charmatrix M) := by
  ext i j x
  by_cases h : i = j
  all_goals 

Proof state:
case neg
R : Type u
inst✝⁴ : CommRing R
n : Type w
inst✝³ : DecidableEq n
inst✝² : Fintype n
m : Type v
inst✝¹ : DecidableEq m
inst✝ : Fintype m
e : n ≃ m
M : Matrix n n R
i j : m
x : ℕ
h : ¬i = j
⊢ coeff (charmatrix ((reindex e e) M) i j) x = coeff ((reindex e e) (charmatrix M) i j) x

Next tactic:
simp [h]
theorem Matrix.charpoly_reindex {m : Type v} [DecidableEq m] [Fintype m] (e : n ≃ m)
    (M : Matrix n n R) : (reindex e e M).charpoly = M.charpoly := by
  

Proof state:
R : Type u
inst✝⁴ : CommRing R
n : Type w
inst✝³ : DecidableEq n
inst✝² : Fintype n
m : Type v
inst✝¹ : DecidableEq m
inst✝ : Fintype m
e : n ≃ m
M : Matrix n n R
⊢ charpoly ((reindex e e) M) = charpoly M

Next tactic:
unfold Matrix.charpoly
theorem Matrix.charpoly_reindex {m : Type v} [DecidableEq m] [Fintype m] (e : n ≃ m)
    (M : Matrix n n R) : (reindex e e M).charpoly = M.charpoly := by
  unfold Matrix.charpoly
  

Proof state:
R : Type u
inst✝⁴ : CommRing R
n : Type w
inst✝³ : DecidableEq n
inst✝² : Fintype n
m : Type v
inst✝¹ : DecidableEq m
inst✝ : Fintype m
e : n ≃ m
M : Matrix n n R
⊢ det (charmatrix ((reindex e e) M)) = det (charmatrix M)

Next tactic:
rw [charmatrix_reindex, Matrix.det_reindex_self]
/-- The **Cayley-Hamilton Theorem**, that the characteristic polynomial of a matrix,
applied to the matrix itself, is zero.

This holds over any commutative ring.

See `LinearMap.aeval_self_charpoly` for the equivalent statement about endomorphisms.
-/
theorem Matrix.aeval_self_charpoly (M : Matrix n n R) : aeval M M.charpoly = 0 := by
  -- We begin with the fact $χ_M(t) I = adjugate (t I - M) * (t I - M)$,
  -- as an identity in `Matrix n n R[X]`.
  

Proof state:
R : Type u
inst✝² : CommRing R
n : Type w
inst✝¹ : DecidableEq n
inst✝ : Fintype n
M : Matrix n n R
⊢ (aeval M) (charpoly M) = 0

Next tactic:
have h : M.charpoly • (1 : Matrix n n R[X]) = adjugate (charmatrix M) * charmatrix M :=
    (adjugate_mul _).symm
/-- The **Cayley-Hamilton Theorem**, that the characteristic polynomial of a matrix,
applied to the matrix itself, is zero.

This holds over any commutative ring.

See `LinearMap.aeval_self_charpoly` for the equivalent statement about endomorphisms.
-/
theorem Matrix.aeval_self_charpoly (M : Matrix n n R) : aeval M M.charpoly = 0 := by
  -- We begin with the fact $χ_M(t) I = adjugate (t I - M) * (t I - M)$,
  -- as an identity in `Matrix n n R[X]`.
  have h : M.charpoly • (1 : Matrix n n R[X]) = adjugate (charmatrix M) * charmatrix M :=
    (adjugate_mul _).symm
  -- Using the algebra isomorphism `Matrix n n R[X] ≃ₐ[R] Polynomial (Matrix n n R)`,
  -- we have the same identity in `Polynomial (Matrix n n R)`.
  

Proof state:
R : Type u
inst✝² : CommRing R
n : Type w
inst✝¹ : DecidableEq n
inst✝ : Fintype n
M : Matrix n n R
h : charpoly M • 1 = adjugate (charmatrix M) * charmatrix M
⊢ (aeval M) (charpoly M) = 0

Next tactic:
apply_fun matPolyEquiv at h
/-- The **Cayley-Hamilton Theorem**, that the characteristic polynomial of a matrix,
applied to the matrix itself, is zero.

This holds over any commutative ring.

See `LinearMap.aeval_self_charpoly` for the equivalent statement about endomorphisms.
-/
theorem Matrix.aeval_self_charpoly (M : Matrix n n R) : aeval M M.charpoly = 0 := by
  -- We begin with the fact $χ_M(t) I = adjugate (t I - M) * (t I - M)$,
  -- as an identity in `Matrix n n R[X]`.
  have h : M.charpoly • (1 : Matrix n n R[X]) = adjugate (charmatrix M) * charmatrix M :=
    (adjugate_mul _).symm
  -- Using the algebra isomorphism `Matrix n n R[X] ≃ₐ[R] Polynomial (Matrix n n R)`,
  -- we have the same identity in `Polynomial (Matrix n n R)`.
  apply_fun matPolyEquiv at h
  

Proof state:
R : Type u
inst✝² : CommRing R
n : Type w
inst✝¹ : DecidableEq n
inst✝ : Fintype n
M : Matrix n n R
h : matPolyEquiv (charpoly M • 1) = matPolyEquiv (adjugate (charmatrix M) * charmatrix M)
⊢ (aeval M) (charpoly M) = 0

Next tactic:
simp only [matPolyEquiv.map_mul, matPolyEquiv_charmatrix] at h
/-- The **Cayley-Hamilton Theorem**, that the characteristic polynomial of a matrix,
applied to the matrix itself, is zero.

This holds over any commutative ring.

See `LinearMap.aeval_self_charpoly` for the equivalent statement about endomorphisms.
-/
theorem Matrix.aeval_self_charpoly (M : Matrix n n R) : aeval M M.charpoly = 0 := by
  -- We begin with the fact $χ_M(t) I = adjugate (t I - M) * (t I - M)$,
  -- as an identity in `Matrix n n R[X]`.
  have h : M.charpoly • (1 : Matrix n n R[X]) = adjugate (charmatrix M) * charmatrix M :=
    (adjugate_mul _).symm
  -- Using the algebra isomorphism `Matrix n n R[X] ≃ₐ[R] Polynomial (Matrix n n R)`,
  -- we have the same identity in `Polynomial (Matrix n n R)`.
  apply_fun matPolyEquiv at h
  simp only [matPolyEquiv.map_mul, matPolyEquiv_charmatrix] at h
  -- Because the coefficient ring `Matrix n n R` is non-commutative,
  -- evaluation at `M` is not multiplicative.
  -- However, any polynomial which is a product of the form $N * (t I - M)$
  -- is sent to zero, because the evaluation function puts the polynomial variable
  -- to the right of any coefficients, so everything telescopes.
  

Proof state:
R : Type u
inst✝² : CommRing R
n : Type w
inst✝¹ : DecidableEq n
inst✝ : Fintype n
M : Matrix n n R
h : matPolyEquiv (charpoly M • 1) = matPolyEquiv (adjugate (charmatrix M)) * (X - C M)
⊢ (aeval M) (charpoly M) = 0

Next tactic:
apply_fun fun p => p.eval M at h
/-- The **Cayley-Hamilton Theorem**, that the characteristic polynomial of a matrix,
applied to the matrix itself, is zero.

This holds over any commutative ring.

See `LinearMap.aeval_self_charpoly` for the equivalent statement about endomorphisms.
-/
theorem Matrix.aeval_self_charpoly (M : Matrix n n R) : aeval M M.charpoly = 0 := by
  -- We begin with the fact $χ_M(t) I = adjugate (t I - M) * (t I - M)$,
  -- as an identity in `Matrix n n R[X]`.
  have h : M.charpoly • (1 : Matrix n n R[X]) = adjugate (charmatrix M) * charmatrix M :=
    (adjugate_mul _).symm
  -- Using the algebra isomorphism `Matrix n n R[X] ≃ₐ[R] Polynomial (Matrix n n R)`,
  -- we have the same identity in `Polynomial (Matrix n n R)`.
  apply_fun matPolyEquiv at h
  simp only [matPolyEquiv.map_mul, matPolyEquiv_charmatrix] at h
  -- Because the coefficient ring `Matrix n n R` is non-commutative,
  -- evaluation at `M` is not multiplicative.
  -- However, any polynomial which is a product of the form $N * (t I - M)$
  -- is sent to zero, because the evaluation function puts the polynomial variable
  -- to the right of any coefficients, so everything telescopes.
  apply_fun fun p => p.eval M at h
  

Proof state:
R : Type u
inst✝² : CommRing R
n : Type w
inst✝¹ : DecidableEq n
inst✝ : Fintype n
M : Matrix n n R
h : eval M (matPolyEquiv (charpoly M • 1)) = eval M (matPolyEquiv (adjugate (charmatrix M)) * (X - C M))
⊢ (aeval M) (charpoly M) = 0

Next tactic:
rw [eval_mul_X_sub_C] at h
/-- The **Cayley-Hamilton Theorem**, that the characteristic polynomial of a matrix,
applied to the matrix itself, is zero.

This holds over any commutative ring.

See `LinearMap.aeval_self_charpoly` for the equivalent statement about endomorphisms.
-/
theorem Matrix.aeval_self_charpoly (M : Matrix n n R) : aeval M M.charpoly = 0 := by
  -- We begin with the fact $χ_M(t) I = adjugate (t I - M) * (t I - M)$,
  -- as an identity in `Matrix n n R[X]`.
  have h : M.charpoly • (1 : Matrix n n R[X]) = adjugate (charmatrix M) * charmatrix M :=
    (adjugate_mul _).symm
  -- Using the algebra isomorphism `Matrix n n R[X] ≃ₐ[R] Polynomial (Matrix n n R)`,
  -- we have the same identity in `Polynomial (Matrix n n R)`.
  apply_fun matPolyEquiv at h
  simp only [matPolyEquiv.map_mul, matPolyEquiv_charmatrix] at h
  -- Because the coefficient ring `Matrix n n R` is non-commutative,
  -- evaluation at `M` is not multiplicative.
  -- However, any polynomial which is a product of the form $N * (t I - M)$
  -- is sent to zero, because the evaluation function puts the polynomial variable
  -- to the right of any coefficients, so everything telescopes.
  apply_fun fun p => p.eval M at h
  rw [eval_mul_X_sub_C] at h
  -- Now $χ_M (t) I$, when thought of as a polynomial of matrices
  -- and evaluated at some `N` is exactly $χ_M (N)$.
  

Proof state:
R : Type u
inst✝² : CommRing R
n : Type w
inst✝¹ : DecidableEq n
inst✝ : Fintype n
M : Matrix n n R
h : eval M (matPolyEquiv (charpoly M • 1)) = 0
⊢ (aeval M) (charpoly M) = 0

Next tactic:
rw [matPolyEquiv_smul_one, eval_map] at h
/-- The **Cayley-Hamilton Theorem**, that the characteristic polynomial of a matrix,
applied to the matrix itself, is zero.

This holds over any commutative ring.

See `LinearMap.aeval_self_charpoly` for the equivalent statement about endomorphisms.
-/
theorem Matrix.aeval_self_charpoly (M : Matrix n n R) : aeval M M.charpoly = 0 := by
  -- We begin with the fact $χ_M(t) I = adjugate (t I - M) * (t I - M)$,
  -- as an identity in `Matrix n n R[X]`.
  have h : M.charpoly • (1 : Matrix n n R[X]) = adjugate (charmatrix M) * charmatrix M :=
    (adjugate_mul _).symm
  -- Using the algebra isomorphism `Matrix n n R[X] ≃ₐ[R] Polynomial (Matrix n n R)`,
  -- we have the same identity in `Polynomial (Matrix n n R)`.
  apply_fun matPolyEquiv at h
  simp only [matPolyEquiv.map_mul, matPolyEquiv_charmatrix] at h
  -- Because the coefficient ring `Matrix n n R` is non-commutative,
  -- evaluation at `M` is not multiplicative.
  -- However, any polynomial which is a product of the form $N * (t I - M)$
  -- is sent to zero, because the evaluation function puts the polynomial variable
  -- to the right of any coefficients, so everything telescopes.
  apply_fun fun p => p.eval M at h
  rw [eval_mul_X_sub_C] at h
  -- Now $χ_M (t) I$, when thought of as a polynomial of matrices
  -- and evaluated at some `N` is exactly $χ_M (N)$.
  rw [matPolyEquiv_smul_one, eval_map] at h
  -- Thus we have $χ_M(M) = 0$, which is the desired result.
  

Proof state:
R : Type u
inst✝² : CommRing R
n : Type w
inst✝¹ : DecidableEq n
inst✝ : Fintype n
M : Matrix n n R
h : eval₂ (algebraMap R (Matrix n n R)) M (charpoly M) = 0
⊢ (aeval M) (charpoly M) = 0

Next tactic:
exact h
protected theorem disjoint (h : IsMetricSeparated s t) : Disjoint s t :=
  let ⟨r, r0, hr⟩ := h
  Set.disjoint_left.mpr fun x hx1 hx2 => r0 <| by 

Proof state:
X : Type u_1
inst✝ : EMetricSpace X
s t : Set X
x✝ y : X
h : IsMetricSeparated s t
r : ENNReal
r0 : r ≠ 0
hr : ∀ x ∈ s, ∀ y ∈ t, r ≤ edist x y
x : X
hx1 : x ∈ s
hx2 : x ∈ t
⊢ r = 0

Next tactic:
simpa using hr x hx1 x hx2
theorem union_left {s'} (h : IsMetricSeparated s t) (h' : IsMetricSeparated s' t) :
    IsMetricSeparated (s ∪ s') t := by
  

Proof state:
X : Type u_1
inst✝ : EMetricSpace X
s t : Set X
x y : X
s' : Set X
h : IsMetricSeparated s t
h' : IsMetricSeparated s' t
⊢ IsMetricSeparated (s ∪ s') t

Next tactic:
rcases h, h' with ⟨⟨r, r0, hr⟩, ⟨r', r0', hr'⟩⟩
theorem union_left {s'} (h : IsMetricSeparated s t) (h' : IsMetricSeparated s' t) :
    IsMetricSeparated (s ∪ s') t := by
  rcases h, h' with ⟨⟨r, r0, hr⟩, ⟨r', r0', hr'⟩⟩
  

Proof state:
case intro.intro.intro.intro
X : Type u_1
inst✝ : EMetricSpace X
s t : Set X
x y : X
s' : Set X
r : ENNReal
r0 : r ≠ 0
hr : ∀ x ∈ s, ∀ y ∈ t, r ≤ edist x y
r' : ENNReal
r0' : r' ≠ 0
hr' : ∀ x ∈ s', ∀ y ∈ t, r' ≤ edist x y
⊢ IsMetricSeparated (s ∪ s') t

Next tactic:
refine' ⟨min r r', _, fun x hx y hy => hx.elim _ _⟩
theorem union_left {s'} (h : IsMetricSeparated s t) (h' : IsMetricSeparated s' t) :
    IsMetricSeparated (s ∪ s') t := by
  rcases h, h' with ⟨⟨r, r0, hr⟩, ⟨r', r0', hr'⟩⟩
  refine' ⟨min r r', _, fun x hx y hy => hx.elim _ _⟩
  · 

Proof state:
case intro.intro.intro.intro.refine'_1
X : Type u_1
inst✝ : EMetricSpace X
s t : Set X
x y : X
s' : Set X
r : ENNReal
r0 : r ≠ 0
hr : ∀ x ∈ s, ∀ y ∈ t, r ≤ edist x y
r' : ENNReal
r0' : r' ≠ 0
hr' : ∀ x ∈ s', ∀ y ∈ t, r' ≤ edist x y
⊢ min r r' ≠ 0

Next tactic:
rw [← pos_iff_ne_zero] at r0 r0' ⊢
theorem union_left {s'} (h : IsMetricSeparated s t) (h' : IsMetricSeparated s' t) :
    IsMetricSeparated (s ∪ s') t := by
  rcases h, h' with ⟨⟨r, r0, hr⟩, ⟨r', r0', hr'⟩⟩
  refine' ⟨min r r', _, fun x hx y hy => hx.elim _ _⟩
  · rw [← pos_iff_ne_zero] at r0 r0' ⊢
    

Proof state:
case intro.intro.intro.intro.refine'_1
X : Type u_1
inst✝ : EMetricSpace X
s t : Set X
x y : X
s' : Set X
r : ENNReal
r0 : 0 < r
hr : ∀ x ∈ s, ∀ y ∈ t, r ≤ edist x y
r' : ENNReal
r0' : 0 < r'
hr' : ∀ x ∈ s', ∀ y ∈ t, r' ≤ edist x y
⊢ 0 < min r r'

Next tactic:
exact lt_min r0 r0'
theorem union_left {s'} (h : IsMetricSeparated s t) (h' : IsMetricSeparated s' t) :
    IsMetricSeparated (s ∪ s') t := by
  rcases h, h' with ⟨⟨r, r0, hr⟩, ⟨r', r0', hr'⟩⟩
  refine' ⟨min r r', _, fun x hx y hy => hx.elim _ _⟩
  · rw [← pos_iff_ne_zero] at r0 r0' ⊢
    exact lt_min r0 r0'
  · 

Proof state:
case intro.intro.intro.intro.refine'_2
X : Type u_1
inst✝ : EMetricSpace X
s t : Set X
x✝ y✝ : X
s' : Set X
r : ENNReal
r0 : r ≠ 0
hr : ∀ x ∈ s, ∀ y ∈ t, r ≤ edist x y
r' : ENNReal
r0' : r' ≠ 0
hr' : ∀ x ∈ s', ∀ y ∈ t, r' ≤ edist x y
x : X
hx : x ∈ s ∪ s'
y : X
hy : y ∈ t
⊢ x ∈ s → min r r' ≤ edist x y

Next tactic:
exact fun hx => (min_le_left _ _).trans (hr _ hx _ hy)
theorem union_left {s'} (h : IsMetricSeparated s t) (h' : IsMetricSeparated s' t) :
    IsMetricSeparated (s ∪ s') t := by
  rcases h, h' with ⟨⟨r, r0, hr⟩, ⟨r', r0', hr'⟩⟩
  refine' ⟨min r r', _, fun x hx y hy => hx.elim _ _⟩
  · rw [← pos_iff_ne_zero] at r0 r0' ⊢
    exact lt_min r0 r0'
  · exact fun hx => (min_le_left _ _).trans (hr _ hx _ hy)
  · 

Proof state:
case intro.intro.intro.intro.refine'_3
X : Type u_1
inst✝ : EMetricSpace X
s t : Set X
x✝ y✝ : X
s' : Set X
r : ENNReal
r0 : r ≠ 0
hr : ∀ x ∈ s, ∀ y ∈ t, r ≤ edist x y
r' : ENNReal
r0' : r' ≠ 0
hr' : ∀ x ∈ s', ∀ y ∈ t, r' ≤ edist x y
x : X
hx : x ∈ s ∪ s'
y : X
hy : y ∈ t
⊢ x ∈ s' → min r r' ≤ edist x y

Next tactic:
exact fun hx => (min_le_right _ _).trans (hr' _ hx _ hy)
theorem finite_iUnion_left_iff {ι : Type*} {I : Set ι} (hI : I.Finite) {s : ι → Set X}
    {t : Set X} : IsMetricSeparated (⋃ i ∈ I, s i) t ↔ ∀ i ∈ I, IsMetricSeparated (s i) t := by
  

Proof state:
X : Type u_1
inst✝ : EMetricSpace X
s✝ t✝ : Set X
x y : X
ι : Type u_2
I : Set ι
hI : Set.Finite I
s : ι → Set X
t : Set X
⊢ IsMetricSeparated (⋃ i ∈ I, s i) t ↔ ∀ i ∈ I, IsMetricSeparated (s i) t

Next tactic:
refine' Finite.induction_on hI (by simp) @fun i I _ _ hI => _
theorem finite_iUnion_left_iff {ι : Type*} {I : Set ι} (hI : I.Finite) {s : ι → Set X}
    {t : Set X} : IsMetricSeparated (⋃ i ∈ I, s i) t ↔ ∀ i ∈ I, IsMetricSeparated (s i) t := by
  refine' Finite.induction_on hI (by 

Proof state:
X : Type u_1
inst✝ : EMetricSpace X
s✝ t✝ : Set X
x y : X
ι : Type u_2
I : Set ι
hI : Set.Finite I
s : ι → Set X
t : Set X
⊢ IsMetricSeparated (⋃ i ∈ ∅, s i) t ↔ ∀ i ∈ ∅, IsMetricSeparated (s i) t

Next tactic:
simp
theorem finite_iUnion_left_iff {ι : Type*} {I : Set ι} (hI : I.Finite) {s : ι → Set X}
    {t : Set X} : IsMetricSeparated (⋃ i ∈ I, s i) t ↔ ∀ i ∈ I, IsMetricSeparated (s i) t := by
  refine' Finite.induction_on hI (by simp) @fun i I _ _ hI => _
  

Proof state:
X : Type u_1
inst✝ : EMetricSpace X
s✝ t✝ : Set X
x y : X
ι : Type u_2
I✝ : Set ι
hI✝ : Set.Finite I✝
s : ι → Set X
t : Set X
i : ι
I : Set ι
x✝¹ : i ∉ I
x✝ : Set.Finite I
hI : IsMetricSeparated (⋃ i ∈ I, s i) t ↔ ∀ i ∈ I, IsMetricSeparated (s i) t
⊢ IsMetricSeparated (⋃ i_1 ∈ insert i I, s i_1) t ↔ ∀ i_1 ∈ insert i I, IsMetricSeparated (s i_1) t

Next tactic:
rw [biUnion_insert, ball_insert_iff, union_left_iff, hI]
theorem finite_iUnion_right_iff {ι : Type*} {I : Set ι} (hI : I.Finite) {s : Set X}
    {t : ι → Set X} : IsMetricSeparated s (⋃ i ∈ I, t i) ↔ ∀ i ∈ I, IsMetricSeparated s (t i) := by
  

Proof state:
X : Type u_1
inst✝ : EMetricSpace X
s✝ t✝ : Set X
x y : X
ι : Type u_2
I : Set ι
hI : Set.Finite I
s : Set X
t : ι → Set X
⊢ IsMetricSeparated s (⋃ i ∈ I, t i) ↔ ∀ i ∈ I, IsMetricSeparated s (t i)

Next tactic:
simpa only [@comm _ _ s] using finite_iUnion_left_iff hI
instance : Category (Monad C) where
  id M := { toNatTrans := 𝟙 (M : C ⥤ C) }
  comp f g :=
    { toNatTrans :=
        { app := fun X => f.app X ≫ g.app X
          naturality := fun X Y h => by 

Proof state:
C : Type u₁
inst✝ : Category.{v₁, u₁} C
T : Monad C
G : Comonad C
X✝ Y✝ Z✝ : Monad C
f : X✝ ⟶ Y✝
g : Y✝ ⟶ Z✝
X Y : C
h : X ⟶ Y
⊢ X✝.map h ≫ (fun X => f.app X ≫ g.app X) Y = (fun X => f.app X ≫ g.app X) X ≫ Z✝.map h

Next tactic:
rw [assoc, f.1.naturality_assoc, g.1.naturality]
instance : Category (Monad C) where
  id M := { toNatTrans := 𝟙 (M : C ⥤ C) }
  comp f g :=
    { toNatTrans :=
        { app := fun X => f.app X ≫ g.app X
          naturality := fun X Y h => by rw [assoc, f.1.naturality_assoc, g.1.naturality] } }
  -- `aesop_cat` can fill in these proofs, but is unfortunately slightly slow.
  id_comp _ := MonadHom.ext _ _ (by 

Proof state:
C : Type u₁
inst✝ : Category.{v₁, u₁} C
T : Monad C
G : Comonad C
X✝ Y✝ : Monad C
x✝ : X✝ ⟶ Y✝
⊢ (𝟙 X✝ ≫ x✝).app = x✝.app

Next tactic:
funext
instance : Category (Monad C) where
  id M := { toNatTrans := 𝟙 (M : C ⥤ C) }
  comp f g :=
    { toNatTrans :=
        { app := fun X => f.app X ≫ g.app X
          naturality := fun X Y h => by rw [assoc, f.1.naturality_assoc, g.1.naturality] } }
  -- `aesop_cat` can fill in these proofs, but is unfortunately slightly slow.
  id_comp _ := MonadHom.ext _ _ (by funext; 

Proof state:
case h
C : Type u₁
inst✝ : Category.{v₁, u₁} C
T : Monad C
G : Comonad C
X✝ Y✝ : Monad C
x✝¹ : X✝ ⟶ Y✝
x✝ : C
⊢ (𝟙 X✝ ≫ x✝¹).app x✝ = x✝¹.app x✝

Next tactic:
simp only [NatTrans.id_app, id_comp]
instance : Category (Monad C) where
  id M := { toNatTrans := 𝟙 (M : C ⥤ C) }
  comp f g :=
    { toNatTrans :=
        { app := fun X => f.app X ≫ g.app X
          naturality := fun X Y h => by rw [assoc, f.1.naturality_assoc, g.1.naturality] } }
  -- `aesop_cat` can fill in these proofs, but is unfortunately slightly slow.
  id_comp _ := MonadHom.ext _ _ (by funext; simp only [NatTrans.id_app, id_comp])
  comp_id _ := MonadHom.ext _ _ (by 

Proof state:
C : Type u₁
inst✝ : Category.{v₁, u₁} C
T : Monad C
G : Comonad C
X✝ Y✝ : Monad C
x✝ : X✝ ⟶ Y✝
⊢ (x✝ ≫ 𝟙 Y✝).app = x✝.app

Next tactic:
funext