l3lab/ntp-mathlib huggingface dataset:
@[ext]
theorem Algebra.IsPushout.algHom_ext [H : Algebra.IsPushout R S R' S'] {A : Type*} [Semiring A]
    [Algebra R A] {f g : S' →ₐ[R] A} (h₁ : f.comp (toAlgHom R R' S') = g.comp (toAlgHom R R' S'))
    (h₂ : f.comp (toAlgHom R S S') = g.comp (toAlgHom R S S')) : f = g := by
  ext x
  refine H.1.inductionOn x ?_ ?_ ?_ ?_
  · simp only [map_zero]
  · exact AlgHom.congr_fun h₁
  · 

Proof state:
case H.refine_3
R : Type u_1
M : Type v₁
N : Type v₂
S : Type v₃
inst✝³³ : AddCommMonoid M
inst✝³² : AddCommMonoid N
inst✝³¹ : CommRing R
inst✝³⁰ : CommRing S
inst✝²⁹ : Algebra R S
inst✝²⁸ : Module R M
inst✝²⁷ : Module R N
inst✝²⁶ : Module S N
inst✝²⁵ : IsScalarTower R S N
f✝ : M →ₗ[R] N
h : IsBaseChange S f✝
P : Type u_2
Q : Type u_3
inst✝²⁴ : AddCommMonoid P
inst✝²³ : Module R P
inst✝²² : AddCommMonoid Q
inst✝²¹ : Module S Q
T : Type u_4
O : Type u_5
inst✝²⁰ : CommRing T
inst✝¹⁹ : Algebra R T
inst✝¹⁸ : Algebra S T
inst✝¹⁷ : IsScalarTower R S T
inst✝¹⁶ : AddCommMonoid O
inst✝¹⁵ : Module R O
inst✝¹⁴ : Module S O
inst✝¹³ : Module T O
inst✝¹² : IsScalarTower S T O
inst✝¹¹ : IsScalarTower R S O
inst✝¹⁰ : IsScalarTower R T O
R' : Type u_6
S' : Type u_7
inst✝⁹ : CommRing R'
inst✝⁸ : CommRing S'
inst✝⁷ : Algebra R R'
inst✝⁶ : Algebra S S'
inst✝⁵ : Algebra R' S'
inst✝⁴ : Algebra R S'
inst✝³ : IsScalarTower R R' S'
inst✝² : IsScalarTower R S S'
H : IsPushout R S R' S'
A : Type u_8
inst✝¹ : Semiring A
inst✝ : Algebra R A
f g : S' →ₐ[R] A
h₁ : AlgHom.comp f (toAlgHom R R' S') = AlgHom.comp g (toAlgHom R R' S')
h₂ : AlgHom.comp f (toAlgHom R S S') = AlgHom.comp g (toAlgHom R S S')
x : S'
⊢ ∀ (s : S) (n : S'), f n = g n → f (s • n) = g (s • n)

Next tactic:
intro s s' e
@[ext]
theorem Algebra.IsPushout.algHom_ext [H : Algebra.IsPushout R S R' S'] {A : Type*} [Semiring A]
    [Algebra R A] {f g : S' →ₐ[R] A} (h₁ : f.comp (toAlgHom R R' S') = g.comp (toAlgHom R R' S'))
    (h₂ : f.comp (toAlgHom R S S') = g.comp (toAlgHom R S S')) : f = g := by
  ext x
  refine H.1.inductionOn x ?_ ?_ ?_ ?_
  · simp only [map_zero]
  · exact AlgHom.congr_fun h₁
  · intro s s' e
    

Proof state:
case H.refine_3
R : Type u_1
M : Type v₁
N : Type v₂
S : Type v₃
inst✝³³ : AddCommMonoid M
inst✝³² : AddCommMonoid N
inst✝³¹ : CommRing R
inst✝³⁰ : CommRing S
inst✝²⁹ : Algebra R S
inst✝²⁸ : Module R M
inst✝²⁷ : Module R N
inst✝²⁶ : Module S N
inst✝²⁵ : IsScalarTower R S N
f✝ : M →ₗ[R] N
h : IsBaseChange S f✝
P : Type u_2
Q : Type u_3
inst✝²⁴ : AddCommMonoid P
inst✝²³ : Module R P
inst✝²² : AddCommMonoid Q
inst✝²¹ : Module S Q
T : Type u_4
O : Type u_5
inst✝²⁰ : CommRing T
inst✝¹⁹ : Algebra R T
inst✝¹⁸ : Algebra S T
inst✝¹⁷ : IsScalarTower R S T
inst✝¹⁶ : AddCommMonoid O
inst✝¹⁵ : Module R O
inst✝¹⁴ : Module S O
inst✝¹³ : Module T O
inst✝¹² : IsScalarTower S T O
inst✝¹¹ : IsScalarTower R S O
inst✝¹⁰ : IsScalarTower R T O
R' : Type u_6
S' : Type u_7
inst✝⁹ : CommRing R'
inst✝⁸ : CommRing S'
inst✝⁷ : Algebra R R'
inst✝⁶ : Algebra S S'
inst✝⁵ : Algebra R' S'
inst✝⁴ : Algebra R S'
inst✝³ : IsScalarTower R R' S'
inst✝² : IsScalarTower R S S'
H : IsPushout R S R' S'
A : Type u_8
inst✝¹ : Semiring A
inst✝ : Algebra R A
f g : S' →ₐ[R] A
h₁ : AlgHom.comp f (toAlgHom R R' S') = AlgHom.comp g (toAlgHom R R' S')
h₂ : AlgHom.comp f (toAlgHom R S S') = AlgHom.comp g (toAlgHom R S S')
x : S'
s : S
s' : S'
e : f s' = g s'
⊢ f (s • s') = g (s • s')

Next tactic:
rw [Algebra.smul_def, f.map_mul, g.map_mul, e]
@[ext]
theorem Algebra.IsPushout.algHom_ext [H : Algebra.IsPushout R S R' S'] {A : Type*} [Semiring A]
    [Algebra R A] {f g : S' →ₐ[R] A} (h₁ : f.comp (toAlgHom R R' S') = g.comp (toAlgHom R R' S'))
    (h₂ : f.comp (toAlgHom R S S') = g.comp (toAlgHom R S S')) : f = g := by
  ext x
  refine H.1.inductionOn x ?_ ?_ ?_ ?_
  · simp only [map_zero]
  · exact AlgHom.congr_fun h₁
  · intro s s' e
    rw [Algebra.smul_def, f.map_mul, g.map_mul, e]
    

Proof state:
case H.refine_3
R : Type u_1
M : Type v₁
N : Type v₂
S : Type v₃
inst✝³³ : AddCommMonoid M
inst✝³² : AddCommMonoid N
inst✝³¹ : CommRing R
inst✝³⁰ : CommRing S
inst✝²⁹ : Algebra R S
inst✝²⁸ : Module R M
inst✝²⁷ : Module R N
inst✝²⁶ : Module S N
inst✝²⁵ : IsScalarTower R S N
f✝ : M →ₗ[R] N
h : IsBaseChange S f✝
P : Type u_2
Q : Type u_3
inst✝²⁴ : AddCommMonoid P
inst✝²³ : Module R P
inst✝²² : AddCommMonoid Q
inst✝²¹ : Module S Q
T : Type u_4
O : Type u_5
inst✝²⁰ : CommRing T
inst✝¹⁹ : Algebra R T
inst✝¹⁸ : Algebra S T
inst✝¹⁷ : IsScalarTower R S T
inst✝¹⁶ : AddCommMonoid O
inst✝¹⁵ : Module R O
inst✝¹⁴ : Module S O
inst✝¹³ : Module T O
inst✝¹² : IsScalarTower S T O
inst✝¹¹ : IsScalarTower R S O
inst✝¹⁰ : IsScalarTower R T O
R' : Type u_6
S' : Type u_7
inst✝⁹ : CommRing R'
inst✝⁸ : CommRing S'
inst✝⁷ : Algebra R R'
inst✝⁶ : Algebra S S'
inst✝⁵ : Algebra R' S'
inst✝⁴ : Algebra R S'
inst✝³ : IsScalarTower R R' S'
inst✝² : IsScalarTower R S S'
H : IsPushout R S R' S'
A : Type u_8
inst✝¹ : Semiring A
inst✝ : Algebra R A
f g : S' →ₐ[R] A
h₁ : AlgHom.comp f (toAlgHom R R' S') = AlgHom.comp g (toAlgHom R R' S')
h₂ : AlgHom.comp f (toAlgHom R S S') = AlgHom.comp g (toAlgHom R S S')
x : S'
s : S
s' : S'
e : f s' = g s'
⊢ f ((algebraMap S S') s) * g s' = g ((algebraMap S S') s) * g s'

Next tactic:
congr 1
@[ext]
theorem Algebra.IsPushout.algHom_ext [H : Algebra.IsPushout R S R' S'] {A : Type*} [Semiring A]
    [Algebra R A] {f g : S' →ₐ[R] A} (h₁ : f.comp (toAlgHom R R' S') = g.comp (toAlgHom R R' S'))
    (h₂ : f.comp (toAlgHom R S S') = g.comp (toAlgHom R S S')) : f = g := by
  ext x
  refine H.1.inductionOn x ?_ ?_ ?_ ?_
  · simp only [map_zero]
  · exact AlgHom.congr_fun h₁
  · intro s s' e
    rw [Algebra.smul_def, f.map_mul, g.map_mul, e]
    congr 1
    

Proof state:
case H.refine_3.e_a
R : Type u_1
M : Type v₁
N : Type v₂
S : Type v₃
inst✝³³ : AddCommMonoid M
inst✝³² : AddCommMonoid N
inst✝³¹ : CommRing R
inst✝³⁰ : CommRing S
inst✝²⁹ : Algebra R S
inst✝²⁸ : Module R M
inst✝²⁷ : Module R N
inst✝²⁶ : Module S N
inst✝²⁵ : IsScalarTower R S N
f✝ : M →ₗ[R] N
h : IsBaseChange S f✝
P : Type u_2
Q : Type u_3
inst✝²⁴ : AddCommMonoid P
inst✝²³ : Module R P
inst✝²² : AddCommMonoid Q
inst✝²¹ : Module S Q
T : Type u_4
O : Type u_5
inst✝²⁰ : CommRing T
inst✝¹⁹ : Algebra R T
inst✝¹⁸ : Algebra S T
inst✝¹⁷ : IsScalarTower R S T
inst✝¹⁶ : AddCommMonoid O
inst✝¹⁵ : Module R O
inst✝¹⁴ : Module S O
inst✝¹³ : Module T O
inst✝¹² : IsScalarTower S T O
inst✝¹¹ : IsScalarTower R S O
inst✝¹⁰ : IsScalarTower R T O
R' : Type u_6
S' : Type u_7
inst✝⁹ : CommRing R'
inst✝⁸ : CommRing S'
inst✝⁷ : Algebra R R'
inst✝⁶ : Algebra S S'
inst✝⁵ : Algebra R' S'
inst✝⁴ : Algebra R S'
inst✝³ : IsScalarTower R R' S'
inst✝² : IsScalarTower R S S'
H : IsPushout R S R' S'
A : Type u_8
inst✝¹ : Semiring A
inst✝ : Algebra R A
f g : S' →ₐ[R] A
h₁ : AlgHom.comp f (toAlgHom R R' S') = AlgHom.comp g (toAlgHom R R' S')
h₂ : AlgHom.comp f (toAlgHom R S S') = AlgHom.comp g (toAlgHom R S S')
x : S'
s : S
s' : S'
e : f s' = g s'
⊢ f ((algebraMap S S') s) = g ((algebraMap S S') s)

Next tactic:
exact (AlgHom.congr_fun h₂ s : _)
@[ext]
theorem Algebra.IsPushout.algHom_ext [H : Algebra.IsPushout R S R' S'] {A : Type*} [Semiring A]
    [Algebra R A] {f g : S' →ₐ[R] A} (h₁ : f.comp (toAlgHom R R' S') = g.comp (toAlgHom R R' S'))
    (h₂ : f.comp (toAlgHom R S S') = g.comp (toAlgHom R S S')) : f = g := by
  ext x
  refine H.1.inductionOn x ?_ ?_ ?_ ?_
  · simp only [map_zero]
  · exact AlgHom.congr_fun h₁
  · intro s s' e
    rw [Algebra.smul_def, f.map_mul, g.map_mul, e]
    congr 1
    exact (AlgHom.congr_fun h₂ s : _)
  · 

Proof state:
case H.refine_4
R : Type u_1
M : Type v₁
N : Type v₂
S : Type v₃
inst✝³³ : AddCommMonoid M
inst✝³² : AddCommMonoid N
inst✝³¹ : CommRing R
inst✝³⁰ : CommRing S
inst✝²⁹ : Algebra R S
inst✝²⁸ : Module R M
inst✝²⁷ : Module R N
inst✝²⁶ : Module S N
inst✝²⁵ : IsScalarTower R S N
f✝ : M →ₗ[R] N
h : IsBaseChange S f✝
P : Type u_2
Q : Type u_3
inst✝²⁴ : AddCommMonoid P
inst✝²³ : Module R P
inst✝²² : AddCommMonoid Q
inst✝²¹ : Module S Q
T : Type u_4
O : Type u_5
inst✝²⁰ : CommRing T
inst✝¹⁹ : Algebra R T
inst✝¹⁸ : Algebra S T
inst✝¹⁷ : IsScalarTower R S T
inst✝¹⁶ : AddCommMonoid O
inst✝¹⁵ : Module R O
inst✝¹⁴ : Module S O
inst✝¹³ : Module T O
inst✝¹² : IsScalarTower S T O
inst✝¹¹ : IsScalarTower R S O
inst✝¹⁰ : IsScalarTower R T O
R' : Type u_6
S' : Type u_7
inst✝⁹ : CommRing R'
inst✝⁸ : CommRing S'
inst✝⁷ : Algebra R R'
inst✝⁶ : Algebra S S'
inst✝⁵ : Algebra R' S'
inst✝⁴ : Algebra R S'
inst✝³ : IsScalarTower R R' S'
inst✝² : IsScalarTower R S S'
H : IsPushout R S R' S'
A : Type u_8
inst✝¹ : Semiring A
inst✝ : Algebra R A
f g : S' →ₐ[R] A
h₁ : AlgHom.comp f (toAlgHom R R' S') = AlgHom.comp g (toAlgHom R R' S')
h₂ : AlgHom.comp f (toAlgHom R S S') = AlgHom.comp g (toAlgHom R S S')
x : S'
⊢ ∀ (n₁ n₂ : S'), f n₁ = g n₁ → f n₂ = g n₂ → f (n₁ + n₂) = g (n₁ + n₂)

Next tactic:
intro s₁ s₂ e₁ e₂
@[ext]
theorem Algebra.IsPushout.algHom_ext [H : Algebra.IsPushout R S R' S'] {A : Type*} [Semiring A]
    [Algebra R A] {f g : S' →ₐ[R] A} (h₁ : f.comp (toAlgHom R R' S') = g.comp (toAlgHom R R' S'))
    (h₂ : f.comp (toAlgHom R S S') = g.comp (toAlgHom R S S')) : f = g := by
  ext x
  refine H.1.inductionOn x ?_ ?_ ?_ ?_
  · simp only [map_zero]
  · exact AlgHom.congr_fun h₁
  · intro s s' e
    rw [Algebra.smul_def, f.map_mul, g.map_mul, e]
    congr 1
    exact (AlgHom.congr_fun h₂ s : _)
  · intro s₁ s₂ e₁ e₂
    

Proof state:
case H.refine_4
R : Type u_1
M : Type v₁
N : Type v₂
S : Type v₃
inst✝³³ : AddCommMonoid M
inst✝³² : AddCommMonoid N
inst✝³¹ : CommRing R
inst✝³⁰ : CommRing S
inst✝²⁹ : Algebra R S
inst✝²⁸ : Module R M
inst✝²⁷ : Module R N
inst✝²⁶ : Module S N
inst✝²⁵ : IsScalarTower R S N
f✝ : M →ₗ[R] N
h : IsBaseChange S f✝
P : Type u_2
Q : Type u_3
inst✝²⁴ : AddCommMonoid P
inst✝²³ : Module R P
inst✝²² : AddCommMonoid Q
inst✝²¹ : Module S Q
T : Type u_4
O : Type u_5
inst✝²⁰ : CommRing T
inst✝¹⁹ : Algebra R T
inst✝¹⁸ : Algebra S T
inst✝¹⁷ : IsScalarTower R S T
inst✝¹⁶ : AddCommMonoid O
inst✝¹⁵ : Module R O
inst✝¹⁴ : Module S O
inst✝¹³ : Module T O
inst✝¹² : IsScalarTower S T O
inst✝¹¹ : IsScalarTower R S O
inst✝¹⁰ : IsScalarTower R T O
R' : Type u_6
S' : Type u_7
inst✝⁹ : CommRing R'
inst✝⁸ : CommRing S'
inst✝⁷ : Algebra R R'
inst✝⁶ : Algebra S S'
inst✝⁵ : Algebra R' S'
inst✝⁴ : Algebra R S'
inst✝³ : IsScalarTower R R' S'
inst✝² : IsScalarTower R S S'
H : IsPushout R S R' S'
A : Type u_8
inst✝¹ : Semiring A
inst✝ : Algebra R A
f g : S' →ₐ[R] A
h₁ : AlgHom.comp f (toAlgHom R R' S') = AlgHom.comp g (toAlgHom R R' S')
h₂ : AlgHom.comp f (toAlgHom R S S') = AlgHom.comp g (toAlgHom R S S')
x s₁ s₂ : S'
e₁ : f s₁ = g s₁
e₂ : f s₂ = g s₂
⊢ f (s₁ + s₂) = g (s₁ + s₂)

Next tactic:
rw [map_add, map_add, e₁, e₂]
/-- The underlying binary operation of the infimum of a set of equivalence relations
    is the infimum of the set's image under the map to the underlying binary operation. -/
theorem sInf_def {s : Set (Setoid α)} : (sInf s).Rel = sInf (Rel '' s) := by
  

Proof state:
α : Type u_1
β : Type u_2
s : Set (Setoid α)
⊢ Rel (sInf s) = sInf (Rel '' s)

Next tactic:
ext
/-- The underlying binary operation of the infimum of a set of equivalence relations
    is the infimum of the set's image under the map to the underlying binary operation. -/
theorem sInf_def {s : Set (Setoid α)} : (sInf s).Rel = sInf (Rel '' s) := by
  ext
  

Proof state:
case h.h.a
α : Type u_1
β : Type u_2
s : Set (Setoid α)
x✝¹ x✝ : α
⊢ Rel (sInf s) x✝¹ x✝ ↔ sInf (Rel '' s) x✝¹ x✝

Next tactic:
simp only [sInf_image, iInf_apply, iInf_Prop_eq]
/-- The underlying binary operation of the infimum of a set of equivalence relations
    is the infimum of the set's image under the map to the underlying binary operation. -/
theorem sInf_def {s : Set (Setoid α)} : (sInf s).Rel = sInf (Rel '' s) := by
  ext
  simp only [sInf_image, iInf_apply, iInf_Prop_eq]
  

Proof state:
case h.h.a
α : Type u_1
β : Type u_2
s : Set (Setoid α)
x✝¹ x✝ : α
⊢ Rel (sInf s) x✝¹ x✝ ↔ ∀ i ∈ s, Rel i x✝¹ x✝

Next tactic:
rfl
theorem eq_top_iff {s : Setoid α} : s = (⊤ : Setoid α) ↔ ∀ x y : α, s.Rel x y := by
  

Proof state:
α : Type u_1
β : Type u_2
s : Setoid α
⊢ s = ⊤ ↔ ∀ (x y : α), Rel s x y

Next tactic:
rw [_root_.eq_top_iff, Setoid.le_def, Setoid.top_def]
theorem eq_top_iff {s : Setoid α} : s = (⊤ : Setoid α) ↔ ∀ x y : α, s.Rel x y := by
  rw [_root_.eq_top_iff, Setoid.le_def, Setoid.top_def]
  

Proof state:
α : Type u_1
β : Type u_2
s : Setoid α
⊢ (∀ {x y : α}, ⊤ x y → Rel s x y) ↔ ∀ (x y : α), Rel s x y

Next tactic:
simp only [Pi.top_apply, Prop.top_eq_true, forall_true_left]
/-- The supremum of two equivalence relations r and s is the equivalence closure of the binary
    relation `x is related to y by r or s`. -/
theorem sup_eq_eqvGen (r s : Setoid α) :
    r ⊔ s = EqvGen.Setoid fun x y => r.Rel x y ∨ s.Rel x y := by
  

Proof state:
α : Type u_1
β : Type u_2
r s : Setoid α
⊢ r ⊔ s = EqvGen.Setoid fun x y => Rel r x y ∨ Rel s x y

Next tactic:
rw [eqvGen_eq]
/-- The supremum of two equivalence relations r and s is the equivalence closure of the binary
    relation `x is related to y by r or s`. -/
theorem sup_eq_eqvGen (r s : Setoid α) :
    r ⊔ s = EqvGen.Setoid fun x y => r.Rel x y ∨ s.Rel x y := by
  rw [eqvGen_eq]
  

Proof state:
α : Type u_1
β : Type u_2
r s : Setoid α
⊢ r ⊔ s = sInf {s_1 | ∀ ⦃x y : α⦄, Rel r x y ∨ Rel s x y → Rel s_1 x y}

Next tactic:
apply congr_arg sInf
/-- The supremum of two equivalence relations r and s is the equivalence closure of the binary
    relation `x is related to y by r or s`. -/
theorem sup_eq_eqvGen (r s : Setoid α) :
    r ⊔ s = EqvGen.Setoid fun x y => r.Rel x y ∨ s.Rel x y := by
  rw [eqvGen_eq]
  apply congr_arg sInf
  

Proof state:
α : Type u_1
β : Type u_2
r s : Setoid α
⊢ {x | r ≤ x ∧ s ≤ x} = {s_1 | ∀ ⦃x y : α⦄, Rel r x y ∨ Rel s x y → Rel s_1 x y}

Next tactic:
simp only [le_def, or_imp, ← forall_and]
/-- The supremum of 2 equivalence relations r and s is the equivalence closure of the
    supremum of the underlying binary operations. -/
theorem sup_def {r s : Setoid α} : r ⊔ s = EqvGen.Setoid (r.Rel ⊔ s.Rel) := by
  

Proof state:
α : Type u_1
β : Type u_2
r s : Setoid α
⊢ r ⊔ s = EqvGen.Setoid (Rel r ⊔ Rel s)

Next tactic:
rw [sup_eq_eqvGen]
/-- The supremum of 2 equivalence relations r and s is the equivalence closure of the
    supremum of the underlying binary operations. -/
theorem sup_def {r s : Setoid α} : r ⊔ s = EqvGen.Setoid (r.Rel ⊔ s.Rel) := by
  rw [sup_eq_eqvGen]; 

Proof state:
α : Type u_1
β : Type u_2
r s : Setoid α
⊢ (EqvGen.Setoid fun x y => Rel r x y ∨ Rel s x y) = EqvGen.Setoid (Rel r ⊔ Rel s)

Next tactic:
rfl
/-- The supremum of a set S of equivalence relations is the equivalence closure of the binary
    relation `there exists r ∈ S relating x and y`. -/
theorem sSup_eq_eqvGen (S : Set (Setoid α)) :
    sSup S = EqvGen.Setoid fun x y => ∃ r : Setoid α, r ∈ S ∧ r.Rel x y := by
  

Proof state:
α : Type u_1
β : Type u_2
S : Set (Setoid α)
⊢ sSup S = EqvGen.Setoid fun x y => ∃ r ∈ S, Rel r x y

Next tactic:
rw [eqvGen_eq]
/-- The supremum of a set S of equivalence relations is the equivalence closure of the binary
    relation `there exists r ∈ S relating x and y`. -/
theorem sSup_eq_eqvGen (S : Set (Setoid α)) :
    sSup S = EqvGen.Setoid fun x y => ∃ r : Setoid α, r ∈ S ∧ r.Rel x y := by
  rw [eqvGen_eq]
  

Proof state:
α : Type u_1
β : Type u_2
S : Set (Setoid α)
⊢ sSup S = sInf {s | ∀ ⦃x y : α⦄, (∃ r ∈ S, Rel r x y) → Rel s x y}

Next tactic:
apply congr_arg sInf
/-- The supremum of a set S of equivalence relations is the equivalence closure of the binary
    relation `there exists r ∈ S relating x and y`. -/
theorem sSup_eq_eqvGen (S : Set (Setoid α)) :
    sSup S = EqvGen.Setoid fun x y => ∃ r : Setoid α, r ∈ S ∧ r.Rel x y := by
  rw [eqvGen_eq]
  apply congr_arg sInf
  

Proof state:
α : Type u_1
β : Type u_2
S : Set (Setoid α)
⊢ upperBounds S = {s | ∀ ⦃x y : α⦄, (∃ r ∈ S, Rel r x y) → Rel s x y}

Next tactic:
simp only [upperBounds, le_def, and_imp, exists_imp]
/-- The supremum of a set S of equivalence relations is the equivalence closure of the binary
    relation `there exists r ∈ S relating x and y`. -/
theorem sSup_eq_eqvGen (S : Set (Setoid α)) :
    sSup S = EqvGen.Setoid fun x y => ∃ r : Setoid α, r ∈ S ∧ r.Rel x y := by
  rw [eqvGen_eq]
  apply congr_arg sInf
  simp only [upperBounds, le_def, and_imp, exists_imp]
  

Proof state:
α : Type u_1
β : Type u_2
S : Set (Setoid α)
⊢ {x | ∀ ⦃a : Setoid α⦄, a ∈ S → ∀ {x_1 y : α}, Rel a x_1 y → Rel x x_1 y} =
    {s | ∀ ⦃x y : α⦄, ∀ x_1 ∈ S, Rel x_1 x y → Rel s x y}

Next tactic:
ext
/-- The supremum of a set S of equivalence relations is the equivalence closure of the binary
    relation `there exists r ∈ S relating x and y`. -/
theorem sSup_eq_eqvGen (S : Set (Setoid α)) :
    sSup S = EqvGen.Setoid fun x y => ∃ r : Setoid α, r ∈ S ∧ r.Rel x y := by
  rw [eqvGen_eq]
  apply congr_arg sInf
  simp only [upperBounds, le_def, and_imp, exists_imp]
  ext
  

Proof state:
case h
α : Type u_1
β : Type u_2
S : Set (Setoid α)
x✝ : Setoid α
⊢ x✝ ∈ {x | ∀ ⦃a : Setoid α⦄, a ∈ S → ∀ {x_1 y : α}, Rel a x_1 y → Rel x x_1 y} ↔
    x✝ ∈ {s | ∀ ⦃x y : α⦄, ∀ x_1 ∈ S, Rel x_1 x y → Rel s x y}

Next tactic:
exact ⟨fun H x y r hr => H hr, fun H r hr x y => H r hr⟩
/-- The supremum of a set of equivalence relations is the equivalence closure of the
    supremum of the set's image under the map to the underlying binary operation. -/
theorem sSup_def {s : Set (Setoid α)} : sSup s = EqvGen.Setoid (sSup (Rel '' s)) := by
  

Proof state:
α : Type u_1
β : Type u_2
s : Set (Setoid α)
⊢ sSup s = EqvGen.Setoid (sSup (Rel '' s))

Next tactic:
rw [sSup_eq_eqvGen, sSup_image]
/-- The supremum of a set of equivalence relations is the equivalence closure of the
    supremum of the set's image under the map to the underlying binary operation. -/
theorem sSup_def {s : Set (Setoid α)} : sSup s = EqvGen.Setoid (sSup (Rel '' s)) := by
  rw [sSup_eq_eqvGen, sSup_image]
  

Proof state:
α : Type u_1
β : Type u_2
s : Set (Setoid α)
⊢ (EqvGen.Setoid fun x y => ∃ r ∈ s, Rel r x y) = EqvGen.Setoid (⨆ a ∈ s, Rel a)

Next tactic:
congr with (x y)
/-- The supremum of a set of equivalence relations is the equivalence closure of the
    supremum of the set's image under the map to the underlying binary operation. -/
theorem sSup_def {s : Set (Setoid α)} : sSup s = EqvGen.Setoid (sSup (Rel '' s)) := by
  rw [sSup_eq_eqvGen, sSup_image]
  congr with (x y)
  

Proof state:
case e_r.h.h.a
α : Type u_1
β : Type u_2
s : Set (Setoid α)
x y : α
⊢ (∃ r ∈ s, Rel r x y) ↔ iSup (fun a => ⨆ (_ : a ∈ s), Rel a) x y

Next tactic:
simp only [iSup_apply, iSup_Prop_eq, exists_prop]
/-- The equivalence closure of an equivalence relation r is r. -/
@[simp]
theorem eqvGen_of_setoid (r : Setoid α) : EqvGen.Setoid r.r = r :=
  le_antisymm (by 

Proof state:
α : Type u_1
β : Type u_2
r : Setoid α
⊢ EqvGen.Setoid Setoid.r ≤ r

Next tactic:
rw [eqvGen_eq]
/-- The equivalence closure of an equivalence relation r is r. -/
@[simp]
theorem eqvGen_of_setoid (r : Setoid α) : EqvGen.Setoid r.r = r :=
  le_antisymm (by rw [eqvGen_eq]; 

Proof state:
α : Type u_1
β : Type u_2
r : Setoid α
⊢ sInf {s | ∀ ⦃x y : α⦄, Setoid.r x y → Rel s x y} ≤ r

Next tactic:
exact sInf_le fun _ _ => id
/-- The equivalence closure of a binary relation r is contained in any equivalence
    relation containing r. -/
theorem eqvGen_le {r : α → α → Prop} {s : Setoid α} (h : ∀ x y, r x y → s.Rel x y) :
    EqvGen.Setoid r ≤ s := by 

Proof state:
α : Type u_1
β : Type u_2
r : α → α → Prop
s : Setoid α
h : ∀ (x y : α), r x y → Rel s x y
⊢ EqvGen.Setoid r ≤ s

Next tactic:
rw [eqvGen_eq]
/-- The equivalence closure of a binary relation r is contained in any equivalence
    relation containing r. -/
theorem eqvGen_le {r : α → α → Prop} {s : Setoid α} (h : ∀ x y, r x y → s.Rel x y) :
    EqvGen.Setoid r ≤ s := by rw [eqvGen_eq]; 

Proof state:
α : Type u_1
β : Type u_2
r : α → α → Prop
s : Setoid α
h : ∀ (x y : α), r x y → Rel s x y
⊢ sInf {s | ∀ ⦃x y : α⦄, r x y → Rel s x y} ≤ s

Next tactic:
exact sInf_le h
/-- Equivalence between functions `α → β` such that `r x y → f x = f y` and functions
`quotient r → β`. -/
def liftEquiv (r : Setoid α) : { f : α → β // r ≤ ker f } ≃ (Quotient r → β) where
  toFun f := Quotient.lift (f : α → β) f.2
  invFun f := ⟨f ∘ Quotient.mk'', fun x y h => by 

Proof state:
α : Type u_1
β : Type u_2
r : Setoid α
f : Quotient r → β
x y : α
h : Rel r x y
⊢ Rel (ker (f ∘ Quotient.mk'')) x y

Next tactic:
simp [ker_def, Quotient.sound' h]
/-- The uniqueness part of the universal property for quotients of an arbitrary type. -/
theorem lift_unique {r : Setoid α} {f : α → β} (H : r ≤ ker f) (g : Quotient r → β)
    (Hg : f = g ∘ Quotient.mk'') : Quotient.lift f H = g := by
  

Proof state:
α : Type u_1
β : Type u_2
r : Setoid α
f : α → β
H : r ≤ ker f
g : Quotient r → β
Hg : f = g ∘ Quotient.mk''
⊢ Quotient.lift f H = g

Next tactic:
ext ⟨x⟩
/-- The uniqueness part of the universal property for quotients of an arbitrary type. -/
theorem lift_unique {r : Setoid α} {f : α → β} (H : r ≤ ker f) (g : Quotient r → β)
    (Hg : f = g ∘ Quotient.mk'') : Quotient.lift f H = g := by
  ext ⟨x⟩
  

Proof state:
case h.mk
α : Type u_1
β : Type u_2
r : Setoid α
f : α → β
H : r ≤ ker f
g : Quotient r → β
Hg : f = g ∘ Quotient.mk''
x✝ : Quotient r
x : α
⊢ Quotient.lift f H (Quot.mk Setoid.r x) = g (Quot.mk Setoid.r x)

Next tactic:
erw [Quotient.lift_mk f H, Hg]
/-- The uniqueness part of the universal property for quotients of an arbitrary type. -/
theorem lift_unique {r : Setoid α} {f : α → β} (H : r ≤ ker f) (g : Quotient r → β)
    (Hg : f = g ∘ Quotient.mk'') : Quotient.lift f H = g := by
  ext ⟨x⟩
  erw [Quotient.lift_mk f H, Hg]
  

Proof state:
case h.mk
α : Type u_1
β : Type u_2
r : Setoid α
f : α → β
H : r ≤ ker f
g : Quotient r → β
Hg : f = g ∘ Quotient.mk''
x✝ : Quotient r
x : α
⊢ (g ∘ Quotient.mk'') x = g (Quot.mk Setoid.r x)

Next tactic:
rfl
/-- The first isomorphism theorem for sets: the quotient of α by the kernel of a function f
    bijects with f's image. -/
noncomputable def quotientKerEquivRange : Quotient (ker f) ≃ Set.range f :=
  Equiv.ofBijective
    ((@Quotient.lift _ (Set.range f) (ker f) fun x => ⟨f x, Set.mem_range_self x⟩) fun _ _ h =>
      Subtype.ext_val h)
    ⟨fun x y h => ker_lift_injective f <| by 

Proof state:
α : Type u_1
β : Type u_2
r : Setoid α
f : α → β
x y : Quotient (ker f)
h :
  Quotient.lift (fun x => { val := f x, property := (_ : f x ∈ Set.range f) })
      (_ :
        ∀ (x x_1 : α),
          x ≈ x_1 →
            { val := f x, property := (_ : f x ∈ Set.range f) } =
              { val := f x_1, property := (_ : f x_1 ∈ Set.range f) })
      x =
    Quotient.lift (fun x => { val := f x, property := (_ : f x ∈ Set.range f) })
      (_ :
        ∀ (x x_1 : α),
          x ≈ x_1 →
            { val := f x, property := (_ : f x ∈ Set.range f) } =
              { val := f x_1, property := (_ : f x_1 ∈ Set.range f) })
      y
⊢ Quotient.lift f (_ : ∀ (x x_1 : α), x ≈ x_1 → x ≈ x_1) x = Quotient.lift f (_ : ∀ (x x_1 : α), x ≈ x_1 → x ≈ x_1) y

Next tactic:
rcases x with ⟨⟩
/-- The first isomorphism theorem for sets: the quotient of α by the kernel of a function f
    bijects with f's image. -/
noncomputable def quotientKerEquivRange : Quotient (ker f) ≃ Set.range f :=
  Equiv.ofBijective
    ((@Quotient.lift _ (Set.range f) (ker f) fun x => ⟨f x, Set.mem_range_self x⟩) fun _ _ h =>
      Subtype.ext_val h)
    ⟨fun x y h => ker_lift_injective f <| by rcases x with ⟨⟩; 

Proof state:
case mk
α : Type u_1
β : Type u_2
r : Setoid α
f : α → β
x y : Quotient (ker f)
a✝ : α
h :
  Quotient.lift (fun x => { val := f x, property := (_ : f x ∈ Set.range f) })
      (_ :
        ∀ (x x_1 : α),
          x ≈ x_1 →
            { val := f x, property := (_ : f x ∈ Set.range f) } =
              { val := f x_1, property := (_ : f x_1 ∈ Set.range f) })
      (Quot.mk Setoid.r a✝) =
    Quotient.lift (fun x => { val := f x, property := (_ : f x ∈ Set.range f) })
      (_ :
        ∀ (x x_1 : α),
          x ≈ x_1 →
            { val := f x, property := (_ : f x ∈ Set.range f) } =
              { val := f x_1, property := (_ : f x_1 ∈ Set.range f) })
      y
⊢ Quotient.lift f (_ : ∀ (x x_1 : α), x ≈ x_1 → x ≈ x_1) (Quot.mk Setoid.r a✝) =
    Quotient.lift f (_ : ∀ (x x_1 : α), x ≈ x_1 → x ≈ x_1) y

Next tactic:
rcases y with ⟨⟩