# Library UniMath.CategoryTheory.FunctorAlgebras

****************************************************************
Benedikt Ahrens started March 2015
Extended by: Anders Mörtberg. October 2015
***************************************************************
Contents :
• Category of algebras of an endofunctor
• This category is saturated if base precategory is
• Lambek's lemma: if (A,a) is an inital F-algebra then a is an iso
• The natural numbers are initial for X ↦ 1 + X

## Category of algebras of an endofunctor

Section Algebra_Definition.

Context {C : precategory} (F : functor C C).

Definition algebra_ob : UU := X : C, F X --> X.

Definition alg_carrier (X : algebra_ob) : C := pr1 X.
Local Coercion alg_carrier : algebra_ob >-> ob.

Definition alg_map (X : algebra_ob) : F X --> X := pr2 X.

A morphism of an F-algebras (F X, g : F X --> X) and (F Y, h : F Y --> Y) is a morphism f : X --> Y such that the following diagram commutes:
F f F x ----> F y | | | g | h V V x ------> y f
Definition is_algebra_mor (X Y : algebra_ob) (f : alg_carrier X --> alg_carrier Y) : UU
:= alg_map X · f = #F f · alg_map Y.

Definition algebra_mor (X Y : algebra_ob) : UU :=
f : X --> Y, is_algebra_mor X Y f.

Coercion mor_from_algebra_mor (X Y : algebra_ob) (f : algebra_mor X Y) : X --> Y := pr1 f.

Definition isaset_algebra_mor (hs : has_homsets C) (X Y : algebra_ob) : isaset (algebra_mor X Y).
Proof.
apply (isofhleveltotal2 2).
- apply hs.
- intro f.
apply isasetaprop.
apply hs.
Qed.

Definition algebra_mor_eq (hs : has_homsets C) {X Y : algebra_ob} {f g : algebra_mor X Y}
: (f : X --> Y) = g f = g.
Proof.
apply invweq.
apply subtypeInjectivity.
intro a. apply hs.
Defined.

Lemma algebra_mor_commutes (X Y : algebra_ob) (f : algebra_mor X Y)
: alg_map X · f = #F f · alg_map Y.
Proof.
exact (pr2 f).
Qed.

Definition algebra_mor_id (X : algebra_ob) : algebra_mor X X.
Proof.
(identity _ ).
abstract (unfold is_algebra_mor;
rewrite id_right ;
rewrite functor_id;
rewrite id_left;
apply idpath).
Defined.

Definition algebra_mor_comp (X Y Z : algebra_ob) (f : algebra_mor X Y) (g : algebra_mor Y Z)
: algebra_mor X Z.
Proof.
(f · g).
abstract (unfold is_algebra_mor;
rewrite assoc;
rewrite algebra_mor_commutes;
rewrite <- assoc;
rewrite algebra_mor_commutes;
rewrite functor_comp, assoc;
apply idpath).
Defined.

Definition precategory_alg_ob_mor : precategory_ob_mor.
Proof.
algebra_ob.
exact algebra_mor.
Defined.

Definition precategory_alg_data : precategory_data.
Proof.
precategory_alg_ob_mor.
algebra_mor_id.
exact algebra_mor_comp.
Defined.

Lemma is_precategory_precategory_alg_data (hs : has_homsets C)
: is_precategory precategory_alg_data.
Proof.
repeat split; intros; simpl.
- apply algebra_mor_eq.
+ apply hs.
+ apply id_left.
- apply algebra_mor_eq.
+ apply hs.
+ apply id_right.
- apply algebra_mor_eq.
+ apply hs.
+ apply assoc.
- apply algebra_mor_eq.
+ apply hs.
+ apply assoc'.
Qed.

Definition precategory_FunctorAlg (hs : has_homsets C)
: precategory := tpair _ _ (is_precategory_precategory_alg_data hs).

Local Notation FunctorAlg := precategory_FunctorAlg.

Lemma has_homsets_FunctorAlg (hs : has_homsets C)
: has_homsets (FunctorAlg hs).
Proof.
intros f g.
apply isaset_algebra_mor.
assumption.
Qed.

forgetful functor from FunctorAlg to its underlying category

