Library HoTT.Categories.UniversalProperties

Universal morphisms

Require Import Category.Core Functor.Core.
Require Import Category.Dual Functor.Dual.
Require Import Category.Objects.
Require Import InitialTerminalCategory.Core InitialTerminalCategory.Functors.
Require Comma.Core.
Local Set Warnings Append "-notation-overridden". (* work around bug 5567, https://coq.inria.fr/bugs/show_bug.cgi?id=5567, notation-overridden,parsing should not trigger for only printing notations *)
Import Comma.Core.
Local Set Warnings Append "notation-overridden".
Require Import Trunc Types.Sigma HoTT.Tactics.
Require Import Basics.Tactics.

Set Universe Polymorphism.
Set Implicit Arguments.
Generalizable All Variables.
Set Asymmetric Patterns.

Local Open Scope morphism_scope.

Section UniversalMorphism.
Quoting Wikipedia:
Suppose that U : D C is a functor from a category D to a category C, and let X be an object of C. Consider the following dual (opposite) notions:

  Local Ltac univ_hprop_t UniversalProperty :=
    apply @istrunc_succ in UniversalProperty;
    eapply @istrunc_sigma;
    first [ intro;
            simpl;
            match goal with
              | [ |- context[?m o 1] ]
                ⇒ simpl rewrite (right_identity _ _ _ m)
              | [ |- context[1 o ?m] ]
                ⇒ simpl rewrite (left_identity _ _ _ m)
            end;
            assumption
          | by typeclasses eauto ].

Initial morphisms

  Section InitialMorphism.

Definition

    Variables C D : PreCategory.

    Variable X : C.
    Variable U : Functor D C.
An initial morphism from X to U is an initial object in the category (X U) of morphisms from X to U. In other words, it consists of a pair (A, φ) where A is an object of D and φ: X U A is a morphism in C, such that the following initial property is satisfied:
  • Whenever Y is an object of D and f : X U Y is a morphism in C, then there exists a unique morphism g : A Y such that the following diagram commutes:
             φ
         X -----> U A       A
          \        .        .
            \      . U g    . g
           f  \    .        .
               ↘   ↓        ↓
                 U Y        Y

    Definition IsInitialMorphism (Ap : object (X / U)) :=
      IsInitialObject (X / U) Ap.

Introduction rule

    Section IntroductionAbstractionBarrier.
      Definition Build_IsInitialMorphism
                 (*(Ap : Object (X ↓ U))*)
                 (A : D)(* := CCO_b Ap*)
                 (p : morphism C X (U A))(*:= CCO_f Ap*)
                 (Ap := CommaCategory.Build_object !X U tt A p)
                 (UniversalProperty
                  : (A' : D) (p' : morphism C X (U A')),
                      Contr { m : morphism D A A'
                            | U _1 m o p = p' })
      : IsInitialMorphism Ap.
      Proof.
        intro x.
        specialize (UniversalProperty (CommaCategory.b x) (CommaCategory.f x)).
We want to preserve the computation rules for the morphisms, even though they're unique up to unique isomorphism.
        eapply istrunc_equiv_istrunc.
        - apply CommaCategory.issig_morphism.
        - apply contr_inhabited_hprop.
          + abstract univ_hprop_t UniversalProperty.
          + ( tt).
            ( (@center _ UniversalProperty).1).
            abstract (progress rewrite ?right_identity, ?left_identity;
                      exact (@center _ UniversalProperty).2).
      Defined.

      Definition Build_IsInitialMorphism_curried
                 (A : D)
                 (p : morphism C X (U A))
                 (Ap := CommaCategory.Build_object !X U tt A p)
                 (m : (A' : D) (p' : morphism C X (U A')),
                        morphism D A A')
                 (H : (A' : D) (p' : morphism C X (U A')),
                        U _1 (m A' p') o p = p')
                 (H' : (A' : D) (p' : morphism C X (U A')) m',
                         U _1 m' o p = p'
                          m A' p' = m')
      : IsInitialMorphism Ap
        := Build_IsInitialMorphism
             A
             p
             (fun A' p'
                Build_Contr _ (m A' p'; H A' p')
                              (fun m'path_sigma
                                 _
                                 (m A' p'; H A' p')
                                 m'
                                 (H' A' p' m'.1 m'.2)
                                 (center _))).

Projections from nested sigmas are currently rather slow. We should just be able to do
      Definition Build_IsInitialMorphism_uncurried
                 (univ
                  : { A : D
                    | { p : morphism C X (U A)
                       | let Ap := CommaCategory.Build_object !X U tt A p in
                         forall (A' : D) (p' : morphism C X (U A')),
                           { m : morphism D A A'
                           | { H : U _1 m o p = p'
                             | forall m',
                                 U _1 m' o p = p'
                                 -> m = m' }}}})
        := @Build_IsInitialMorphism_curried
             (univ.1)
             (univ.2.1)
             (fun A' p' => (univ.2.2 A' p').1)
             (fun A' p' => (univ.2.2 A' p').2.1)
             (fun A' p' => (univ.2.2 A' p').2.2).
But that's currently too slow. (About 6-8 seconds, on my machine.) So instead we factor out all of the type parts by hand, and then apply them after.

      Let make_uncurried A' B' C' D' E'0
          (E'1 : a a' b b' (c : C' a a'), D' a a' b b' c E'0 a a' Type)
          (E' : a a' b b' (c : C' a a'), D' a a' b b' c E'0 a a' Type)
          F'
          (f : (a : A')
                      (b : B' a)
                      (c : (a' : A') (b' : B' a'),
                             C' a a')
                      (d : (a' : A') (b' : B' a'),
                             D' a a' b b' (c a' b'))
                      (e : (a' : A') (b' : B' a')
                                  (e0 : E'0 a a')
                                  (e1 : E'1 a a' b b' (c a' b') (d a' b') e0),
                             E' a a' b b' (c a' b') (d a' b') e0),
                 F' a b)
          (univ
           : { a : A'
             | { b : B' a
               | (a' : A') (b' : B' a'),
                   { c : C' a a'
                   | { d : D' a a' b b' c
                     | (e0 : E'0 a a')
                              (e1 : E'1 a a' b b' c d e0),
                         E' a a' b b' c d e0 }}}})
      : F' univ.1 univ.2.1
        := f
             (univ.1)
             (univ.2.1)
             (fun A' p'(univ.2.2 A' p').1)
             (fun A' p'(univ.2.2 A' p').2.1)
             (fun A' p'(univ.2.2 A' p').2.2).

      Definition Build_IsInitialMorphism_uncurried
      : (univ
                : { A : D
                  | { p : morphism C X (U A)
                    | let Ap := CommaCategory.Build_object !X U tt A p in
                       (A' : D) (p' : morphism C X (U A')),
                        { m : morphism D A A'
                        | { H : U _1 m o p = p'
                          | m',
                              U _1 m' o p = p'
                               m = m' }}}}),
          IsInitialMorphism (CommaCategory.Build_object !X U tt univ.1 univ.2.1)
        := @make_uncurried
             _ _ _ _ _ _ _ _
             (@Build_IsInitialMorphism_curried).
    End IntroductionAbstractionBarrier.

    Global Arguments Build_IsInitialMorphism : simpl never.
    Global Arguments Build_IsInitialMorphism_curried : simpl never.
    Global Arguments Build_IsInitialMorphism_uncurried : simpl never.

Elimination rule

    Section EliminationAbstractionBarrier.
      Variable Ap : object (X / U).

      Definition IsInitialMorphism_object (M : IsInitialMorphism Ap) : D
        := CommaCategory.b Ap.
      Definition IsInitialMorphism_morphism (M : IsInitialMorphism Ap)
      : morphism C X (U (IsInitialMorphism_object M))
        := CommaCategory.f Ap.
      Definition IsInitialMorphism_property_morphism (M : IsInitialMorphism Ap)
                 (Y : D) (f : morphism C X (U Y))
      : morphism D (IsInitialMorphism_object M) Y
        := CommaCategory.h
             (@center _ (M (CommaCategory.Build_object !X U tt Y f))).
      Definition IsInitialMorphism_property_morphism_property
                 (M : IsInitialMorphism Ap)
                 (Y : D) (f : morphism C X (U Y))
      : (U _1 (IsInitialMorphism_property_morphism M Y f))
          o IsInitialMorphism_morphism M = f
        := concat
             (CommaCategory.p
                (@center _ (M (CommaCategory.Build_object !X U tt Y f))))
             (right_identity _ _ _ _).
      Definition IsInitialMorphism_property_morphism_unique
                 (M : IsInitialMorphism Ap)
                 (Y : D) (f : morphism C X (U Y))
                 m'
                 (H : U _1 m' o IsInitialMorphism_morphism M = f)
      : IsInitialMorphism_property_morphism M Y f = m'
        := ap
             (@CommaCategory.h _ _ _ _ _ _ _)
             (@contr _
                     (M (CommaCategory.Build_object !X U tt Y f))
                     (CommaCategory.Build_morphism
                        Ap (CommaCategory.Build_object !X U tt Y f)
                        tt m' (H @ (right_identity _ _ _ _)^)%path)).
      Definition IsInitialMorphism_property
                 (M : IsInitialMorphism Ap)
                 (Y : D) (f : morphism C X (U Y))
      : Contr { m : morphism D (IsInitialMorphism_object M) Y
              | U _1 m o IsInitialMorphism_morphism M = f }
        := Build_Contr _ (IsInitialMorphism_property_morphism M Y f;
                         IsInitialMorphism_property_morphism_property M Y f)
              (fun m'path_sigma
                            _
                            (IsInitialMorphism_property_morphism M Y f;
                             IsInitialMorphism_property_morphism_property M Y f)
                            m'
                            (@IsInitialMorphism_property_morphism_unique M Y f m'.1 m'.2)
                            (center _)).
    End EliminationAbstractionBarrier.

    Global Arguments IsInitialMorphism_object : simpl never.
    Global Arguments IsInitialMorphism_morphism : simpl never.
    Global Arguments IsInitialMorphism_property : simpl never.
    Global Arguments IsInitialMorphism_property_morphism : simpl never.
    Global Arguments IsInitialMorphism_property_morphism_property : simpl never.
    Global Arguments IsInitialMorphism_property_morphism_unique : simpl never.
  End InitialMorphism.

Terminal morphisms

  Section TerminalMorphism.

Definition

    Variables C D : PreCategory.

    Variable U : Functor D C.
    Variable X : C.
A terminal morphism from U to X is a terminal object in the comma category (U X) of morphisms from U to X. In other words, it consists of a pair (A, φ) where A is an object of D and φ : U A X is a morphism in C, such that the following terminal property is satisfied:
  • Whenever Y is an object of D and f : U Y X is a morphism in C, then there exists a unique morphism g : Y A such that the following diagram commutes:
         Y      U Y
         .       . \
       g .   U g .   \  f
         .       .     \
         ↓       ↓       ↘
         A      U A -----> X
                      φ
    Local Notation op_object Ap
      := (CommaCategory.Build_object
            (Functors.from_terminal C^op X) (U^op)
            (CommaCategory.b (Ap : object (U / X)))
            (CommaCategory.a (Ap : object (U / X)))
            (CommaCategory.f (Ap : object (U / X)))
          : object ((X : object C^op) / U^op)).

    Definition IsTerminalMorphism (Ap : object (U / X)) : Type
      := @IsInitialMorphism
           (C^op)
           _
           X
           (U^op)
           (op_object Ap).

Introduction rule

    Section IntroductionAbstractionBarrier.
      Definition Build_IsTerminalMorphism
      :
          (*(Ap : Object (U ↓ X))*)
          (A : D)(* := CommaCategory.a Ap*)
          (p : morphism C (U A) X)(*:= CommaCategory.f Ap*)
          (Ap := CommaCategory.Build_object U !X A tt p)
          (UniversalProperty
           : (A' : D) (p' : morphism C (U A') X),
               Contr { m : morphism D A' A
                     | p o U _1 m = p' }),
          IsTerminalMorphism Ap
        := @Build_IsInitialMorphism
             (C^op)
             (D^op)
             X
             (U^op).

      Definition Build_IsTerminalMorphism_curried
      :
          (A : D)
          (p : morphism C (U A) X)
          (Ap := CommaCategory.Build_object U !X A tt p)
          (m : (A' : D) (p' : morphism C (U A') X),
                 morphism D A' A)
          (H : (A' : D) (p' : morphism C (U A') X),
                 p o U _1 (m A' p') = p')
          (H' : (A' : D) (p' : morphism C (U A') X) m',
                  p o U _1 m' = p'
                   m A' p' = m'),
          IsTerminalMorphism Ap
        := @Build_IsInitialMorphism_curried
             (C^op)
             (D^op)
             X
             (U^op).

      Definition Build_IsTerminalMorphism_uncurried
      :
          (univ : { A : D
                  | { p : morphism C (U A) X
                    | let Ap := CommaCategory.Build_object U !X A tt p in
                       (A' : D) (p' : morphism C (U A') X),
                        { m : morphism D A' A
                        | { H : p o U _1 m = p'
                          | m',
                              p o U _1 m' = p'
                               m = m' }}}}),
          IsTerminalMorphism (CommaCategory.Build_object U !X univ.1 tt univ.2.1)
        := @Build_IsInitialMorphism_uncurried
             (C^op)
             (D^op)
             X
             (U^op).
    End IntroductionAbstractionBarrier.

Elimination rule

    Section EliminationAbstractionBarrier.
      Variable Ap : object (U / X).
      Variable M : IsTerminalMorphism Ap.

      Definition IsTerminalMorphism_object : D :=
        @IsInitialMorphism_object C^op D^op X U^op (op_object Ap) M.
      Definition IsTerminalMorphism_morphism
      : morphism C (U IsTerminalMorphism_object) X
        := @IsInitialMorphism_morphism C^op D^op X U^op (op_object Ap) M.
      Definition IsTerminalMorphism_property
      : (Y : D) (f : morphism C (U Y) X),
          Contr { m : morphism D Y IsTerminalMorphism_object
                | IsTerminalMorphism_morphism o U _1 m = f }
        := @IsInitialMorphism_property C^op D^op X U^op (op_object Ap) M.
      Definition IsTerminalMorphism_property_morphism
      : (Y : D) (f : morphism C (U Y) X),
          morphism D Y IsTerminalMorphism_object
        := @IsInitialMorphism_property_morphism
             C^op D^op X U^op (op_object Ap) M.
      Definition IsTerminalMorphism_property_morphism_property
      : (Y : D) (f : morphism C (U Y) X),
          IsTerminalMorphism_morphism
            o (U _1 (IsTerminalMorphism_property_morphism Y f))
          = f
        := @IsInitialMorphism_property_morphism_property
             C^op D^op X U^op (op_object Ap) M.
      Definition IsTerminalMorphism_property_morphism_unique
      : (Y : D) (f : morphism C (U Y) X)
               m'
               (H : IsTerminalMorphism_morphism o U _1 m' = f),
          IsTerminalMorphism_property_morphism Y f = m'
        := @IsInitialMorphism_property_morphism_unique
             C^op D^op X U^op (op_object Ap) M.
    End EliminationAbstractionBarrier.
  End TerminalMorphism.

  Section UniversalMorphism.
The term universal morphism refers either to an initial morphism or a terminal morphism, and the term universal property refers either to an initial property or a terminal property. In each definition, the existence of the morphism g intuitively expresses the fact that (A, φ) is ``general enough'', while the uniqueness of the morphism ensures that (A, φ) is ``not too general''.
  End UniversalMorphism.
End UniversalMorphism.

Arguments Build_IsInitialMorphism [C D] X U A p UniversalProperty _.
Arguments Build_IsTerminalMorphism [C D] U X A p UniversalProperty _.