l3lab/ntp-mathlib huggingface dataset:
theorem antilipschitz (coercive : IsCoercive B) : ∃ C : ℝ≥0, 0 < C ∧ AntilipschitzWith C B♯ := by
  rcases coercive.bounded_below with ⟨C, C_pos, below_bound⟩
  refine' ⟨C⁻¹.toNNReal, Real.toNNReal_pos.mpr (inv_pos.mpr C_pos), _⟩
  refine' ContinuousLinearMap.antilipschitz_of_bound B♯ _
  simp_rw [Real.coe_toNNReal', max_eq_left_of_lt (inv_pos.mpr C_pos), ←
    inv_mul_le_iff (inv_pos.mpr C_pos)]
  

Proof state:
case intro.intro
V : Type u
inst✝² : NormedAddCommGroup V
inst✝¹ : InnerProductSpace ℝ V
inst✝ : CompleteSpace V
B : V →L[ℝ] V →L[ℝ] ℝ
coercive : IsCoercive B
C : ℝ
C_pos : 0 < C
below_bound : ∀ (v : V), C * ‖v‖ ≤ ‖(continuousLinearMapOfBilin B) v‖
⊢ ∀ (x : V), C⁻¹⁻¹ * ‖x‖ ≤ ‖(continuousLinearMapOfBilin B) x‖

Next tactic:
simpa using below_bound
theorem ker_eq_bot (coercive : IsCoercive B) : ker B♯ = ⊥ := by
  

Proof state:
V : Type u
inst✝² : NormedAddCommGroup V
inst✝¹ : InnerProductSpace ℝ V
inst✝ : CompleteSpace V
B : V →L[ℝ] V →L[ℝ] ℝ
coercive : IsCoercive B
⊢ ker (continuousLinearMapOfBilin B) = ⊥

Next tactic:
rw [LinearMapClass.ker_eq_bot]
theorem ker_eq_bot (coercive : IsCoercive B) : ker B♯ = ⊥ := by
  rw [LinearMapClass.ker_eq_bot]
  

Proof state:
V : Type u
inst✝² : NormedAddCommGroup V
inst✝¹ : InnerProductSpace ℝ V
inst✝ : CompleteSpace V
B : V →L[ℝ] V →L[ℝ] ℝ
coercive : IsCoercive B
⊢ Function.Injective ⇑(continuousLinearMapOfBilin B)

Next tactic:
rcases coercive.antilipschitz with ⟨_, _, antilipschitz⟩
theorem ker_eq_bot (coercive : IsCoercive B) : ker B♯ = ⊥ := by
  rw [LinearMapClass.ker_eq_bot]
  rcases coercive.antilipschitz with ⟨_, _, antilipschitz⟩
  

Proof state:
case intro.intro
V : Type u
inst✝² : NormedAddCommGroup V
inst✝¹ : InnerProductSpace ℝ V
inst✝ : CompleteSpace V
B : V →L[ℝ] V →L[ℝ] ℝ
coercive : IsCoercive B
w✝ : ℝ≥0
left✝ : 0 < w✝
antilipschitz : AntilipschitzWith w✝ ⇑(continuousLinearMapOfBilin B)
⊢ Function.Injective ⇑(continuousLinearMapOfBilin B)

Next tactic:
exact antilipschitz.injective
theorem closed_range (coercive : IsCoercive B) : IsClosed (range B♯ : Set V) := by
  

Proof state:
V : Type u
inst✝² : NormedAddCommGroup V
inst✝¹ : InnerProductSpace ℝ V
inst✝ : CompleteSpace V
B : V →L[ℝ] V →L[ℝ] ℝ
coercive : IsCoercive B
⊢ IsClosed ↑(range (continuousLinearMapOfBilin B))

Next tactic:
rcases coercive.antilipschitz with ⟨_, _, antilipschitz⟩
theorem closed_range (coercive : IsCoercive B) : IsClosed (range B♯ : Set V) := by
  rcases coercive.antilipschitz with ⟨_, _, antilipschitz⟩
  

Proof state:
case intro.intro
V : Type u
inst✝² : NormedAddCommGroup V
inst✝¹ : InnerProductSpace ℝ V
inst✝ : CompleteSpace V
B : V →L[ℝ] V →L[ℝ] ℝ
coercive : IsCoercive B
w✝ : ℝ≥0
left✝ : 0 < w✝
antilipschitz : AntilipschitzWith w✝ ⇑(continuousLinearMapOfBilin B)
⊢ IsClosed ↑(range (continuousLinearMapOfBilin B))

