------------------------------------------------------------------------
-- Aczel's structure identity principle (for 1-categories), more or
-- less as found in "Homotopy Type Theory: Univalent Foundations of
-- Mathematics" (first edition)
------------------------------------------------------------------------

{-# OPTIONS --without-K #-}

open import Equality

module Structure-identity-principle
  {reflexive} (eq :  {a p}  Equality-with-J a p reflexive) where

open import Bijection eq using (_↔_; module _↔_; Σ-≡,≡↔≡)
open import Category eq
open Derived-definitions-and-properties eq
open import Equality.Decidable-UIP eq
open import Equivalence eq as Eq
  hiding (id; _∘_; inverse; lift-equality)
open import Function-universe eq hiding (id) renaming (_∘_ to _⊚_)
open import H-level eq
open import H-level.Closure eq
open import Logical-equivalence using (module _⇔_)
open import Prelude as P hiding (id)
open import Univalence-axiom eq
open import Univalence-axiom.Isomorphism-is-equality.Simple eq
  using (Assumptions; module Assumptions;
         Universe; module Universe;
         module Class)

-- Standard notions of structure.

record Standard-notion-of-structure
         {c₁ c₂} ℓ₁ ℓ₂ (C : Precategory c₁ c₂) :
         Set (c₁  c₂  lsuc (ℓ₁  ℓ₂)) where
  open Precategory C

  field
    P               : Obj  Set ℓ₁
    H               :  {X Y} (p : P X) (q : P Y)  Hom X Y  Set ℓ₂
    H-prop          :  {X Y} {p : P X} {q : P Y}
                      (f : Hom X Y)  Is-proposition (H p q f)
    H-id            :  {X} {p : P X}  H p p id
    H-∘             :  {X Y Z} {p : P X} {q : P Y} {r : P Z} {f g} 
                      H p q f  H q r g  H p r (f  g)
    H-antisymmetric :  {X} (p q : P X) 
                      H p q id  H q p id  p  q

  -- P constructs sets. (The proof was suggested by Michael Shulman in
  -- a mailing list post.)

  P-set :  A  Is-set (P A)
  P-set A = propositional-identity⇒set
     p q  H p q id × H q p id)
     _ _  ×-closure 1 (H-prop id) (H-prop id))
     _  H-id , H-id)
     p q  uncurry (H-antisymmetric p q))

  -- Two Str morphisms (see below) of equal type are equal if their
  -- first components are equal.

  lift-equality : {X Y :  P} {f g :  (H (proj₂ X) (proj₂ Y))} 
                  proj₁ f  proj₁ g  f  g
  lift-equality eq =
    Σ-≡,≡→≡ eq (_⇔_.to propositional⇔irrelevant (H-prop _) _ _)

  -- A derived precategory.

  Str : Precategory (c₁  ℓ₁) (c₂  ℓ₂)
  Str = record { precategory =
     P ,
     { (X , p) (Y , q) 
          (H p q) ,
         Σ-closure 2 Hom-is-set  f  mono₁ 1 (H-prop f)) }) ,
    (id , H-id) ,
     { (f , hf) (g , hg)  f  g , H-∘ hf hg }) ,
    lift-equality left-identity ,
    lift-equality right-identity ,
    lift-equality assoc }

  module Str = Precategory Str

  -- A rearrangement lemma.

  proj₁-≡→≅-¹ :
     {X Y} (X≡Y : X  Y) 
    proj₁ (Str.≡→≅ X≡Y Str.¹) 
    elim  {X Y} _  Hom X Y)  _  id) (cong proj₁ X≡Y)
  proj₁-≡→≅-¹ {X , p} = elim¹
     X≡Y  proj₁ (Str.≡→≅ X≡Y Str.¹) 
             elim  {X Y} _  Hom X Y)  _  id) (cong proj₁ X≡Y))
    (proj₁ (Str.≡→≅ (refl (X , p)) Str.¹)                               ≡⟨ cong (proj₁  Str._¹) $ elim-refl  {X Y} _  X Str.≅ Y) _ 
     proj₁ (Str.id {X = X , p})                                         ≡⟨⟩
     id {X = X}                                                         ≡⟨ sym $ elim-refl  {X Y} _  Hom X Y) _ 
     elim  {X Y} _  Hom X Y)  _  id) (refl X)                     ≡⟨ cong (elim  {X Y} _  Hom X Y) _) $ sym $ cong-refl proj₁ ⟩∎
     elim  {X Y} _  Hom X Y)  _  id) (cong proj₁ (refl (X , p)))  )

