Timings for FreeProduct.v
Require Import Basics Types.
Require Import WildCat.Core WildCat.Coproducts.
Require Import Cubical.DPath.
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 successively out of coequalizers. *)
(** We will call M [amal_type] and prefix all the constructors with [amal_] (for amalgamated free product). *)
Section AmalgamatedFreeProduct.
Context {G H K : Group}
(f : GroupHomomorphism G H) (g : GroupHomomorphism G K).
Local Definition Words : Type := list (H + K).
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.
1: symmetry; apply app_nil.
destruct x; rhs napply app_assoc; 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 ++ [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 ++ [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.
snapply 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 ++ [inl h1, inl h2] ++ y) = e (x ++ [inl (h1 * h2)] ++ y))
(ek : forall (x y : Words) (k1 k2 : K),
e (x ++ [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 *)
(** We will frequently need to use that path types in [amal_type] are hprops, and so it speeds things up to create this instance. It is fast to use [_] here, but when the terms are large below, it becomes slower. *)
Local Instance ishprop_paths_amal_type (x y : amal_type) : IsHProp (x = y) := _.
(** The group operation is concatenation of the underlying list. Most of the work is spent showing that it respects the path constructors. *)
Local Instance sgop_amal_type : SgOp amal_type.
snapply amal_type_rec; only 1: exact _; intros x; revert y.
snapply amal_type_rec; only 1: exact _; intros y.
1: exact (amal_eta (x ++ y)).
refine (ap amal_eta _ @ _ @ ap amal_eta _^).
refine (ap amal_eta _ @ _ @ ap amal_eta _^).
refine (ap amal_eta _ @ _ @ ap amal_eta _^).
refine (ap amal_eta _ @ _ @ ap amal_eta _^).
refine (ap amal_eta _ @ _ @ ap amal_eta _^).
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 _).
refine (ap amal_eta (ap (app x) _)^ @ _ @ ap amal_eta (ap (app x) _)).
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 _).
refine (ap amal_eta (ap (app x) _)^ @ _ @ ap amal_eta (ap (app x) _)).
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 _).
refine (ap amal_eta (ap (app x) _)^ @ _ @ ap amal_eta (ap (app x) _)).
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 _).
refine (ap amal_eta (ap (app x) _)^ @ _).
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 _).
refine (ap amal_eta (ap (app x) _)^ @ _).
(** The identity element is the empty list *)
Local Instance monunit_amal_type : MonUnit amal_type.
Local Instance inverse_amal_type : Inverse 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 _).
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 _).
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 _).
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 _^ @ _).
rewrite inverse_mon_unit.
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 _^ @ _).
rewrite inverse_mon_unit.
Local 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.
Local Instance leftidentity_sgop_amal_type : LeftIdentity sg_op mon_unit.
rapply amal_type_ind_hprop; intro x.
Local 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).
refine (amal_mu_H _ _ _ _ @ _).
change (amal_eta (word_inverse ([inr k] ++ xs) ++ [inr k] ++ xs) = mon_unit).
refine (amal_mu_K _ _ _ _ @ _).
Lemma amal_eta_word_concat_wV (x : Words) : amal_eta (x ++ word_inverse x) = mon_unit.
change (amal_eta ([inl h]) * amal_eta ((xs ++ word_inverse xs)) * amal_eta ([inl h^]) = mon_unit).
rewrite rightidentity_sgop_amal_type.
rewrite <- (app_nil (cons _ _)).
change (amal_eta (([inl h] ++ [inl h^]) ++ nil) = mon_unit).
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])).
change (amal_eta ([inr k]) * amal_eta ((xs ++ word_inverse xs)) * amal_eta ([inr k^]) = mon_unit).
rewrite rightidentity_sgop_amal_type.
rewrite <- (app_nil (cons _ _)).
change (amal_eta (([inr k] ++ [inr k^]) ++ nil) = mon_unit).
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])).
Local Instance leftinverse_sgop_amal_type : LeftInverse (.*.) (^) mon_unit.
rapply amal_type_ind_hprop; intro x.
apply amal_eta_word_concat_Vw.
Local Instance rightinverse_sgop_amal_type : RightInverse (.*.) (^) mon_unit.
rapply amal_type_ind_hprop; intro x.
apply amal_eta_word_concat_wV.
Definition AmalgamatedFreeProduct : Group.
snapply (Build_Group amal_type); repeat split; exact _.
End AmalgamatedFreeProduct.
Arguments amal_eta {G H K f g} x.
Arguments amal_mu_H {G H K f g} x y.
Arguments amal_mu_K {G H K f g} x y.
Arguments amal_tau {G H K f g} x y z.
Arguments amal_omega_H {G H K f g} x y.
Arguments amal_omega_K {G H K f g} x y.
Context {G H K : Group}
{f : GroupHomomorphism G H} {g : GroupHomomorphism G K}.
(** 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 f g -> 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).
Local 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 : H $-> X) (k : K $-> X)
(p : h $o f $== k $o g)
: AmalgamatedFreeProduct f g $-> X.
snapply Build_GroupHomomorphism.
1: srapply (AmalgamatedFreeProduct_rec' X h k p).
Definition amal_inl : H $-> AmalgamatedFreeProduct f g.
snapply Build_GroupHomomorphism.
exact (amal_eta [inl x]).
rewrite <- (app_nil [inl (x * y)]).
rewrite <- (amal_mu_H nil nil x y).
Definition amal_inr : K $-> AmalgamatedFreeProduct f g.
snapply Build_GroupHomomorphism.
exact (amal_eta [inr x]).
rewrite <- (app_nil [inr (x * y)]).
rewrite <- (amal_mu_K nil nil x y).
Definition amal_glue : amal_inl $o f $== amal_inr $o g.
hnf; apply (amal_tau nil nil).
Theorem equiv_amalgamatedfreeproduct_rec `{Funext} (X : Group)
: {h : H $-> X & {k : K $-> X & h $o f $== k $o g }}
<~> (AmalgamatedFreeProduct f g $-> X).
snapply 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 <- (app_nil [inl (f x)]).
rewrite <- (app_nil [inr (g x)]).
exact (amal_tau nil nil x).
apply equiv_path_grouphomomorphism.
srapply amal_type_ind_hprop.
1: symmetry; exact (grp_homo_unit r).
destruct a; symmetry;
rapply (grp_homo_op r (amal_eta [_]) (amal_eta x)).
tapply (equiv_ap' (equiv_sigma_prod
(fun hk : (H $-> X) * (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.
Definition amalgamatedfreeproduct_ind_hprop (P : AmalgamatedFreeProduct f g -> Type)
`{forall x, IsHProp (P x)}
(l : forall a, P (amal_inl a)) (r : forall b, P (amal_inr b))
(Hop : forall x y, P x -> P y -> P (x * y))
: forall x, P x.
rapply amal_type_ind_hprop.
simple_list_induction w a w IH.
rewrite <- (amal_omega_H nil nil).
change (P (amal_inl a * amal_eta w)).
change (P (amal_inr b * amal_eta w)).
Definition amalgamatedfreeproduct_ind_homotopy {P : Group}
{k k' : AmalgamatedFreeProduct f g $-> P}
(l : k $o amal_inl $== k' $o amal_inl)
(r : k $o amal_inr $== k' $o amal_inr)
: k $== k'.
rapply (amalgamatedfreeproduct_ind_hprop _ l r).
intros x y; napply grp_homo_op_agree.
Definition equiv_amalgamatedfreeproduct_ind_homotopy `{Funext} {P : Group}
(k k' : AmalgamatedFreeProduct f g $-> P)
: (k $o amal_inl $== k' $o amal_inl) * (k $o amal_inr $== k' $o amal_inr)
<~> k $== k'.
exact (uncurry amalgamatedfreeproduct_ind_homotopy).
intros p; split; exact (p $@R _).
Definition FreeProduct (G H : Group) : Group
:= AmalgamatedFreeProduct (grp_trivial_rec G) (grp_trivial_rec H).
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_ind_hprop {G H} (P : FreeProduct G H -> Type)
`{forall x, IsHProp (P x)}
(l : forall g, P (freeproduct_inl g))
(r : forall h, P (freeproduct_inr h))
(Hop : forall x y, P x -> P y -> P (x * y))
: forall x, P x
:= amalgamatedfreeproduct_ind_hprop P l r Hop.
(* The above is slow, ~0.15s. *)
Definition freeproduct_ind_homotopy {G H K : Group}
{f f' : FreeProduct G H $-> K}
(l : f $o freeproduct_inl $== f' $o freeproduct_inl)
(r : f $o freeproduct_inr $== f' $o freeproduct_inr)
: f $== f'
:= amalgamatedfreeproduct_ind_homotopy l r.
Definition equiv_freeproduct_ind_homotopy {Funext : Funext} {G H K : Group}
(f f' : FreeProduct G H $-> K)
: (f $o freeproduct_inl $== f' $o freeproduct_inl)
* (f $o freeproduct_inr $== f' $o freeproduct_inr)
<~> f $== f'
:= equiv_amalgamatedfreeproduct_ind_homotopy _ _.
Definition FreeProduct_rec {G H K : Group} (f : G $-> K) (g : H $-> K)
: FreeProduct G H $-> K.
srapply (AmalgamatedFreeProduct_rec _ f g).
exact (grp_homo_unit f @ (grp_homo_unit g)^).
Definition freeproduct_rec_beta_inl {G H K : Group}
(f : G $-> K) (g : H $-> K)
: FreeProduct_rec f g $o freeproduct_inl $== f
:= fun x => right_identity (f x).
Definition freeproduct_rec_beta_inr {G H K : Group}
(f : G $-> K) (g : H $-> K)
: FreeProduct_rec f g $o freeproduct_inr $== g
:= fun x => right_identity (g x).
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 []; rapply contr_inhabited_hprop.
exact (grp_homo_unit _ @ (grp_homo_unit _)^).
(** The free product is the coproduct in the category of groups. *)
Instance hasbinarycoproducts : HasBinaryCoproducts Group.
snapply Build_BinaryCoproduct.
intros Z; exact FreeProduct_rec.
intros; apply freeproduct_rec_beta_inl.
intros; apply freeproduct_rec_beta_inr.
by snapply freeproduct_ind_homotopy.