Next tactic:
exact antilipschitz.isClosed_range B♯.uniformContinuous
theorem range_eq_top (coercive : IsCoercive B) : range B♯ = ⊤ := by
  

Proof state:
V : Type u
inst✝² : NormedAddCommGroup V
inst✝¹ : InnerProductSpace ℝ V
inst✝ : CompleteSpace V
B : V →L[ℝ] V →L[ℝ] ℝ
coercive : IsCoercive B
⊢ range (continuousLinearMapOfBilin B) = ⊤

Next tactic:
haveI := coercive.closed_range.completeSpace_coe
theorem range_eq_top (coercive : IsCoercive B) : range B♯ = ⊤ := by
  haveI := coercive.closed_range.completeSpace_coe
  

Proof state:
V : Type u
inst✝² : NormedAddCommGroup V
inst✝¹ : InnerProductSpace ℝ V
inst✝ : CompleteSpace V
B : V →L[ℝ] V →L[ℝ] ℝ
coercive : IsCoercive B
this : CompleteSpace ↑↑(range (continuousLinearMapOfBilin B))
⊢ range (continuousLinearMapOfBilin B) = ⊤

Next tactic:
rw [← (range B♯).orthogonal_orthogonal]
theorem range_eq_top (coercive : IsCoercive B) : range B♯ = ⊤ := by
  haveI := coercive.closed_range.completeSpace_coe
  rw [← (range B♯).orthogonal_orthogonal]
  

Proof state:
V : Type u
inst✝² : NormedAddCommGroup V
inst✝¹ : InnerProductSpace ℝ V
inst✝ : CompleteSpace V
B : V →L[ℝ] V →L[ℝ] ℝ
coercive : IsCoercive B
this : CompleteSpace ↑↑(range (continuousLinearMapOfBilin B))
⊢ (range (continuousLinearMapOfBilin B))ᗮᗮ = ⊤

