/-- If `A : S.obj B ⟶ T` is a costructured arrow for `S : C ⥤ D` and `T : D`, then we can
    explicitly describe the quotients of `A` as the quotients `P` of `B` in `C` for which `A.hom`
    factors through the image of `P` under `S`. -/
def quotientEquiv [HasColimits C] [PreservesColimits S] (A : CostructuredArrow S T) :
    Subobject (op A) ≃o { P : Subobject (op A.left) // ∃ q, S.map P.arrow.unop ≫ q = A.hom } where
  toFun P := ⟨projectQuotient P, projectQuotient_factors P⟩
  invFun P := liftQuotient P.val P.prop.choose_spec
  left_inv P := lift_projectQuotient _ _
  right_inv P := Subtype.ext (by simp only [liftQuotient, Quiver.Hom.unop_op, homMk_left,
      Quiver.Hom.op_unop, projectQuotient_mk, Subobject.mk_arrow])
  map_rel_iff' := by
    apply Subobject.ind₂
    intro P Q f g hf hg
    

Proof state:
case h
C : Type u₁
inst✝³ : Category.{v, u₁} C
D : Type u₂
inst✝² : Category.{v, u₂} D
S : C ⥤ D
T : D
inst✝¹ : HasColimits C
inst✝ : PreservesColimits S
A : CostructuredArrow S T
P Q : (CostructuredArrow S T)ᵒᵖ
f : P ⟶ op A
g : Q ⟶ op A
hf : Mono f
hg : Mono g
⊢ {
          toFun := fun P =>
            { val := projectQuotient P,
              property := (_ : ∃ q, S.map (Subobject.arrow (projectQuotient P)).unop ≫ q = A.hom) },
          invFun := fun P =>
            liftQuotient ↑P
              (_ :
                S.map (Subobject.arrow ↑P).unop ≫ Exists.choose (_ : ∃ q, S.map (Subobject.arrow ↑P).unop ≫ q = A.hom) =
                  A.hom),
          left_inv :=
            (_ :
              ∀ (P : Subobject (op A)),
                liftQuotient (projectQuotient P)
                    (_ :
                      S.map
                            (Subobject.arrow
                                ↑((fun P =>
                                      { val := projectQuotient P,
                                        property :=
                                          (_ : ∃ q, S.map (Subobject.arrow (projectQuotient P)).unop ≫ q = A.hom) })
                                    P)).unop ≫
                          Exists.choose
                            (_ :
                              ∃ q,
                                S.map
                                      (Subobject.arrow
                                          ↑((fun P =>
                                                { val := projectQuotient P,
                                                  property :=
                                                    (_ :
                                                      ∃ q,
                                                        S.map (Subobject.arrow (projectQuotient P)).unop ≫ q = A.hom) })
                                              P)).unop ≫
                                    q =
                                  A.hom) =
                        A.hom) =
                  P),
          right_inv :=
            (_ :
              ∀ (P : { P // ∃ q, S.map (Subobject.arrow P).unop ≫ q = A.hom }),
                (fun P =>
                      { val := projectQuotient P,
                        property := (_ : ∃ q, S.map (Subobject.arrow (projectQuotient P)).unop ≫ q = A.hom) })
                    ((fun P =>
                        liftQuotient ↑P
                          (_ :
                            S.map (Subobject.arrow ↑P).unop ≫
                                Exists.choose (_ : ∃ q, S.map (Subobject.arrow ↑P).unop ≫ q = A.hom) =
                              A.hom))
                      P) =
                  P) }
        (Subobject.mk f) ≤
      {
          toFun := fun P =>
            { val := projectQuotient P,
              property := (_ : ∃ q, S.map (Subobject.arrow (projectQuotient P)).unop ≫ q = A.hom) },
          invFun := fun P =>
            liftQuotient ↑P
              (_ :
                S.map (Subobject.arrow ↑P).unop ≫ Exists.choose (_ : ∃ q, S.map (Subobject.arrow ↑P).unop ≫ q = A.hom) =
                  A.hom),
          left_inv :=
            (_ :
              ∀ (P : Subobject (op A)),
                liftQuotient (projectQuotient P)
                    (_ :
                      S.map
                            (Subobject.arrow
                                ↑((fun P =>
                                      { val := projectQuotient P,
                                        property :=
                                          (_ : ∃ q, S.map (Subobject.arrow (projectQuotient P)).unop ≫ q = A.hom) })
                                    P)).unop ≫
                          Exists.choose
                            (_ :
                              ∃ q,
                                S.map
                                      (Subobject.arrow
                                          ↑((fun P =>
                                                { val := projectQuotient P,
                                                  property :=
                                                    (_ :
                                                      ∃ q,
                                                        S.map (Subobject.arrow (projectQuotient P)).unop ≫ q = A.hom) })
                                              P)).unop ≫
                                    q =
                                  A.hom) =
                        A.hom) =
                  P),
          right_inv :=
            (_ :
              ∀ (P : { P // ∃ q, S.map (Subobject.arrow P).unop ≫ q = A.hom }),
                (fun P =>
                      { val := projectQuotient P,
                        property := (_ : ∃ q, S.map (Subobject.arrow (projectQuotient P)).unop ≫ q = A.hom) })
                    ((fun P =>
                        liftQuotient ↑P
                          (_ :
                            S.map (Subobject.arrow ↑P).unop ≫
                                Exists.choose (_ : ∃ q, S.map (Subobject.arrow ↑P).unop ≫ q = A.hom) =
                              A.hom))
                      P) =
                  P) }
        (Subobject.mk g) ↔
    Subobject.mk f ≤ Subobject.mk g

Next tactic:
refine' ⟨fun h => Subobject.mk_le_mk_of_comm _ _, fun h => _⟩