-- The structure identity principle states that the precategory Str is
-- a category (assuming extensionality).
--
-- The proof below is based on (but not quite identical to) the one in
-- "Homotopy Type Theory: Univalent Foundations of Mathematics" (first
-- edition).

abstract

  structure-identity-principle :
     {c₁ c₂ ℓ₁ ℓ₂} 
    Extensionality (ℓ₁  ℓ₂) (ℓ₁  ℓ₂) 
    (C : Category c₁ c₂) 
    (S : Standard-notion-of-structure ℓ₁ ℓ₂ (Category.precategory C)) 
     {X Y}  Is-equivalence
                (Precategory.≡→≅ (Standard-notion-of-structure.Str S)
                                 {X} {Y})
  structure-identity-principle ext C S =
    Str.≡→≅-equivalence-lemma ≡≃≅ ≡≃≅-refl
    where
    open Standard-notion-of-structure S
    module C = Category C

    -- _≡_ is pointwise equivalent to Str._≅_.

    module ≅HH≃≅ where

      to :  {X Y} {p : P X} {q : P Y} 
           ( λ (f : X C.≅ Y)  H p q (f C.¹) × H q p (f C.⁻¹)) 
           (X , p) Str.≅ (Y , q)
      to ((f , f⁻¹ , f∙f⁻¹ , f⁻¹∙f) , Hf , Hf⁻¹) =
        (f , Hf) , (f⁻¹ , Hf⁻¹) ,
        lift-equality f∙f⁻¹ ,
        lift-equality f⁻¹∙f

    ≅HH≃≅ :  {X Y} {p : P X} {q : P Y} 
            ( λ (f : X C.≅ Y)  H p q (f C.¹) × H q p (f C.⁻¹)) 
            ((X , p) Str.≅ (Y , q))
    ≅HH≃≅ {X} {Y} {p} {q} = ↔⇒≃ (record
      { surjection = record
        { logical-equivalence = record
          { to   = ≅HH≃≅.to
          ; from = from
          }
        ; right-inverse-of = to∘from
        }
      ; left-inverse-of = from∘to
      })
      where
      from : (X , p) Str.≅ (Y , q) 
              λ (f : X C.≅ Y)  H p q (f C.¹) × H q p (f C.⁻¹)
      from ((f , Hf) , (f⁻¹ , Hf⁻¹) , f∙f⁻¹ , f⁻¹∙f) =
        (f , f⁻¹ , cong proj₁ f∙f⁻¹ , cong proj₁ f⁻¹∙f) , Hf , Hf⁻¹

      to∘from :  p  ≅HH≃≅.to (from p)  p
      to∘from ((f , Hf) , (f⁻¹ , Hf⁻¹) , f∙f⁻¹ , f⁻¹∙f) =
        cong₂  f∙f⁻¹ f⁻¹∙f 
                 (f , Hf) , (f⁻¹ , Hf⁻¹) , f∙f⁻¹ , f⁻¹∙f)
              (_⇔_.to set⇔UIP Str.Hom-is-set _ _)
              (_⇔_.to set⇔UIP Str.Hom-is-set _ _)

      from∘to :  p  from (≅HH≃≅.to p)  p
      from∘to ((f , f⁻¹ , f∙f⁻¹ , f⁻¹∙f) , Hf , Hf⁻¹) =
        cong₂  f∙f⁻¹ f⁻¹∙f  (f , f⁻¹ , f∙f⁻¹ , f⁻¹∙f) , Hf , Hf⁻¹)
              (_⇔_.to set⇔UIP C.Hom-is-set _ _)
              (_⇔_.to set⇔UIP C.Hom-is-set _ _)

    module ≡≡≃≅HH where

      to :  {X Y} {p : P X} {q : P Y} 
           (X≡Y : X  Y)  subst P X≡Y p  q 
           H p q (C.≡→≅ X≡Y C.¹) × H q p (C.≡→≅ X≡Y C.⁻¹)
      to {X} {p = p} X≡Y p≡q = elim¹
         X≡Y   {q}  subst P X≡Y p  q 
                 H p q (C.≡→≅ X≡Y C.¹) × H q p (C.≡→≅ X≡Y C.⁻¹))
        (elim¹
            {q} _  H p q (C.≡→≅ (refl X) C.¹) ×
                      H q p (C.≡→≅ (refl X) C.⁻¹))
           ( subst  { (q , f)  H p q f })
                   (sym $ cong₂ _,_
                            (subst P (refl X) p  ≡⟨ subst-refl P _ ⟩∎
                             p                   )
                            (C.≡→≅ (refl X) C.¹  ≡⟨ cong C._¹ C.≡→≅-refl ⟩∎
                             C.id                ))
                   H-id
           , subst  { (q , f)  H q p f })
                   (sym $ cong₂ _,_
                            (subst P (refl X) p  ≡⟨ subst-refl P _ ⟩∎
                             p                   )
                            (C.≡→≅ (refl X) C.⁻¹  ≡⟨ cong C._⁻¹ C.≡→≅-refl ⟩∎
                             C.id                 ))
                   H-id
           ))
        X≡Y p≡q

      to-refl :  {X} {p : P X} 
                subst  f  H p p (f C.¹) × H p p (f C.⁻¹))
                      C.≡→≅-refl
                      (to (refl X) (subst-refl P p)) 
                (H-id , H-id)
      to-refl =
        cong₂ _,_ (_⇔_.to propositional⇔irrelevant (H-prop _) _ _)
                  (_⇔_.to propositional⇔irrelevant (H-prop _) _ _)

    ≡≡≃≅HH :  {X Y} {p : P X} {q : P Y} 
             ( λ (eq : X  Y)  subst P eq p  q) 
             ( λ (f : X C.≅ Y)  H p q (f C.¹) × H q p (f C.⁻¹))
    ≡≡≃≅HH {X} {p = p} {q} =
      Σ-preserves C.≡≃≅ λ X≡Y 
        _↔_.to (⇔↔≃ ext (P-set _ _ _)
                        (×-closure 1 (H-prop _) (H-prop _)))
               (record { to = ≡≡≃≅HH.to X≡Y ; from = from X≡Y })
      where
      from :  X≡Y  H p q (C.≡→≅ X≡Y C.¹) × H q p (C.≡→≅ X≡Y C.⁻¹) 
             subst P X≡Y p  q
      from X≡Y ( , H⁻¹) = elim¹
         {Y} X≡Y   {q} 
                     H p q (C.≡→≅ X≡Y C.¹)  H q p (C.≡→≅ X≡Y C.⁻¹) 
                     subst P X≡Y p  q)
         {q}  H⁻¹ 
           subst P (refl X) p  ≡⟨ subst-refl P _ 
           p                   ≡⟨ H-antisymmetric p q
                                    (subst (H p q) (cong C._¹  C.≡→≅-refl) )
                                    (subst (H q p) (cong C._⁻¹ C.≡→≅-refl) H⁻¹) ⟩∎
           q                   )
        X≡Y  H⁻¹

    ≡≃≅ :  {X Y} {p : P X} {q : P Y} 
          _≡_ {A =  P} (X , p) (Y , q)  ((X , p) Str.≅ (Y , q))
    ≡≃≅ = ≅HH≃≅  ≡≡≃≅HH  ↔⇒≃ (inverse Σ-≡,≡↔≡)

    -- …and the proof maps reflexivity to the identity morphism.

    ≡≃≅-refl :  {Xp}  _≃_.to ≡≃≅ (refl Xp)  Str.id≅
    ≡≃≅-refl {X , p} =
      ≅HH≃≅.to (_≃_.to ≡≡≃≅HH (Σ-≡,≡←≡ (refl (_,_ {B = P} X p))))      ≡⟨ cong (≅HH≃≅.to  _≃_.to ≡≡≃≅HH) $ Σ-≡,≡←≡-refl {B = P} 
      ≅HH≃≅.to (_≃_.to ≡≡≃≅HH (refl X , subst-refl P p))               ≡⟨⟩
      ≅HH≃≅.to (C.≡→≅ (refl X) , ≡≡≃≅HH.to (refl X) (subst-refl P p))  ≡⟨ cong ≅HH≃≅.to $ Σ-≡,≡→≡ C.≡→≅-refl ≡≡≃≅HH.to-refl 
      ≅HH≃≅.to (C.id≅ , H-id , H-id)                                   ≡⟨ refl _ ⟩∎
      Str.id≅                                                          