Next tactic:
rw [Submodule.eq_top_iff']
theorem range_eq_top (coercive : IsCoercive B) : range B♯ = ⊤ := by
  haveI := coercive.closed_range.completeSpace_coe
  rw [← (range B♯).orthogonal_orthogonal]
  rw [Submodule.eq_top_iff']
  

Proof state:
V : Type u
inst✝² : NormedAddCommGroup V
inst✝¹ : InnerProductSpace ℝ V
inst✝ : CompleteSpace V
B : V →L[ℝ] V →L[ℝ] ℝ
coercive : IsCoercive B
this : CompleteSpace ↑↑(range (continuousLinearMapOfBilin B))
⊢ ∀ (x : V), x ∈ (range (continuousLinearMapOfBilin B))ᗮᗮ

Next tactic:
intro v w mem_w_orthogonal
theorem range_eq_top (coercive : IsCoercive B) : range B♯ = ⊤ := by
  haveI := coercive.closed_range.completeSpace_coe
  rw [← (range B♯).orthogonal_orthogonal]
  rw [Submodule.eq_top_iff']
  intro v w mem_w_orthogonal
  

Proof state:
V : Type u
inst✝² : NormedAddCommGroup V
inst✝¹ : InnerProductSpace ℝ V
inst✝ : CompleteSpace V
B : V →L[ℝ] V →L[ℝ] ℝ
coercive : IsCoercive B
this : CompleteSpace ↑↑(range (continuousLinearMapOfBilin B))
v w : V
mem_w_orthogonal : w ∈ (range (continuousLinearMapOfBilin B))ᗮ
⊢ inner w v = 0

Next tactic:
rcases coercive with ⟨C, C_pos, coercivity⟩
theorem range_eq_top (coercive : IsCoercive B) : range B♯ = ⊤ := by
  haveI := coercive.closed_range.completeSpace_coe
  rw [← (range B♯).orthogonal_orthogonal]
  rw [Submodule.eq_top_iff']
  intro v w mem_w_orthogonal
  rcases coercive with ⟨C, C_pos, coercivity⟩
  

Proof state:
case intro.intro
V : Type u
inst✝² : NormedAddCommGroup V
inst✝¹ : InnerProductSpace ℝ V
inst✝ : CompleteSpace V
B : V →L[ℝ] V →L[ℝ] ℝ
this : CompleteSpace ↑↑(range (continuousLinearMapOfBilin B))
v w : V
mem_w_orthogonal : w ∈ (range (continuousLinearMapOfBilin B))ᗮ
C : ℝ
C_pos : 0 < C
coercivity : ∀ (u : V), C * ‖u‖ * ‖u‖ ≤ (B u) u
⊢ inner w v = 0

Next tactic:
obtain rfl : w = 0 := by
    rw [← norm_eq_zero, ← mul_self_eq_zero, ← mul_right_inj' C_pos.ne', mul_zero, ←
      mul_assoc]
    apply le_antisymm
    · calc
        C * ‖w‖ * ‖w‖ ≤ B w w := coercivity w
        _ = ⟪B♯ w, w⟫_ℝ := (continuousLinearMapOfBilin_apply B w w).symm
        _ = 0 := mem_w_orthogonal _ ⟨w, rfl⟩
    · exact mul_nonneg (mul_nonneg C_pos.le (norm_nonneg w)) (norm_nonneg w)
theorem range_eq_top (coercive : IsCoercive B) : range B♯ = ⊤ := by
  haveI := coercive.closed_range.completeSpace_coe
  rw [← (range B♯).orthogonal_orthogonal]
  rw [Submodule.eq_top_iff']
  intro v w mem_w_orthogonal
  rcases coercive with ⟨C, C_pos, coercivity⟩
  obtain rfl : w = 0 := by
    

Proof state:
V : Type u
inst✝² : NormedAddCommGroup V
inst✝¹ : InnerProductSpace ℝ V
inst✝ : CompleteSpace V
B : V →L[ℝ] V →L[ℝ] ℝ
this : CompleteSpace ↑↑(range (continuousLinearMapOfBilin B))
v w : V
mem_w_orthogonal : w ∈ (range (continuousLinearMapOfBilin B))ᗮ
C : ℝ
C_pos : 0 < C
coercivity : ∀ (u : V), C * ‖u‖ * ‖u‖ ≤ (B u) u
⊢ w = 0

Next tactic:
rw [← norm_eq_zero, ← mul_self_eq_zero, ← mul_right_inj' C_pos.ne', mul_zero, ←
      mul_assoc]
theorem range_eq_top (coercive : IsCoercive B) : range B♯ = ⊤ := by
  haveI := coercive.closed_range.completeSpace_coe
  rw [← (range B♯).orthogonal_orthogonal]
  rw [Submodule.eq_top_iff']
  intro v w mem_w_orthogonal
  rcases coercive with ⟨C, C_pos, coercivity⟩
  obtain rfl : w = 0 := by
    rw [← norm_eq_zero, ← mul_self_eq_zero, ← mul_right_inj' C_pos.ne', mul_zero, ←
      mul_assoc]
    

Proof state:
V : Type u
inst✝² : NormedAddCommGroup V
inst✝¹ : InnerProductSpace ℝ V
inst✝ : CompleteSpace V
B : V →L[ℝ] V →L[ℝ] ℝ
this : CompleteSpace ↑↑(range (continuousLinearMapOfBilin B))
v w : V
mem_w_orthogonal : w ∈ (range (continuousLinearMapOfBilin B))ᗮ
C : ℝ
C_pos : 0 < C
coercivity : ∀ (u : V), C * ‖u‖ * ‖u‖ ≤ (B u) u
⊢ C * ‖w‖ * ‖w‖ = 0

Next tactic:
apply le_antisymm
theorem range_eq_top (coercive : IsCoercive B) : range B♯ = ⊤ := by
  haveI := coercive.closed_range.completeSpace_coe
  rw [← (range B♯).orthogonal_orthogonal]
  rw [Submodule.eq_top_iff']
  intro v w mem_w_orthogonal
  rcases coercive with ⟨C, C_pos, coercivity⟩
  obtain rfl : w = 0 := by
    rw [← norm_eq_zero, ← mul_self_eq_zero, ← mul_right_inj' C_pos.ne', mul_zero, ←
      mul_assoc]
    apply le_antisymm
    · 

Proof state:
case a
V : Type u
inst✝² : NormedAddCommGroup V
inst✝¹ : InnerProductSpace ℝ V
inst✝ : CompleteSpace V
B : V →L[ℝ] V →L[ℝ] ℝ
this : CompleteSpace ↑↑(range (continuousLinearMapOfBilin B))
v w : V
mem_w_orthogonal : w ∈ (range (continuousLinearMapOfBilin B))ᗮ
C : ℝ
C_pos : 0 < C
coercivity : ∀ (u : V), C * ‖u‖ * ‖u‖ ≤ (B u) u
⊢ C * ‖w‖ * ‖w‖ ≤ 0

Next tactic:
calc
        C * ‖w‖ * ‖w‖ ≤ B w w := coercivity w
        _ = ⟪B♯ w, w⟫_ℝ := (continuousLinearMapOfBilin_apply B w w).symm
        _ = 0 := mem_w_orthogonal _ ⟨w, rfl⟩
theorem range_eq_top (coercive : IsCoercive B) : range B♯ = ⊤ := by
  haveI := coercive.closed_range.completeSpace_coe
  rw [← (range B♯).orthogonal_orthogonal]
  rw [Submodule.eq_top_iff']
  intro v w mem_w_orthogonal
  rcases coercive with ⟨C, C_pos, coercivity⟩
  obtain rfl : w = 0 := by
    rw [← norm_eq_zero, ← mul_self_eq_zero, ← mul_right_inj' C_pos.ne', mul_zero, ←
      mul_assoc]
    apply le_antisymm
    · calc
        C * ‖w‖ * ‖w‖ ≤ B w w := coercivity w
        _ = ⟪B♯ w, w⟫_ℝ := (continuousLinearMapOfBilin_apply B w w).symm
        _ = 0 := mem_w_orthogonal _ ⟨w, rfl⟩
    · 

Proof state:
case a
V : Type u
inst✝² : NormedAddCommGroup V
inst✝¹ : InnerProductSpace ℝ V
inst✝ : CompleteSpace V
B : V →L[ℝ] V →L[ℝ] ℝ
this : CompleteSpace ↑↑(range (continuousLinearMapOfBilin B))
v w : V
mem_w_orthogonal : w ∈ (range (continuousLinearMapOfBilin B))ᗮ
C : ℝ
C_pos : 0 < C
coercivity : ∀ (u : V), C * ‖u‖ * ‖u‖ ≤ (B u) u
⊢ 0 ≤ C * ‖w‖ * ‖w‖

Next tactic:
exact mul_nonneg (mul_nonneg C_pos.le (norm_nonneg w)) (norm_nonneg w)
theorem range_eq_top (coercive : IsCoercive B) : range B♯ = ⊤ := by
  haveI := coercive.closed_range.completeSpace_coe
  rw [← (range B♯).orthogonal_orthogonal]
  rw [Submodule.eq_top_iff']
  intro v w mem_w_orthogonal
  rcases coercive with ⟨C, C_pos, coercivity⟩
  obtain rfl : w = 0 := by
    rw [← norm_eq_zero, ← mul_self_eq_zero, ← mul_right_inj' C_pos.ne', mul_zero, ←
      mul_assoc]
    apply le_antisymm
    · calc
        C * ‖w‖ * ‖w‖ ≤ B w w := coercivity w
        _ = ⟪B♯ w, w⟫_ℝ := (continuousLinearMapOfBilin_apply B w w).symm
        _ = 0 := mem_w_orthogonal _ ⟨w, rfl⟩
    · exact mul_nonneg (mul_nonneg C_pos.le (norm_nonneg w)) (norm_nonneg w)
  

Proof state:
case intro.intro
V : Type u
inst✝² : NormedAddCommGroup V
inst✝¹ : InnerProductSpace ℝ V
inst✝ : CompleteSpace V
B : V →L[ℝ] V →L[ℝ] ℝ
this : CompleteSpace ↑↑(range (continuousLinearMapOfBilin B))
v : V
C : ℝ
C_pos : 0 < C
coercivity : ∀ (u : V), C * ‖u‖ * ‖u‖ ≤ (B u) u
mem_w_orthogonal : 0 ∈ (range (continuousLinearMapOfBilin B))ᗮ
⊢ inner 0 v = 0

Next tactic:
exact inner_zero_left _
theorem funMap_quotient_mk' {n : ℕ} (f : L.Functions n) (x : Fin n → M) :
    (funMap f fun i => (⟦x i⟧ : Quotient s)) = ⟦@funMap _ _ ps.toStructure _ f x⟧ := by
  

Proof state:
L : Language
M : Type u_1
s : Setoid M
ps : Prestructure L s
n : ℕ
f : Functions L n
x : Fin n → M
⊢ (funMap f fun i => ⟦x i⟧) = ⟦funMap f x⟧

Next tactic:
change
    Quotient.map (@funMap L M ps.toStructure n f) Prestructure.fun_equiv (Quotient.finChoice _) =
      _
theorem funMap_quotient_mk' {n : ℕ} (f : L.Functions n) (x : Fin n → M) :
    (funMap f fun i => (⟦x i⟧ : Quotient s)) = ⟦@funMap _ _ ps.toStructure _ f x⟧ := by
  change
    Quotient.map (@funMap L M ps.toStructure n f) Prestructure.fun_equiv (Quotient.finChoice _) =
      _
  

Proof state:
L : Language
M : Type u_1
s : Setoid M
ps : Prestructure L s
n : ℕ
f : Functions L n
x : Fin n → M
⊢ Quotient.map (funMap f) (_ : ∀ (x y : Fin n → M), x ≈ y → funMap f x ≈ funMap f y)
      (Quotient.finChoice fun i => ⟦x i⟧) =
    ⟦funMap f x⟧

Next tactic:
rw [Quotient.finChoice_eq, Quotient.map_mk]
theorem relMap_quotient_mk' {n : ℕ} (r : L.Relations n) (x : Fin n → M) :
    (RelMap r fun i => (⟦x i⟧ : Quotient s)) ↔ @RelMap _ _ ps.toStructure _ r x := by
  

Proof state:
L : Language
M : Type u_1
s : Setoid M
ps : Prestructure L s
n : ℕ
r : Relations L n
x : Fin n → M
⊢ (RelMap r fun i => ⟦x i⟧) ↔ RelMap r x

Next tactic:
change
    Quotient.lift (@RelMap L M ps.toStructure n r) Prestructure.rel_equiv (Quotient.finChoice _) ↔
      _
theorem relMap_quotient_mk' {n : ℕ} (r : L.Relations n) (x : Fin n → M) :
    (RelMap r fun i => (⟦x i⟧ : Quotient s)) ↔ @RelMap _ _ ps.toStructure _ r x := by
  change
    Quotient.lift (@RelMap L M ps.toStructure n r) Prestructure.rel_equiv (Quotient.finChoice _) ↔
      _
  

Proof state:
L : Language
M : Type u_1
s : Setoid M
ps : Prestructure L s
n : ℕ
r : Relations L n
x : Fin n → M
⊢ Quotient.lift (RelMap r) (_ : ∀ (x y : Fin n → M), x ≈ y → RelMap r x = RelMap r y)
      (Quotient.finChoice fun i => ⟦x i⟧) ↔
    RelMap r x

Next tactic:
rw [Quotient.finChoice_eq, Quotient.lift_mk]
theorem Term.realize_quotient_mk' {β : Type*} (t : L.Term β) (x : β → M) :
    (t.realize fun i => (⟦x i⟧ : Quotient s)) = ⟦@Term.realize _ _ ps.toStructure _ x t⟧ := by
  

Proof state:
L : Language
M : Type u_1
s : Setoid M
ps : Prestructure L s
β : Type u_2
t : Term L β
x : β → M
⊢ realize (fun i => ⟦x i⟧) t = ⟦realize x t⟧

Next tactic:
induction' t with _ _ _ _ ih
theorem Term.realize_quotient_mk' {β : Type*} (t : L.Term β) (x : β → M) :
    (t.realize fun i => (⟦x i⟧ : Quotient s)) = ⟦@Term.realize _ _ ps.toStructure _ x t⟧ := by
  induction' t with _ _ _ _ ih
  · 

Proof state:
case var
L : Language
M : Type u_1
s : Setoid M
ps : Prestructure L s
β : Type u_2
x : β → M
_a✝ : β
⊢ realize (fun i => ⟦x i⟧) (var _a✝) = ⟦realize x (var _a✝)⟧

Next tactic:
rfl
theorem Term.realize_quotient_mk' {β : Type*} (t : L.Term β) (x : β → M) :
    (t.realize fun i => (⟦x i⟧ : Quotient s)) = ⟦@Term.realize _ _ ps.toStructure _ x t⟧ := by
  induction' t with _ _ _ _ ih
  · rfl
  · 

Proof state:
case func
L : Language
M : Type u_1
s : Setoid M
ps : Prestructure L s
β : Type u_2
x : β → M
l✝ : ℕ
_f✝ : Functions L l✝
_ts✝ : Fin l✝ → Term L β
ih : ∀ (a : Fin l✝), realize (fun i => ⟦x i⟧) (_ts✝ a) = ⟦realize x (_ts✝ a)⟧
⊢ realize (fun i => ⟦x i⟧) (func _f✝ _ts✝) = ⟦realize x (func _f✝ _ts✝)⟧

Next tactic:
simp only [ih, funMap_quotient_mk', Term.realize]
/-- A coercion from a congruence relation to its underlying binary relation. -/
@[to_additive "A coercion from an additive congruence relation to its underlying binary relation."]
instance : FunLike (Con M) M (fun _ => M → Prop) where
  coe c := c.r
  coe_injective' := fun x y h => by
    

Proof state:
M : Type u_1
N : Type u_2
P : Type u_3
inst✝² : Mul M
inst✝¹ : Mul N
inst✝ : Mul P
c x y : Con M
h : (fun c => r) x = (fun c => r) y
⊢ x = y

Next tactic:
rcases x with ⟨⟨x, _⟩, _⟩
/-- A coercion from a congruence relation to its underlying binary relation. -/
@[to_additive "A coercion from an additive congruence relation to its underlying binary relation."]
instance : FunLike (Con M) M (fun _ => M → Prop) where
  coe c := c.r
  coe_injective' := fun x y h => by
    rcases x with ⟨⟨x, _⟩, _⟩
    

Proof state:
case mk.mk
M : Type u_1
N : Type u_2
P : Type u_3
inst✝² : Mul M
inst✝¹ : Mul N
inst✝ : Mul P
c y : Con M
x : M → M → Prop
iseqv✝ : Equivalence x
mul'✝ : ∀ {w x_1 y z : M}, r w x_1 → r y z → r (w * y) (x_1 * z)
h : (fun c => r) { toSetoid := { r := x, iseqv := iseqv✝ }, mul' := mul'✝ } = (fun c => r) y
⊢ { toSetoid := { r := x, iseqv := iseqv✝ }, mul' := mul'✝ } = y

Next tactic:
rcases y with ⟨⟨y, _⟩, _⟩
/-- A coercion from a congruence relation to its underlying binary relation. -/
@[to_additive "A coercion from an additive congruence relation to its underlying binary relation."]
instance : FunLike (Con M) M (fun _ => M → Prop) where
  coe c := c.r
  coe_injective' := fun x y h => by
    rcases x with ⟨⟨x, _⟩, _⟩
    rcases y with ⟨⟨y, _⟩, _⟩
    

Proof state:
case mk.mk.mk.mk
M : Type u_1
N : Type u_2
P : Type u_3
inst✝² : Mul M
inst✝¹ : Mul N
inst✝ : Mul P
c : Con M
x : M → M → Prop
iseqv✝¹ : Equivalence x
mul'✝¹ : ∀ {w x_1 y z : M}, r w x_1 → r y z → r (w * y) (x_1 * z)
y : M → M → Prop
iseqv✝ : Equivalence y
mul'✝ : ∀ {w x y_1 z : M}, r w x → r y_1 z → r (w * y_1) (x * z)
h :
  (fun c => r) { toSetoid := { r := x, iseqv := iseqv✝¹ }, mul' := mul'✝¹ } =
    (fun c => r) { toSetoid := { r := y, iseqv := iseqv✝ }, mul' := mul'✝ }
⊢ { toSetoid := { r := x, iseqv := iseqv✝¹ }, mul' := mul'✝¹ } =
    { toSetoid := { r := y, iseqv := iseqv✝ }, mul' := mul'✝ }

Next tactic:
have : x = y := h
/-- A coercion from a congruence relation to its underlying binary relation. -/
@[to_additive "A coercion from an additive congruence relation to its underlying binary relation."]
instance : FunLike (Con M) M (fun _ => M → Prop) where
  coe c := c.r
  coe_injective' := fun x y h => by
    rcases x with ⟨⟨x, _⟩, _⟩
    rcases y with ⟨⟨y, _⟩, _⟩
    have : x = y := h
    

Proof state:
case mk.mk.mk.mk
M : Type u_1
N : Type u_2
P : Type u_3
inst✝² : Mul M
inst✝¹ : Mul N
inst✝ : Mul P
c : Con M
x : M → M → Prop
iseqv✝¹ : Equivalence x
mul'✝¹ : ∀ {w x_1 y z : M}, r w x_1 → r y z → r (w * y) (x_1 * z)
y : M → M → Prop
iseqv✝ : Equivalence y
mul'✝ : ∀ {w x y_1 z : M}, r w x → r y_1 z → r (w * y_1) (x * z)
h :
  (fun c => r) { toSetoid := { r := x, iseqv := iseqv✝¹ }, mul' := mul'✝¹ } =
    (fun c => r) { toSetoid := { r := y, iseqv := iseqv✝ }, mul' := mul'✝ }
this : x = y
⊢ { toSetoid := { r := x, iseqv := iseqv✝¹ }, mul' := mul'✝¹ } =
    { toSetoid := { r := y, iseqv := iseqv✝ }, mul' := mul'✝ }

Next tactic:
subst x
/-- A coercion from a congruence relation to its underlying binary relation. -/
@[to_additive "A coercion from an additive congruence relation to its underlying binary relation."]
instance : FunLike (Con M) M (fun _ => M → Prop) where
  coe c := c.r
  coe_injective' := fun x y h => by
    rcases x with ⟨⟨x, _⟩, _⟩
    rcases y with ⟨⟨y, _⟩, _⟩
    have : x = y := h
    subst x; 

Proof state:
case mk.mk.mk.mk
M : Type u_1
N : Type u_2
P : Type u_3
inst✝² : Mul M
inst✝¹ : Mul N
inst✝ : Mul P
c : Con M
y : M → M → Prop
iseqv✝¹ : Equivalence y
mul'✝¹ : ∀ {w x y_1 z : M}, r w x → r y_1 z → r (w * y_1) (x * z)
iseqv✝ : Equivalence y
mul'✝ : ∀ {w x y_1 z : M}, r w x → r y_1 z → r (w * y_1) (x * z)
h :
  (fun c => r) { toSetoid := { r := y, iseqv := iseqv✝ }, mul' := mul'✝ } =
    (fun c => r) { toSetoid := { r := y, iseqv := iseqv✝¹ }, mul' := mul'✝¹ }
⊢ { toSetoid := { r := y, iseqv := iseqv✝ }, mul' := mul'✝ } =
    { toSetoid := { r := y, iseqv := iseqv✝¹ }, mul' := mul'✝¹ }

Next tactic:
rfl
/-- Extensionality rule for congruence relations. -/
@[to_additive (attr := ext) "Extensionality rule for additive congruence relations."]
theorem ext {c d : Con M} (H : ∀ x y, c x y ↔ d x y) : c = d :=
  ext' <| by 

Proof state:
M : Type u_1
N : Type u_2
P : Type u_3
inst✝² : Mul M
inst✝¹ : Mul N
inst✝ : Mul P
c✝ c d : Con M
H : ∀ (x y : M), c x y ↔ d x y
⊢ ⇑c = ⇑d

Next tactic:
ext
/-- Extensionality rule for congruence relations. -/
@[to_additive (attr := ext) "Extensionality rule for additive congruence relations."]
theorem ext {c d : Con M} (H : ∀ x y, c x y ↔ d x y) : c = d :=
  ext' <| by ext; 

Proof state:
case h.h.a
M : Type u_1
N : Type u_2
P : Type u_3
inst✝² : Mul M
inst✝¹ : Mul N
inst✝ : Mul P
c✝ c d : Con M
H : ∀ (x y : M), c x y ↔ d x y
x✝¹ x✝ : M
⊢ c x✝¹ x✝ ↔ d x✝¹ x✝

Next tactic:
apply H
/-- The kernel of a multiplication-preserving function as a congruence relation. -/
@[to_additive "The kernel of an addition-preserving function as an additive congruence relation."]
def mulKer (f : M → P) (h : ∀ x y, f (x * y) = f x * f y) : Con M
    where
  toSetoid := Setoid.ker f
  mul' h1 h2 := by
    

Proof state:
M : Type u_1
N : Type u_2
P : Type u_3
inst✝² : Mul M
inst✝¹ : Mul N
inst✝ : Mul P
c : Con M
f : M → P
h : ∀ (x y : M), f (x * y) = f x * f y
w✝ x✝ y✝ z✝ : M
h1 : r w✝ x✝
h2 : r y✝ z✝
⊢ r (w✝ * y✝) (x✝ * z✝)

Next tactic:
dsimp [Setoid.ker, onFun] at *
/-- The kernel of a multiplication-preserving function as a congruence relation. -/
@[to_additive "The kernel of an addition-preserving function as an additive congruence relation."]
def mulKer (f : M → P) (h : ∀ x y, f (x * y) = f x * f y) : Con M
    where
  toSetoid := Setoid.ker f
  mul' h1 h2 := by
    dsimp [Setoid.ker, onFun] at *
    

Proof state:
M : Type u_1
N : Type u_2
P : Type u_3
inst✝² : Mul M
inst✝¹ : Mul N
inst✝ : Mul P
c : Con M
f : M → P
h : ∀ (x y : M), f (x * y) = f x * f y
w✝ x✝ y✝ z✝ : M
h1 : f w✝ = f x✝
h2 : f y✝ = f z✝
⊢ f (w✝ * y✝) = f (x✝ * z✝)

Next tactic:
rw [h, h1, h2, h]
/-- Makes an isomorphism of quotients by two congruence relations, given that the relations are
    equal. -/
@[to_additive "Makes an additive isomorphism of quotients by two additive congruence relations,
given that the relations are equal."]
protected def congr {c d : Con M} (h : c = d) : c.Quotient ≃* d.Quotient :=
  { Quotient.congr (Equiv.refl M) <| by 

Proof state:
M : Type u_1
N : Type u_2
P : Type u_3
inst✝² : Mul M
inst✝¹ : Mul N
inst✝ : Mul P
c✝ c d : Con M
h : c = d
⊢ ∀ (a₁ a₂ : M), r a₁ a₂ ↔ r ((Equiv.refl M) a₁) ((Equiv.refl M) a₂)

Next tactic:
apply ext_iff.2 h
/-- Makes an isomorphism of quotients by two congruence relations, given that the relations are
    equal. -/
@[to_additive "Makes an additive isomorphism of quotients by two additive congruence relations,
given that the relations are equal."]
protected def congr {c d : Con M} (h : c = d) : c.Quotient ≃* d.Quotient :=
  { Quotient.congr (Equiv.refl M) <| by apply ext_iff.2 h with
    map_mul' := fun x y => by 

Proof state:
M : Type u_1
N : Type u_2
P : Type u_3
inst✝² : Mul M
inst✝¹ : Mul N
inst✝ : Mul P
c✝ c d : Con M
h : c = d
src✝ : Quotient c.toSetoid ≃ Quotient d.toSetoid := Quotient.congr (Equiv.refl M) (_ : ∀ (x y : M), c x y ↔ d x y)
x y : Con.Quotient c
⊢ Equiv.toFun
      { toFun := src✝.toFun, invFun := src✝.invFun, left_inv := (_ : LeftInverse src✝.invFun src✝.toFun),
        right_inv := (_ : Function.RightInverse src✝.invFun src✝.toFun) }
      (x * y) =
    Equiv.toFun
        { toFun := src✝.toFun, invFun := src✝.invFun, left_inv := (_ : LeftInverse src✝.invFun src✝.toFun),
          right_inv := (_ : Function.RightInverse src✝.invFun src✝.toFun) }
        x *
      Equiv.toFun
        { toFun := src✝.toFun, invFun := src✝.invFun, left_inv := (_ : LeftInverse src✝.invFun src✝.toFun),
          right_inv := (_ : Function.RightInverse src✝.invFun src✝.toFun) }
        y

Next tactic:
rcases x with ⟨⟩
/-- Makes an isomorphism of quotients by two congruence relations, given that the relations are
    equal. -/
@[to_additive "Makes an additive isomorphism of quotients by two additive congruence relations,
given that the relations are equal."]
protected def congr {c d : Con M} (h : c = d) : c.Quotient ≃* d.Quotient :=
  { Quotient.congr (Equiv.refl M) <| by apply ext_iff.2 h with
    map_mul' := fun x y => by rcases x with ⟨⟩; 

Proof state:
case mk
M : Type u_1
N : Type u_2
P : Type u_3
inst✝² : Mul M
inst✝¹ : Mul N
inst✝ : Mul P
c✝ c d : Con M
h : c = d
src✝ : Quotient c.toSetoid ≃ Quotient d.toSetoid := Quotient.congr (Equiv.refl M) (_ : ∀ (x y : M), c x y ↔ d x y)
x y : Con.Quotient c
a✝ : M
⊢ Equiv.toFun
      { toFun := src✝.toFun, invFun := src✝.invFun, left_inv := (_ : LeftInverse src✝.invFun src✝.toFun),
        right_inv := (_ : Function.RightInverse src✝.invFun src✝.toFun) }
      (Quot.mk r a✝ * y) =
    Equiv.toFun
        { toFun := src✝.toFun, invFun := src✝.invFun, left_inv := (_ : LeftInverse src✝.invFun src✝.toFun),
          right_inv := (_ : Function.RightInverse src✝.invFun src✝.toFun) }
        (Quot.mk r a✝) *
      Equiv.toFun
        { toFun := src✝.toFun, invFun := src✝.invFun, left_inv := (_ : LeftInverse src✝.invFun src✝.toFun),
          right_inv := (_ : Function.RightInverse src✝.invFun src✝.toFun) }
        y

Next tactic:
rcases y with ⟨⟩