Timings for FreeProduct.v
Require Import Basics Types.
Require Import Spaces.List.Core Spaces.List.Theory.
Require Import Colimits.Pushout.
Require Import Truncations.Core Truncations.SeparatedTrunc.
Require Import Algebra.Groups.Group.
Local Open Scope list_scope.
Local Open Scope mc_scope.
Local Open Scope mc_mult_scope.
(** In this file we define the amalgamated free product of a span of group homomorphisms as a HIT. *)
(** We wish to define the amalgamated free product of a span of group homomorphisms f : G -> H, g : G -> K as the following HIT:
HIT M(f,g)
| amal_eta : list (H + K) -> M(f,g)
| mu_H : forall (x y : list (H + K)) (h1 h2 : H),
amal_eta (x ++ [inl h1, inl h2] ++ y) = amal_eta (x ++ [inl (h1 * h2)] ++ y)
| mu_K : forall (x y : list (H + K)) (k1 k2 : K),
amal_eta (x ++ [inr k1, inr k2] ++ y) = amal_eta (x ++ [inr (k1 * k2)] ++ y)
| tau : forall (x y : list (H + K)) (z : G),
amal_eta (x ++ [inl (f z)] ++ y) = amal_eta (x ++ [inr (g z)] ++ y)
| omega_H : forall (x y : list (H + K)),
amal_eta (x ++ [inl mon_unit] ++ y) = amal_eta (x ++ y)
| omega_K : forall (x y : list (H + K)),
amal_eta (x ++ [inr mon_unit] ++ y) = amal_eta (x ++ y).
We will build this HIT up sucessively out of coequalizers. *)
(** We will call M [amal_type] and prefix all the constructors with [amal_] (for amalgmated free product). *)
Context (G H K : Group)
(f : GroupHomomorphism G H) (g : GroupHomomorphism G K).
Local Definition Words : Type := list (H + K).
Local Notation "[ x ]" := (cons x nil).
Local Definition word_concat_w_nil (x : Words) : x ++ nil = x.
Local Definition word_concat_w_ww (x y z : Words) : x ++ (y ++ z) = (x ++ y) ++ z.
Local Fixpoint word_inverse (x : Words) : Words.
exact ((word_inverse xs) ++ [inl (- h)]).
exact ((word_inverse xs) ++ [inr (- k)]).
(** Inversion changes order of concatenation. *)
Local Definition word_inverse_ww (x y : Words)
: word_inverse (x ++ y) = word_inverse y ++ word_inverse x.
destruct x; refine (_ @ (word_concat_w_ww _ _ _)^); f_ap.
(** There are five source types for the path constructors. We will construct this HIT as the colimit of five forks going into [Words]. We can bundle up this colimit as a single coequalizer. *)
(** Source types of path constructors *)
Local Definition pc1 : Type := Words * H * H * Words.
Local Definition pc2 : Type := Words * K * K * Words.
Local Definition pc3 : Type := Words * G * Words.
Local Definition pc4 : Type := Words * Words.
Local Definition pc5 : Type := Words * Words.
(** End points of the first path constructor *)
Local Definition m1 : pc1 -> Words.
exact (x ++ (inl h1 :: [inl h2]) ++ y).
Local Definition m1' : pc1 -> Words.
exact (x ++ [inl (h1 * h2)] ++ y).
(** End points of the second path construct *)
Local Definition m2 : pc2 -> Words.
exact (x ++ (inr k1 :: [inr k2]) ++ y).
Local Definition m2' : pc2 -> Words.
exact (x ++ [inr (k1 * k2)] ++ y).
(** End points of the third path constructor *)
Local Definition m3 : pc3 -> Words.
exact (x ++ [inl (f z)] ++ y).
Local Definition m3' : pc3 -> Words.
exact (x ++ [inr (g z)] ++ y).
(** End points of the fourth path constructor *)
Local Definition m4 : pc4 -> Words.
exact (x ++ [inl mon_unit] ++ y).
Local Definition m4' : pc4 -> Words.
(** End points of the fifth path constructor *)
Local Definition m5 : pc5 -> Words.
exact (x ++ [inr mon_unit] ++ y).
Local Definition m5' : pc5 -> Words.
(** We can then define maps going into words consisting of the corresponding endpoints of the path constructors. *)
Local Definition map1 : pc1 + pc2 + pc3 + pc4 + pc5 -> Words.
intros [[[[x|x]|x]|x]|x].
Local Definition map2 : pc1 + pc2 + pc3 + pc4 + pc5 -> Words.
intros [[[[x|x]|x]|x]|x].
(** Finally we can define our type as the 0-truncation of the coequalizer of these maps *)
Definition amal_type : Type := Tr 0 (Coeq map1 map2).
(** We can define the constructors *)
Definition amal_eta : Words -> amal_type := tr o coeq.
Definition amal_mu_H (x y : Words) (h1 h2 : H)
: amal_eta (x ++ (cons (inl h1) [inl h2]) ++ y) = amal_eta (x ++ [inl (h1 * h2)] ++ y).
exact (cglue (inl (inl (inl (inl (x,h1,h2,y)))))).
Definition amal_mu_K (x y : Words) (k1 k2 : K)
: amal_eta (x ++ (cons (inr k1) [inr k2]) ++ y) = amal_eta (x ++ [inr (k1 * k2)] ++ y).
exact (cglue (inl (inl (inl (inr (x,k1,k2,y)))))).
Definition amal_tau (x y : Words) (z : G)
: amal_eta (x ++ [inl (f z)] ++ y) = amal_eta (x ++ [inr (g z)] ++ y).
exact (cglue (inl (inl (inr (x,z,y))))).
Definition amal_omega_H (x y : Words)
: amal_eta (x ++ [inl mon_unit] ++ y) = amal_eta (x ++ y).
exact (cglue (inl (inr (x,y)))).
Definition amal_omega_K (x y : Words)
: amal_eta (x ++ [inr mon_unit] ++ y) = amal_eta (x ++ y).
exact (cglue (inr (x,y))).
(** Now we can derive the dependent eliminator *)
Definition amal_type_ind (P : amal_type -> Type) `{forall x, IsHSet (P x)}
(e : forall w, P (amal_eta w))
(mh : forall (x y : Words) (h1 h2 : H),
DPath P (amal_mu_H x y h1 h2) (e (x ++ (inl h1 :: [inl h2]) ++ y)) (e (x ++ [inl (h1 * h2)] ++ y)))
(mk : forall (x y : Words) (k1 k2 : K),
DPath P (amal_mu_K x y k1 k2) (e (x ++ (inr k1 :: [inr k2]) ++ y)) (e (x ++ [inr (k1 * k2)] ++ y)))
(t : forall (x y : Words) (z : G),
DPath P (amal_tau x y z) (e (x ++ [inl (f z)] ++ y)) (e (x ++ [inr (g z)] ++ y)))
(oh : forall (x y : Words),
DPath P (amal_omega_H x y) (e (x ++ [inl mon_unit] ++ y)) (e (x ++ y)))
(ok : forall (x y : Words),
DPath P (amal_omega_K x y) (e (x ++ [inr mon_unit] ++ y)) (e (x ++ y)))
: forall x, P x.
snrapply Trunc_ind; [exact _|].
destruct a as [ [ [ [a | a ] | a] | a ] | a ].
destruct a as [[[x h1] h2] y].
destruct a as [[[x k1] k2] y].
Definition amal_type_ind_hprop (P : amal_type -> Type) `{forall x, IsHProp (P x)}
(e : forall w, P (amal_eta w))
: forall x, P x.
all: intros; apply path_ishprop.
(** From which we can derive the non-dependent eliminator / recursion principle *)
Definition amal_type_rec (P : Type) `{IsHSet P} (e : Words -> P)
(eh : forall (x y : Words) (h1 h2 : H),
e (x ++ (cons (inl h1) [inl h2]) ++ y) = e (x ++ [inl (h1 * h2)] ++ y))
(ek : forall (x y : Words) (k1 k2 : K),
e (x ++ (cons (inr k1) [inr k2]) ++ y) = e (x ++ [inr (k1 * k2)] ++ y))
(t : forall (x y : Words) (z : G),
e (x ++ [inl (f z)] ++ y) = e (x ++ [inr (g z)] ++ y))
(oh : forall (x y : Words), e (x ++ [inl mon_unit] ++ y) = e (x ++ y))
(ok : forall (x y : Words), e (x ++ [inr mon_unit] ++ y) = e (x ++ y))
: amal_type -> P.
all: intros; apply dp_const.
(** Now for the group structure *)
(** The group operation is concatenation of the underlying list. Most of the work is spent showing that it respects the path constructors. *)
Global Instance sgop_amal_type : SgOp amal_type.
srapply amal_type_rec; intros x; revert y.
srapply amal_type_rec; intros y.
1: exact (amal_eta (x ++ y)).
refine (ap amal_eta _ @ _ @ ap amal_eta _^).
1,3: apply word_concat_w_ww.
refine (ap amal_eta _ @ _ @ ap amal_eta _^).
1,3: apply word_concat_w_ww.
refine (ap amal_eta _ @ _ @ ap amal_eta _^).
1,3: apply word_concat_w_ww.
refine (ap amal_eta _ @ _ @ ap amal_eta _^).
1,3: apply word_concat_w_ww.
refine (ap amal_eta _ @ _ @ ap amal_eta _^).
1,3: apply word_concat_w_ww.
intros r y h1 h2; revert r.
rapply amal_type_ind_hprop.
intros z;
change (amal_eta ((x ++ ((inl h1 :: [inl h2]) ++ y)) ++ z)
= amal_eta ((x ++ [inl (h1 * h2)] ++ y) ++ z)).
refine (ap amal_eta _^ @ _ @ ap amal_eta _).
1,3: apply word_concat_w_ww.
refine (ap amal_eta (ap (app x) _)^ @ _ @ ap amal_eta (ap (app x) _)).
1,3: apply word_concat_w_ww.
intros r y k1 k2; revert r.
rapply amal_type_ind_hprop.
intros z;
change (amal_eta ((x ++ ((inr k1 :: [inr k2]) ++ y)) ++ z)
= amal_eta ((x ++ [inr (k1 * k2)] ++ y) ++ z)).
refine (ap amal_eta _^ @ _ @ ap amal_eta _).
1,3: apply word_concat_w_ww.
refine (ap amal_eta (ap (app x) _)^ @ _ @ ap amal_eta (ap (app x) _)).
1,3: apply word_concat_w_ww.
rapply amal_type_ind_hprop.
intros w;
change (amal_eta ((x ++ [inl (f z)] ++ y) ++ w)
= amal_eta ((x ++ [inr (g z)] ++ y) ++ w)).
refine (ap amal_eta _^ @ _ @ ap amal_eta _).
1,3: apply word_concat_w_ww.
refine (ap amal_eta (ap (app x) _)^ @ _ @ ap amal_eta (ap (app x) _)).
1,3: apply word_concat_w_ww.
rapply amal_type_ind_hprop.
intros w;
change (amal_eta ((x ++ [inl mon_unit] ++ z) ++ w) = amal_eta ((x ++ z) ++ w)).
refine (ap amal_eta _^ @ _ @ ap amal_eta _).
1,3: apply word_concat_w_ww.
refine (ap amal_eta (ap (app x) _)^ @ _).
1: apply word_concat_w_ww.
rapply amal_type_ind_hprop.
intros w;
change (amal_eta ((x ++ [inr mon_unit] ++ z) ++ w) = amal_eta ((x ++ z) ++ w)).
refine (ap amal_eta _^ @ _ @ ap amal_eta _).
1,3: apply word_concat_w_ww.
refine (ap amal_eta (ap (app x) _)^ @ _).
1: apply word_concat_w_ww.
(** The identity element is the empty list *)
Global Instance monunit_amal_type : MonUnit amal_type.
Global Instance negate_amal_type : Negate amal_type.
exact (amal_eta (word_inverse w)).
refine (ap amal_eta _ @ _ @ ap amal_eta _^).
1,3: refine (word_inverse_ww _ _ @ ap (fun s => s ++ _) _).
1: apply word_inverse_ww.
refine (word_inverse_ww _ _ @ _).
rapply (ap (fun s => [s])).
refine (ap amal_eta _^ @ _ @ ap amal_eta _).
1,3: apply word_concat_w_ww.
refine (ap amal_eta _ @ _ @ ap amal_eta _^).
1,3: refine (word_inverse_ww _ _ @ ap (fun s => s ++ _) _).
1: apply word_inverse_ww.
refine (word_inverse_ww _ _ @ _).
rapply (ap (fun s => [s])).
refine (ap amal_eta _^ @ _ @ ap amal_eta _).
1,3: apply word_concat_w_ww.
refine (ap amal_eta _ @ _ @ ap amal_eta _^).
1,3: refine (word_inverse_ww _ _ @ ap (fun s => s ++ _) _).
1,2: cbn; refine (ap _ _).
1,2: rapply (ap (fun s => [s])).
1,2: symmetry; apply grp_homo_inv.
refine (ap amal_eta _^ @ _ @ ap amal_eta _).
1,3: apply word_concat_w_ww.
refine (ap amal_eta _ @ _ @ ap amal_eta _^).
1,3: apply word_inverse_ww.
refine (ap amal_eta _ @ _).
refine (ap (fun s => s ++ _) _).
refine (ap amal_eta _^ @ _).
1: apply word_concat_w_ww.
refine (ap amal_eta _ @ _ @ ap amal_eta _^).
1,3: apply word_inverse_ww.
refine (ap amal_eta _ @ _).
refine (ap (fun s => s ++ _) _).
refine (ap amal_eta _^ @ _).
1: apply word_concat_w_ww.
Global Instance associative_sgop_m : Associative sg_op.
rapply amal_type_ind_hprop; intro z; revert y.
rapply amal_type_ind_hprop; intro y; revert x.
rapply amal_type_ind_hprop; intro x.
Global Instance leftidentity_sgop_amal_type : LeftIdentity sg_op mon_unit.
rapply amal_type_ind_hprop; intro x.
Global Instance rightidentity_sgop_amal_type : RightIdentity sg_op mon_unit.
rapply amal_type_ind_hprop; intro x.
Lemma amal_eta_word_concat_Vw (x : Words) : amal_eta (word_inverse x ++ x) = mon_unit.
change (amal_eta (word_inverse ([inl h] ++ xs) ++ [inl h] ++ xs) = mon_unit).
rewrite <- word_concat_w_ww.
refine (amal_mu_H _ _ _ _ @ _).
change (amal_eta (word_inverse ([inr k] ++ xs) ++ [inr k] ++ xs) = mon_unit).
rewrite <- word_concat_w_ww.
refine (amal_mu_K _ _ _ _ @ _).
Lemma amal_eta_word_concat_wV (x : Words) : amal_eta (x ++ word_inverse x) = mon_unit.
rewrite word_concat_w_ww.
change (amal_eta ([inl h]) * amal_eta ((xs ++ word_inverse xs)) * amal_eta ([inl (- h)]) = mon_unit).
rewrite rightidentity_sgop_amal_type.
rewrite <- (word_concat_w_nil (cons _ _)).
change (amal_eta (([inl h] ++ [inl (- h)]) ++ nil) = mon_unit).
rewrite <- word_concat_w_ww.
change (amal_eta (nil ++ [inl h] ++ [inl (- h)] ++ nil) = mon_unit).
refine (amal_mu_H _ _ _ _ @ _).
rapply (ap (fun x => x ++ _)).
rapply (ap (fun x => [x])).
rewrite word_concat_w_ww.
change (amal_eta ([inr k]) * amal_eta ((xs ++ word_inverse xs)) * amal_eta ([inr (-k)]) = mon_unit).
rewrite rightidentity_sgop_amal_type.
rewrite <- (word_concat_w_nil (cons _ _)).
change (amal_eta (([inr k] ++ [inr (- k)]) ++ nil) = mon_unit).
rewrite <- word_concat_w_ww.
change (amal_eta (nil ++ [inr k] ++ [inr (- k)] ++ nil) = mon_unit).
refine (amal_mu_K _ _ _ _ @ _).
rapply (ap (fun x => x ++ _)).
rapply (ap (fun x => [x])).
Global Instance leftinverse_sgop_amal_type : LeftInverse sg_op negate mon_unit.
rapply amal_type_ind_hprop; intro x.
apply amal_eta_word_concat_Vw.
Global Instance rightinverse_sgop_amal_type : RightInverse sg_op negate mon_unit.
rapply amal_type_ind_hprop; intro x.
apply amal_eta_word_concat_wV.
Definition AmalgamatedFreeProduct : Group.
snrapply (Build_Group amal_type); repeat split; exact _.
(** Using foldr. It's important that we use foldr as foldl is near impossible to reason about. *)
Definition AmalgamatedFreeProduct_rec' (X : Group)
(h : GroupHomomorphism H X) (k : GroupHomomorphism K X)
(p : h o f == k o g)
: AmalgamatedFreeProduct -> X.
refine (fold_right _ _ w).
rewrite simple_associativity.
exact (grp_homo_op h h1 h2).
rewrite simple_associativity.
exact (grp_homo_op k k1 k2).
Global Instance issemigrouppreserving_AmalgamatedFreeProduct_rec'
(X : Group) (h : GroupHomomorphism H X) (k : GroupHomomorphism K X)
(p : h o f == k o g)
: IsSemiGroupPreserving (AmalgamatedFreeProduct_rec' X h k p).
intros x; srapply amal_type_ind_hprop; intro y; revert x;
srapply amal_type_ind_hprop; intro x; simpl.
set (s := (fold_right
(fun X0 : H + K => match X0 with
| inl l => fun x0 : X => h l * x0
| inr r => fun x0 : X => k r * x0
end) mon_unit y)).
1: symmetry; apply left_identity.
destruct a; apply simple_associativity.
Definition AmalgamatedFreeProduct_rec (X : Group)
(h : GroupHomomorphism H X) (k : GroupHomomorphism K X)
(p : h o f == k o g)
: GroupHomomorphism AmalgamatedFreeProduct X.
snrapply Build_GroupHomomorphism.
1: srapply (AmalgamatedFreeProduct_rec' X h k p).
Definition amal_inl : GroupHomomorphism H AmalgamatedFreeProduct.
snrapply Build_GroupHomomorphism.
exact (amal_eta [inl x]).
rewrite <- (word_concat_w_nil [inl (x * y)]).
rewrite <- (amal_mu_H nil nil x y).
rewrite word_concat_w_nil.
Definition amal_inr : GroupHomomorphism K AmalgamatedFreeProduct.
snrapply Build_GroupHomomorphism.
exact (amal_eta [inr x]).
rewrite <- (word_concat_w_nil [inr (x * y)]).
rewrite <- (amal_mu_K nil nil x y).
rewrite word_concat_w_nil.
Theorem equiv_amalgamatedfreeproduct_rec `{Funext} (X : Group)
: {h : GroupHomomorphism H X & {k : GroupHomomorphism K X & h o f == k o g }}
<~> GroupHomomorphism AmalgamatedFreeProduct X.
snrapply equiv_adjointify.
1: intros [h [k p]]; exact (AmalgamatedFreeProduct_rec X h k p).
exists (grp_homo_compose r amal_inl).
exists (grp_homo_compose r amal_inr).
rewrite <- (word_concat_w_nil [inl (f x)]).
rewrite <- (word_concat_w_nil [inr (g x)]).
apply (amal_tau nil nil x).
apply equiv_path_grouphomomorphism.
srapply amal_type_ind_hprop.
1: symmetry; apply (grp_homo_unit r).
destruct a; symmetry;
rapply (grp_homo_op r (amal_eta [_]) (amal_eta x)).
rapply (equiv_ap' (equiv_sigma_prod
(fun hk : GroupHomomorphism H X * GroupHomomorphism K X
=> fst hk o f == snd hk o g)) _ _)^-1%equiv.
destruct hkp as [h [k p]].
apply path_prod; cbn;
apply equiv_path_grouphomomorphism;
intro; simpl; rapply right_identity.
Arguments amal_eta {G H K f g} x.
Definition FreeProduct (G H : Group) : Group
:= AmalgamatedFreeProduct grp_trivial G H (grp_trivial_rec _) (grp_trivial_rec _).
Definition freeproduct_inl {G H : Group} : GroupHomomorphism G (FreeProduct G H)
:= amal_inl _ _ _ _ _.
Definition freeproduct_inr {G H : Group} : GroupHomomorphism H (FreeProduct G H)
:= amal_inr _ _ _ _ _.
Definition FreeProduct_rec (G H K : Group)
(f : GroupHomomorphism G K) (g : GroupHomomorphism H K)
: GroupHomomorphism (FreeProduct G H) K.
snrapply (AmalgamatedFreeProduct_rec _ _ _ _ _ _ f g).
refine (grp_homo_unit _ @ (grp_homo_unit _)^).
Definition equiv_freeproduct_rec `{funext : Funext} (G H K : Group)
: (GroupHomomorphism G K) * (GroupHomomorphism H K)
<~> GroupHomomorphism (FreeProduct G H) K.
refine (equiv_amalgamatedfreeproduct_rec _ _ _ _ _ K oE _^-1).
refine (equiv_sigma_prod0 _ _ oE equiv_functor_sigma_id (fun _ => equiv_sigma_contr _)).
intros []; apply contr_inhab_prop.
refine (grp_homo_unit _ @ (grp_homo_unit _)^).
(** The freeproduct is the coproduct in the category of groups. *)
Global Instance hasbinarycoproducts : HasBinaryCoproducts Group.
snrapply Build_BinaryCoproduct.
exact (FreeProduct_rec G H).
srapply amal_type_ind_hprop; simpl.
1: exact (grp_homo_unit _ @ (grp_homo_unit _)^).
Local Notation "[ x ]" := (cons x nil).
change (f (amal_eta [gh] * amal_eta w) = g (amal_eta [gh] * amal_eta w)).
refine (grp_homo_op _ _ _ @ _ @ (grp_homo_op _ _ _)^).