Definition forget_algebras_data (hsC: has_homsets C): functor_data (FunctorAlg hsC) C.
Proof.
set (onobs := fun alg : FunctorAlg hsCalg_carrier alg).
apply (make_functor_data onobs).
intros alg1 alg2 m.
simpl in m.
exact (mor_from_algebra_mor _ _ m).
Defined.

Definition forget_algebras (hsC: has_homsets C): functor (FunctorAlg hsC) C.
Proof.
apply (make_functor (forget_algebras_data hsC)).
abstract ( split; [intro alg; apply idpath | intros alg1 alg2 alg3 m n; apply idpath] ).
Defined.

## This category is saturated if the base category is

Section FunctorAlg_saturated.

Hypothesis H : is_univalent C.

Definition algebra_eq_type (X Y : FunctorAlg (pr2 H)) : UU
:= p : iso (pr1 X) (pr1 Y), is_algebra_mor X Y p.

Definition algebra_ob_eq (X Y : FunctorAlg (pr2 H)) :
(X = Y) algebra_eq_type X Y.
Proof.
eapply weqcomp.
- apply total2_paths_equiv.
- set (H1 := make_weq _ (pr1 H (pr1 X) (pr1 Y))).
apply (weqbandf H1).
simpl.
intro p.
destruct X as [X α].
destruct Y as [Y β]; simpl in ×.
destruct p.
rewrite idpath_transportf.
unfold is_algebra_mor; simpl.
rewrite functor_id.
rewrite id_left, id_right.
apply idweq.
Defined.