------------------------------------------------------------------------
-- An example

-- The structure identity principle can be used to prove a slightly
-- restricted variant of isomorphism-is-equality (which is defined in
-- Univalence-axiom.Isomorphism-is-equality.Simple.Class).

isomorphism-is-equality′ :
  (Univ : Universe)  let open Universe Univ in
  Assumptions 
   c X Y 
  (∀ {B}  Is-set B  Is-set (El (proj₁ c) B))   -- Extra assumption.
  Is-set (proj₁ X)  Is-set (proj₁ Y)            -- Extra assumptions.
  Class.Isomorphic Univ c X Y  (X  Y)
isomorphism-is-equality′ Univ ass
  (a , P) (C , x , p) (D , y , q) El-set C-set D-set = isomorphic

  module Isomorphism-is-equality′ where

  open Assumptions ass
  open Universe Univ
  open Class Univ using (Isomorphic; Carrier)

  -- The category of sets and functions.

  Fun : Category (# 2) (# 1)
  Fun = category-Set (# 1) ext univ₁

  module Fun = Category Fun

  -- The category of sets and bijections.

  Bij : Category (# 2) (# 1)
  Bij = category-Set-≅ (# 1) ext univ₁

  module Bij = Category Bij

  -- If two sets are isomorphic, then the underlying types are
  -- equivalent.

  ≅⇒≃ : (C D : Fun.Obj)  C Fun.≅ D  Type C  Type D
  ≅⇒≃ C D = _≃_.from (≃≃≅-Set (# 1) ext C D)

  -- The "standard notion of structure" that the structure identity
  -- principle is instantiated with.

  S : Standard-notion-of-structure (# 1) (# 1) Bij.precategory
  S = record
    { P               = El a  Type
    ; H               = λ {C D} x y C≅D 
                          Is-isomorphism a (≅⇒≃ C D C≅D) x y
    ; H-prop          = λ {_ C} _  El-set (proj₂ C) _ _
    ; H-id            = λ {C x} 
                          resp a (≅⇒≃ C C (Bij.id {X = C})) x  ≡⟨ cong  eq  resp a eq x) $ Eq.lift-equality ext (refl _) 
                          resp a Eq.id x                       ≡⟨ resp-id ass a x ⟩∎
                          x                                    
    ; H-∘             = λ {B C D x y z B≅C C≅D} x≅y y≅z 
                          resp a (≅⇒≃ B D (B≅C Bij.∙ C≅D)) x             ≡⟨ cong  eq  resp a eq x) $ Eq.lift-equality ext (refl _) 
                          resp a (≅⇒≃ C D C≅D  ≅⇒≃ B C B≅C) x           ≡⟨ resp-preserves-compositions (El a) (resp a) (resp-id ass a)
                                                                                                        univ₁ ext (≅⇒≃ B C B≅C) (≅⇒≃ C D C≅D) x 
                          resp a (≅⇒≃ C D C≅D) (resp a (≅⇒≃ B C B≅C) x)  ≡⟨ cong (resp a (≅⇒≃ C D C≅D)) x≅y 
                          resp a (≅⇒≃ C D C≅D) y                         ≡⟨ y≅z ⟩∎
                          z                                              
    ; H-antisymmetric = λ {C} x y x≡y _ 
                          x                                    ≡⟨ sym $ resp-id ass a x 
                          resp a Eq.id x                       ≡⟨ cong  eq  resp a eq x) $ Eq.lift-equality ext (refl _) 
                          resp a (≅⇒≃ C C (Bij.id {X = C})) x  ≡⟨ x≡y ⟩∎
                          y                                    
    }

  open module S = Standard-notion-of-structure S
    using (H; Str; module Str)

  abstract

    -- Every Str morphism is an isomorphism.

    Str-homs-are-isos :
       {C D x y} (f :  (H {X = C} {Y = D} x y)) 
      Str.Is-isomorphism {X = C , x} {Y = D , y} f
    Str-homs-are-isos {C} {D} {x} {y} (C≅D , x≅y) =

      (D≅C ,
       (resp a (≅⇒≃ D C D≅C) y            ≡⟨ cong  eq  resp a eq y) $ Eq.lift-equality ext (refl _) 
        resp a (inverse $ ≅⇒≃ C D C≅D) y  ≡⟨ resp-preserves-inverses (El a) (resp a) (resp-id ass a) univ₁ ext (≅⇒≃ C D C≅D) _ _ x≅y ⟩∎
        x                                 )) ,

      S.lift-equality {X = C , x} {Y = C , x} (
        C≅D Fun.∙≅ D≅C   ≡⟨ _≃_.from (Fun.≡≃≡¹ {X = C} {Y = C}) (Fun._¹⁻¹ {X = C} {Y = D} C≅D) ⟩∎
        Fun.id≅ {X = C}  ) ,

      S.lift-equality {X = D , y} {Y = D , y} (
        D≅C Fun.∙≅ C≅D   ≡⟨ _≃_.from (Fun.≡≃≡¹ {X = D} {Y = D}) (Fun._⁻¹¹ {X = C} {Y = D} C≅D) ⟩∎
        Fun.id≅ {X = D}  )

      where

      D≅C : D Fun.≅ C
      D≅C = Fun._⁻¹≅ {X = C} {Y = D} C≅D

    -- The isomorphism that should be constructed.

    isomorphic : Isomorphic (a , P) (C , x , p) (D , y , q) 
                 ((C , x , p)  (D , y , q))
    isomorphic =
      Σ (C  D)  eq  Is-isomorphism a eq x y)     ↝⟨ (let ≃≃≅-CD = ≃≃≅-Set (# 1) ext (C , C-set) (D , D-set) in
                                                         Σ-cong ≃≃≅-CD  eq 
                                                           let eq′ = _≃_.from ≃≃≅-CD (_≃_.to ≃≃≅-CD eq) in
                                                           Is-isomorphism a eq  x y  ↝⟨ ≡⇒↝ _ $ cong  eq  Is-isomorphism a eq x y) $ sym $
                                                                                          _≃_.left-inverse-of ≃≃≅-CD eq 
                                                           Is-isomorphism a eq′ x y  )) 
       (H {X = C , C-set} {Y = D , D-set} x y)      ↝⟨ inverse ×-right-identity 
       (H {X = C , C-set} {Y = D , D-set} x y) ×   ↝⟨ ∃-cong  X≅Y  _⇔_.to contractible⇔⊤↔ $ propositional⇒inhabited⇒contractible
                                                                          (Str.Is-isomorphism-propositional X≅Y)
                                                                          (Str-homs-are-isos X≅Y)) 
      (((C , C-set) , x) Str.≅ ((D , D-set) , y))    ↔⟨ inverse  _ , structure-identity-principle ext Bij S
                                                                        {X = (C , C-set) , x} {Y = (D , D-set) , y}  
      (((C , C-set) , x)  ((D , D-set) , y))        ↔⟨ ≃-≡ $ ↔⇒≃ (Σ-assoc  ∃-cong  _  ×-comm)  inverse Σ-assoc) 
      (((C , x) , C-set)  ((D , y) , D-set))        ↝⟨ inverse $ ignore-propositional-component (H-level-propositional ext 2) 
      ((C , x)  (D , y))                            ↝⟨ ignore-propositional-component (proj₂ (P D y) ass) 
      (((C , x) , p)  ((D , y) , q))                ↔⟨ ≃-≡ $ ↔⇒≃ Σ-assoc ⟩□
      ((C , x , p)  (D , y , q))                    

    -- A simplification lemma.

    proj₁-from-isomorphic :
       X≡Y 
      proj₁ (_↔_.from isomorphic X≡Y) 
      elim  {X Y} _  proj₁ X  proj₁ Y)  _  Eq.id) X≡Y
    proj₁-from-isomorphic X≡Y = Eq.lift-equality ext (

      _≃_.to (proj₁ (_↔_.from isomorphic X≡Y))                         ≡⟨⟩

      cast C-set D-set X≡Y                                             ≡⟨ lemma ⟩∎

      _≃_.to (elim  {X Y} _  proj₁ X  proj₁ Y)  _  Eq.id) X≡Y)  )

      where

      cast :  {X Y} 
             Is-set (Carrier (a , P) X)  Is-set (Carrier (a , P) Y) 
             X  Y  Carrier (a , P) X  Carrier (a , P) Y
      cast {C , x , p} {D , y , q} C-set D-set X≡Y =
        proj₁ $ proj₁ $ proj₁ $
        Str.≡→≅ {X = (C , C-set) , x} {Y = (D , D-set) , y} $
        cong  { ((C , x) , C-set)  (C , C-set) , x }) $
        Σ-≡,≡→≡ (proj₁ (Σ-≡,≡←≡
                   (cong  { (C , (x , p))  (C , x) , p }) X≡Y)))
                (proj₁ (H-level-propositional ext 2 _ _))

      lemma :
        cast C-set D-set X≡Y 
        _≃_.to (elim  {X Y} _  proj₁ X  proj₁ Y)  _  Eq.id) X≡Y)
      lemma = elim¹
         X≡Y   D-set  cast C-set D-set X≡Y 
                           _≃_.to (elim  {X Y} _  proj₁ X  proj₁ Y)
                                         _  Eq.id) X≡Y))
         C-set′ 

           cast C-set C-set′ (refl (C , x , p))                      ≡⟨ cong  eq 
                                                                                proj₁ $ proj₁ $ proj₁ $
                                                                                Str.≡→≅ {X = (C , C-set) , x} {Y = (C , C-set′) , x} $
                                                                                cong  { ((C , x) , C-set)  (C , C-set) , x }) $
                                                                                Σ-≡,≡→≡ (proj₁ (Σ-≡,≡←≡ {B = proj₁  uncurry P} eq))
                                                                                        (proj₁ (H-level-propositional ext 2 _ _)))
                                                                             (cong-refl  { (C , (x , p))  (C , x) , p })) 
           (proj₁ $ proj₁ $ proj₁ $
            Str.≡→≅ {X = (C , C-set) , x} {Y = (C , C-set′) , x} $
            cong  { ((C , x) , C-set)  (C , C-set) , x }) $
            Σ-≡,≡→≡ (proj₁ (Σ-≡,≡←≡ (refl ((C , x) , p))))
                    (proj₁ (H-level-propositional ext 2 _ _)))       ≡⟨ cong proj₁ (S.proj₁-≡→≅-¹ _) 

           (proj₁ $
            Fun.≡→≅ $
            cong proj₁ $
            cong  { ((C , x) , C-set)  (C , C-set) , x }) $
            Σ-≡,≡→≡ (proj₁ (Σ-≡,≡←≡ (refl ((C , x) , p))))
                    (proj₁ (H-level-propositional ext 2 _ _)))       ≡⟨ cong (proj₁  Fun.≡→≅) $
                                                                          cong-∘ proj₁  { ((C , x) , C-set)  (C , C-set) , x }) _ 
           (proj₁ $
            Fun.≡→≅ $
            cong  { ((C , _) , C-set)  C , C-set }) $
            Σ-≡,≡→≡ (proj₁ (Σ-≡,≡←≡ (refl ((C , x) , p))))
                    (proj₁ (H-level-propositional ext 2 _ _)))       ≡⟨ Fun.≡→≅-¹ _ 

           (elim  {X Y} _  Fun.Hom X Y)  _  P.id) $
            cong  { ((C , _) , C-set)  C , C-set }) $
            Σ-≡,≡→≡ (proj₁ (Σ-≡,≡←≡ (refl ((C , x) , p))))
                    (proj₁ (H-level-propositional ext 2 _ _)))       ≡⟨ elim¹  eq  elim  {X Y} _  Fun.Hom X Y)  _  P.id) eq 
                                                                                      ≡⇒↝ implication (cong proj₁ eq))
                        (elim  {X Y} _  Fun.Hom X Y)  _  P.id)
                              (refl (C , C-set))                          ≡⟨ elim-refl  {X Y} _  Fun.Hom X Y) _ 
                         P.id                                             ≡⟨ sym $ elim-refl  {A B} _  A  B) _ 
                         ≡⇒↝ implication (refl C)                         ≡⟨ cong (≡⇒↝ implication) (sym $ cong-refl proj₁) ⟩∎
                         ≡⇒↝ implication (cong proj₁ (refl (C , C-set)))  ) _ 

           (≡⇒↝ implication $
            cong proj₁ $
            cong  { ((C , _) , C-set)  C , C-set }) $
            Σ-≡,≡→≡ (proj₁ (Σ-≡,≡←≡ (refl ((C , x) , p))))
                    (proj₁ (H-level-propositional ext 2 _ _)))       ≡⟨ cong (≡⇒↝ implication)
                                                                             (cong-∘ proj₁  { ((C , _) , C-set)  C , C-set }) _) 
           (≡⇒↝ implication $
            cong  { ((C , _) , _)  C }) $
            Σ-≡,≡→≡ (proj₁ (Σ-≡,≡←≡ (refl ((C , x) , p))))
                    (proj₁ (H-level-propositional ext 2 _ _)))       ≡⟨ cong  eq 
                                                                                ≡⇒↝ implication $
                                                                                cong  { ((C , _) , _)  C }) $
                                                                                Σ-≡,≡→≡ (proj₁ {B = λ q  subst (proj₁  uncurry P) q p  p} eq)
                                                                                        (proj₁ (H-level-propositional ext 2 _ C-set′)))
                                                                             (Σ-≡,≡←≡-refl {B = λ { (C , x)  proj₁ (P C x)}}) 
           (≡⇒↝ implication $
            cong  { ((C , _) , _)  C }) $
            Σ-≡,≡→≡ (refl (C , x))
                    (proj₁ (H-level-propositional ext 2 _ _)))       ≡⟨ cong (≡⇒↝ implication  cong  { ((C , _) , _)  C }))
                                                                             (Σ-≡,≡→≡-reflˡ (proj₁ (H-level-propositional ext 2 _ _))) 
           (≡⇒↝ implication $
            cong  { ((C , _) , _)  C }) $
            cong (_,_ (C , x))
                 (trans (sym $ subst-refl (Is-set  proj₁) C-set)
                        (proj₁ (H-level-propositional ext 2 _ _))))  ≡⟨ cong (≡⇒↝ implication)
                                                                             (cong-∘  { ((C , _) , _)  C }) (_,_ (C , x)) _) 
           (≡⇒↝ implication $
            cong (const C)
                 (trans (sym $ subst-refl (Is-set  proj₁) C-set)
                        (proj₁ (H-level-propositional ext 2 _ _))))  ≡⟨ cong (≡⇒↝ implication) (cong-const _) 

           ≡⇒↝ implication (refl C)                                  ≡⟨ ≡⇒↝-refl 

           P.id                                                      ≡⟨ sym $ cong _≃_.to $ elim-refl  {X Y} _  proj₁ X  proj₁ Y) _ ⟩∎

           _≃_.to (elim  {X Y} _  proj₁ X  proj₁ Y)
                         _  Eq.id)
                        (refl (C , x , p)))                          )

        X≡Y D-set

