/-- Given a congruence relation `c` on a type `M` with a multiplication, the order-preserving
    bijection between the set of congruence relations containing `c` and the congruence relations
    on the quotient of `M` by `c`. -/
@[to_additive "Given an additive congruence relation `c` on a type `M` with an addition,
the order-preserving bijection between the set of additive congruence relations containing `c` and
the additive congruence relations on the quotient of `M` by `c`."]
def correspondence : { d // c ≤ d } ≃o Con c.Quotient
    where
  toFun d :=
    d.1.mapOfSurjective (↑) _ (by rw [mul_ker_mk_eq]; exact d.2) <| @exists_rep _ c.toSetoid
  invFun d :=
    ⟨comap ((↑) : M → c.Quotient) (fun x y => rfl) d, fun x y h =>
      show d x y by rw [c.eq.2 h]; exact d.refl _⟩
  left_inv d :=
    --Porting note: by exact needed for unknown reason
    by exact
      Subtype.ext_iff_val.2 <|
        ext fun x y =>
          ⟨fun h =>
            let ⟨a, b, hx, hy, H⟩ := h
            d.1.trans (d.1.symm <| d.2 <| c.eq.1 hx) <| d.1.trans H <| d.2 <| c.eq.1 hy,
            fun h => ⟨_, _, rfl, rfl, h⟩⟩
  right_inv d :=
    --Porting note: by exact needed for unknown reason
    by exact
      ext fun x y =>
        ⟨fun h =>
          let ⟨_, _, hx, hy, H⟩ := h
          hx ▸ hy ▸ H,
          Con.induction_on₂ x y fun w z h => ⟨w, z, rfl, rfl, h⟩⟩
  map_rel_iff' := @fun s t => 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
s t : { d // c ≤ d }
⊢ {
          toFun := fun d =>
            mapOfSurjective (↑d) toQuotient (_ : ∀ (x x_1 : M), ↑(x * x_1) = ↑(x * x_1))
              (_ : mulKer toQuotient (_ : ∀ (x x_1 : M), ↑(x * x_1) = ↑(x * x_1)) ≤ ↑d)
              (_ : ∀ (q : Quotient c.toSetoid), ∃ a, ⟦a⟧ = q),
          invFun := fun d =>
            { val := comap toQuotient (_ : ∀ (x y : M), ↑(x * y) = ↑(x * y)) d,
              property := (_ : ∀ (x y : M), c x y → d ↑x ↑y) },
          left_inv :=
            (_ :
              ∀ (d : { d // c ≤ d }),
                (fun d =>
                      { val := comap toQuotient (_ : ∀ (x y : M), ↑(x * y) = ↑(x * y)) d,
                        property := (_ : ∀ (x y : M), c x y → d ↑x ↑y) })
                    ((fun d =>
                        mapOfSurjective (↑d) toQuotient (_ : ∀ (x x_1 : M), ↑(x * x_1) = ↑(x * x_1))
                          (_ : mulKer toQuotient (_ : ∀ (x x_1 : M), ↑(x * x_1) = ↑(x * x_1)) ≤ ↑d)
                          (_ : ∀ (q : Quotient c.toSetoid), ∃ a, ⟦a⟧ = q))
                      d) =
                  d),
          right_inv :=
            (_ :
              ∀ (d : Con (Con.Quotient c)),
                (fun d =>
                      mapOfSurjective (↑d) toQuotient (_ : ∀ (x x_1 : M), ↑(x * x_1) = ↑(x * x_1))
                        (_ : mulKer toQuotient (_ : ∀ (x x_1 : M), ↑(x * x_1) = ↑(x * x_1)) ≤ ↑d)
                        (_ : ∀ (q : Quotient c.toSetoid), ∃ a, ⟦a⟧ = q))
                    ((fun d =>
                        { val := comap toQuotient (_ : ∀ (x y : M), ↑(x * y) = ↑(x * y)) d,
                          property := (_ : ∀ (x y : M), c x y → d ↑x ↑y) })
                      d) =
                  d) }
        s ≤
      {
          toFun := fun d =>
            mapOfSurjective (↑d) toQuotient (_ : ∀ (x x_1 : M), ↑(x * x_1) = ↑(x * x_1))
              (_ : mulKer toQuotient (_ : ∀ (x x_1 : M), ↑(x * x_1) = ↑(x * x_1)) ≤ ↑d)
              (_ : ∀ (q : Quotient c.toSetoid), ∃ a, ⟦a⟧ = q),
          invFun := fun d =>
            { val := comap toQuotient (_ : ∀ (x y : M), ↑(x * y) = ↑(x * y)) d,
              property := (_ : ∀ (x y : M), c x y → d ↑x ↑y) },
          left_inv :=
            (_ :
              ∀ (d : { d // c ≤ d }),
                (fun d =>
                      { val := comap toQuotient (_ : ∀ (x y : M), ↑(x * y) = ↑(x * y)) d,
                        property := (_ : ∀ (x y : M), c x y → d ↑x ↑y) })
                    ((fun d =>
                        mapOfSurjective (↑d) toQuotient (_ : ∀ (x x_1 : M), ↑(x * x_1) = ↑(x * x_1))
                          (_ : mulKer toQuotient (_ : ∀ (x x_1 : M), ↑(x * x_1) = ↑(x * x_1)) ≤ ↑d)
                          (_ : ∀ (q : Quotient c.toSetoid), ∃ a, ⟦a⟧ = q))
                      d) =
                  d),
          right_inv :=
            (_ :
              ∀ (d : Con (Con.Quotient c)),
                (fun d =>
                      mapOfSurjective (↑d) toQuotient (_ : ∀ (x x_1 : M), ↑(x * x_1) = ↑(x * x_1))
                        (_ : mulKer toQuotient (_ : ∀ (x x_1 : M), ↑(x * x_1) = ↑(x * x_1)) ≤ ↑d)
                        (_ : ∀ (q : Quotient c.toSetoid), ∃ a, ⟦a⟧ = q))
                    ((fun d =>
                        { val := comap toQuotient (_ : ∀ (x y : M), ↑(x * y) = ↑(x * y)) d,
                          property := (_ : ∀ (x y : M), c x y → d ↑x ↑y) })
                      d) =
                  d) }
        t ↔
    s ≤ t

Next tactic:
constructor