Definition is_iso_from_is_algebra_iso (X Y : FunctorAlg (pr2 H)) (f : X --> Y)
: is_iso f is_iso (pr1 f).
Proof.
intro p.
apply is_iso_from_is_z_iso.
set (H' := iso_inv_after_iso (make_iso f p)).
set (H'':= iso_after_iso_inv (make_iso f p)).
(pr1 (inv_from_iso (make_iso f p))).
split; simpl.
- apply (maponpaths pr1 H').
- apply (maponpaths pr1 H'').
Defined.

Definition inv_algebra_mor_from_is_iso {X Y : FunctorAlg (pr2 H)} (f : X --> Y)
: is_iso (pr1 f) (Y --> X).
Proof.
intro T.
set (fiso:=make_iso (pr1 f) T).
set (finv:=inv_from_iso fiso).
finv.
unfold finv.
apply pathsinv0.
apply iso_inv_on_left.
simpl.
rewrite functor_on_inv_from_iso.
rewrite <- assoc.
apply pathsinv0.
apply iso_inv_on_right.
simpl.
apply (pr2 f).
Defined.

Definition is_algebra_iso_from_is_iso {X Y : FunctorAlg (pr2 H)} (f : X --> Y)
: is_iso (pr1 f) is_iso f.
Proof.
intro T.
apply is_iso_from_is_z_iso.
(inv_algebra_mor_from_is_iso f T).
split; simpl.
- apply algebra_mor_eq.
+ apply (pr2 H).
+ simpl.
apply (iso_inv_after_iso (make_iso (pr1 f) T)).
- apply algebra_mor_eq.
+ apply (pr2 H).
+ apply (iso_after_iso_inv (make_iso (pr1 f) T)).
Defined.

Definition algebra_iso_first_iso {X Y : FunctorAlg (pr2 H)}
: iso X Y f : X --> Y, is_iso (pr1 f).
Proof.
apply (weqbandf (idweq _ )).
unfold idweq. simpl.
intro f.
apply weqimplimpl.
- apply is_iso_from_is_algebra_iso.
- apply is_algebra_iso_from_is_iso.
- apply isaprop_is_iso.
- apply isaprop_is_iso.
Defined.

Definition swap (A B : UU) : A × B B × A.
Proof.
intro ab.
(pr2 ab).
exact (pr1 ab).
Defined.

Definition swapweq (A B : UU) : (A × B) (B × A).
Proof.
(swap A B).
apply (isweq_iso _ (swap B A)).
- abstract ( intro ab; destruct ab; apply idpath ).
- abstract ( intro ba; destruct ba; apply idpath ).
Defined.

Definition algebra_iso_rearrange {X Y : FunctorAlg (pr2 H)}
: ( f : X --> Y, is_iso (pr1 f)) algebra_eq_type X Y.
Proof.
eapply weqcomp.
- apply weqtotal2asstor.
- simpl. unfold algebra_eq_type.
apply invweq.
eapply weqcomp.
+ apply weqtotal2asstor.
+ simpl. apply (weqbandf (idweq _ )).
unfold idweq. simpl.
intro f; apply swapweq.
Defined.

Definition algebra_idtoiso (X Y : FunctorAlg (pr2 H)) :
(X = Y) iso X Y.
Proof.
eapply weqcomp.
- apply algebra_ob_eq.
- eapply weqcomp.
+ apply (invweq (algebra_iso_rearrange)).
+ apply (invweq algebra_iso_first_iso).
Defined.

Lemma isweq_idtoiso_FunctorAlg (X Y : FunctorAlg (pr2 H))
: isweq (@idtoiso _ X Y).
Proof.
apply (isweqhomot (algebra_idtoiso X Y)).
- intro p. induction p.
simpl. apply eq_iso. apply algebra_mor_eq.
+ apply (pr2 H).
+ apply idpath.
- apply (pr2 _ ).
Defined.

Lemma is_univalent_FunctorAlg : is_univalent (FunctorAlg (pr2 H)).
Proof.
split.
- apply isweq_idtoiso_FunctorAlg.
- intros a b.
apply isaset_algebra_mor.
apply (pr2 H).
Defined.

End FunctorAlg_saturated.

Lemma idtomor_FunctorAlg_commutes (hsC: has_homsets C)(X Y: FunctorAlg hsC)(e: X = Y): mor_from_algebra_mor _ _ (idtomor _ _ e) = idtomor _ _ (maponpaths alg_carrier e).
Proof.
induction e.
apply idpath.
Qed.

Corollary idtoiso_FunctorAlg_commutes (hsC: has_homsets C)(X Y: FunctorAlg hsC)(e: X = Y): mor_from_algebra_mor _ _ (morphism_from_iso (idtoiso e)) = idtoiso (maponpaths alg_carrier e).
Proof.
unfold morphism_from_iso.
do 2 rewrite eq_idtoiso_idtomor.
apply idtomor_FunctorAlg_commutes.
Qed.

End Algebra_Definition.

Notation FunctorAlg := precategory_FunctorAlg.

## Lambek's lemma: If (A,a) is an initial F-algebra then a is an iso

Section Lambeks_lemma.

Variables (C : precategory) (hsC : has_homsets C) (F : functor C C).
Variables (Aa : algebra_ob F) (AaIsInitial : isInitial (FunctorAlg F hsC) Aa).

Local Definition AaInitial : Initial (FunctorAlg F hsC) :=
make_Initial _ AaIsInitial.

Local Notation A := (alg_carrier _ Aa).
Local Notation a := (alg_map _ Aa).

Local Definition FAa : algebra_ob F := tpair (λ X, C F X,X) (F A) (# F a).
Local Definition Fa' := InitialArrow AaInitial FAa.
Local Definition a' : CA,F A := mor_from_algebra_mor _ _ _ Fa'.
Local Definition Ha' := algebra_mor_commutes _ _ _ Fa'.

Lemma initialAlg_is_iso_subproof : is_inverse_in_precat a a'.
Proof.
assert (Ha'a : a' · a = identity A).
{ assert (algMor_a'a : is_algebra_mor _ _ _ (a' · a)).
{ unfold is_algebra_mor, a'; rewrite functor_comp.
eapply pathscomp0; [|eapply cancel_postcomposition; apply Ha'].
apply assoc. }
apply pathsinv0; set (X := tpair _ _ algMor_a'a).
apply (maponpaths pr1 (!@InitialEndo_is_identity _ AaInitial X)).
}
split; trivial.
eapply pathscomp0; [apply Ha'|]; cbn.
rewrite <- functor_comp.
eapply pathscomp0; [eapply maponpaths; apply Ha'a|].
apply functor_id.
Qed.

Lemma initialAlg_is_iso : is_iso a.
Proof.
exact (is_iso_qinv _ a' initialAlg_is_iso_subproof).
Defined.

End Lambeks_lemma.

## The natural numbers are intial for X ↦ 1 + X

This can be used as a definition of a natural numbers object (NNO) in any category with binary coproducts and a terminal object. We prove the universal property of NNOs below.

Section Nats.
Context (C : precategory).
Context (bc : BinCoproducts C).
Context (hsC : has_homsets C).
Context (T : Terminal C).

Local Notation "1" := T.
Local Notation "f + g" := (BinCoproductOfArrows _ _ _ f g).
Local Notation "[ f , g ]" := (BinCoproductArrow _ _ f g).

Let F : functor C C := BinCoproduct_of_functors _ _ bc
(constant_functor _ _ 1)
(functor_identity _).

F on objects: X ↦ 1 + X
Definition F_compute1 : c : C, F c = BinCoproductObject _ (bc 1 c) :=
fun c ⇒ (idpath _).

F on arrows: f ↦ identity 1, f
Definition F_compute2 {x y : C} : f : x --> y, # F f = (identity 1) + f :=
fun c ⇒ (idpath _).

Definition nat_ob : UU := Initial (FunctorAlg F hsC).

Definition nat_ob_carrier (N : nat_ob) : ob C :=
alg_carrier _ (InitialObject N).
Local Coercion nat_ob_carrier : nat_ob >-> ob.

We have an arrow alg_map : (F N = 1 + N) --> N, so by the η-rule (UMP) for the coproduct, we can assume that it arises from a pair of maps by composing with coproduct injections.
in1 in2 1 ----> 1 + N <---- N | | | nat_ob_z | | alg_map | nat_ob_s | V | +-------> N <-------+
Definition nat_ob_z (N : nat_ob) : (1 --> N) :=
BinCoproductIn1 C (bc 1 (alg_carrier F (pr1 N))) · (alg_map _ (pr1 N)).

Definition nat_ob_s (N : nat_ob) : (N --> N) :=
BinCoproductIn2 C (bc 1 (alg_carrier F (pr1 N))) · (alg_map _ (pr1 N)).

Local Notation "0" := (nat_ob_z _).

Use the universal property of the coproduct to make any object with a point and an endomorphism into an F-algebra
Definition make_F_alg {X : ob C} (f : 1 --> X) (g : X --> X) : ob (FunctorAlg F hsC).
Proof.
refine (X,, _).
exact (BinCoproductArrow _ _ f g).
Defined.

Using make_F_alg, X will be an F-algebra, and by initiality of N, there will be a unique morphism of F-algebras N --> X, which can be projected to a morphism in C.
Definition nat_ob_rec (N : nat_ob) {X : ob C} :
(f : 1 --> X) (g : X --> X), (N --> X) :=
fun f gmor_from_algebra_mor _ _ _ (InitialArrow N (make_F_alg f g)).

When calling the recursor on 0, you get the base case. Specifically,
nat_ob_z · nat_ob_rec = f
Lemma nat_ob_rec_z (N : nat_ob) {X : ob C} :
(f : 1 --> X) (g : X --> X), nat_ob_z N · nat_ob_rec N f g = f.
Proof.
intros f g.

pose (inlN := BinCoproductIn1 _ (bc 1 N)).
pose (succ := nat_ob_s N).

By initiality of N, there is a unique morphism making the following diagram commute:
inlN identity 1 + nat_ob_rec 1 -----> 1 + N -------------------------> 1 + X | | alg_map N | | alg_map X V V N --------------------------> X nat_ob_rec
This proof uses somewhat idiosyncratic "forward reasoning", transforming the term "diagram" rather than the goal.
pose
(diagram :=
maponpaths
(fun xinlN · x)
(algebra_mor_commutes F (pr1 N) _ (InitialArrow N (make_F_alg f g)))).
rewrite (F_compute2 _) in diagram.

Using the η-rules for coproducts, we can assume that alg_map X = f,g for f : 1 --> X, g : X --> X.
rewrite (BinCoproductArrowEta C 1 X (bc _ _) _ _) in diagram.

Using the β-rules for coproducts, we can simplify some of the terms (identity 1 + _) · f, g --β--> identity 1 · f, _ · g
rewrite (precompWithBinCoproductArrow C (bc 1 N) (bc 1 X)
(identity 1) _ _ _) in diagram.

inl · identity 1 · f, _ · g --β--> identity 1 · f
rewrite (BinCoproductIn1Commutes C 1 N (bc 1 _) _ _ _) in diagram.

We can dispense with the identity
rewrite (id_left _) in diagram.

rewrite assoc in diagram.
rewrite (BinCoproductArrowEta C 1 N (bc _ _) _ _) in diagram.

refine (_ @ (BinCoproductIn1Commutes C _ _ (bc 1 _) _ f g)).
rewrite (!BinCoproductIn1Commutes C _ _ (bc 1 _) _ 0 succ).
unfold nat_ob_rec in ×.
exact diagram.
Defined.

Opaque nat_ob_rec_z.

The succesor case:
nat_ob_s · nat_ob_rec = nat_ob_rec · g
The proof is very similar.
Lemma nat_ob_rec_s (N : nat_ob) {X : ob C} :
(f : 1 --> X) (g : X --> X),
nat_ob_s N · nat_ob_rec N f g = nat_ob_rec N f g · g.
Proof.
intros f g.

pose (inrN := BinCoproductIn2 _ (bc 1 N)).
pose (succ := nat_ob_s N).

By initiality of N, there is a unique morphism making the same diagram commute as above, but with "inrN" in place of "inlN".
pose
(diagram :=
maponpaths
(fun xinrN · x)
(algebra_mor_commutes F (pr1 N) _ (InitialArrow N (make_F_alg f g)))).
rewrite (F_compute2 _) in diagram.

rewrite (BinCoproductArrowEta C 1 X (bc _ _) _ _) in diagram.

Using the β-rules for coproducts, we can simplify some of the terms (identity 1 + _) · f, g --β--> identity 1 · f, _ · g
rewrite (precompWithBinCoproductArrow C (bc 1 N) (bc 1 X)
(identity 1) _ _ _) in diagram.

inl · identity 1 · f, _ · g --β--> identity 1 · f
rewrite (BinCoproductIn2Commutes C 1 N (bc 1 _) _ _ _) in diagram.

rewrite assoc in diagram.
rewrite (BinCoproductArrowEta C 1 N (bc _ _) _ _) in diagram.

refine
(_ @ maponpaths (fun xnat_ob_rec N f g · x)
(BinCoproductIn2Commutes C _ _ (bc 1 _) _ f g)).
rewrite (!BinCoproductIn2Commutes C _ _ (bc 1 _) _ 0 (nat_ob_s N)).
unfold nat_ob_rec in ×.
exact diagram.
Defined.

Opaque nat_ob_rec_s.

End Nats.

nat_ob implies NNO
Lemma nat_ob_NNO {C : precategory} (BC : BinCoproducts C) (hsC : has_homsets C) (TC : Terminal C) :
nat_ob C BC hsC TC NNO TC.
Proof.
intros N.
use make_NNO.
- exact (nat_ob_carrier _ _ _ _ N).
- apply nat_ob_z.
- apply nat_ob_s.
- intros n z s.
use unique_exists.
+ apply (nat_ob_rec _ _ _ _ _ z s).
+ split; [ apply nat_ob_rec_z | apply nat_ob_rec_s ].
+ intros x; apply isapropdirprod; apply hsC.
+ intros x [H1 H2].
transparent assert (xalg : (FunctorAlg (BinCoproduct_of_functors C C BC
(constant_functor C C TC)
(functor_identity C)) hsC
InitialObject N, make_F_alg C BC hsC TC z s )).
{ refine (x,,_).
abstract (apply pathsinv0; etrans; [apply precompWithBinCoproductArrow |];
rewrite id_left, <- H1;
etrans; [eapply maponpaths, pathsinv0, H2|];
now apply pathsinv0, BinCoproductArrowUnique; rewrite assoc;
apply maponpaths).
}
exact (maponpaths pr1 (InitialArrowUnique N (make_F_alg C BC hsC TC z s) xalg)).
Defined.