abstract

  -- The from component of isomorphism-is-equality′ is equal
  -- to a simple function.

  from-isomorphism-is-equality′ :
     Univ ass c X Y  let open Universe Univ; open Class Univ in
    (El-set :  {B}  Is-set B  Is-set (El (proj₁ c) B)) 
     I-set J-set 
    _↔_.from (isomorphism-is-equality′
                Univ ass c X Y El-set I-set J-set) 
    elim  {X Y} _  Isomorphic c X Y)
          { (_ , x , _)  Eq.id , resp-id ass (proj₁ c) x })
  from-isomorphism-is-equality′ Univ ass c X Y El-set I-set J-set =
    ext λ eq 
      Σ-≡,≡→≡ (lemma eq) (_⇔_.to set⇔UIP (El-set J-set) _ _)
    where
    open Assumptions ass
    open Universe Univ
    open Class Univ

    lemma :
       eq 
      proj₁ (_↔_.from (isomorphism-is-equality′
                         Univ ass c X Y El-set I-set J-set) eq) 
      proj₁ (elim  {X Y} _  Isomorphic c X Y)
                   { (_ , x , _)  Eq.id , resp-id ass (proj₁ c) x })
                  eq)
    lemma eq =
      proj₁ (_↔_.from (isomorphism-is-equality′
                         Univ ass c X Y El-set I-set J-set) eq)          ≡⟨ Isomorphism-is-equality′.proj₁-from-isomorphic
                                                                              Univ ass _ _ _ _ _ _ _ _ El-set I-set J-set eq 
      elim  {X Y} _  proj₁ X  proj₁ Y)  _  Eq.id) eq              ≡⟨ sym $ elim-∘  {X Y} _  Isomorphic c X Y) _ proj₁ _ ⟩∎
      proj₁ (elim  {X Y} _  Isomorphic c X Y)
                   { (_ , x , _)  Eq.id , resp-id ass (proj₁ c) x })
                  eq)