Timings for Quotient.v
Require Import TruncType.
Require Import Colimits.GraphQuotient.
Require Import Truncations.Core.
Require Import PropResizing.
Local Open Scope path_scope.
(** * The set-quotient of a type by an hprop-valued relation
We aim to model:
<<
Inductive Quotient R : Type :=
| class_of R : A -> Quotient R
| qglue : forall x y, (R x y) -> class_of R x = class_of R y
| ishset_quotient : IsHSet (Quotient R)
>>
We do this by defining the quotient as a 0-truncated graph quotient. *)
Definition Quotient@{i j k} {A : Type@{i}} (R : Relation@{i j} A) : Type@{k}
:= Trunc@{k} 0 (GraphQuotient@{i j k} R).
Definition class_of@{i j k} {A : Type@{i}} (R : Relation@{i j} A)
: A -> Quotient@{i j k} R := tr o gq.
Definition qglue@{i j k} {A : Type@{i}} {R : Relation@{i j} A}
{x y : A}
: R x y -> class_of@{i j k} R x = class_of R y
:= fun p => ap tr (gqglue p).
Global Instance ishset_quotient {A : Type} (R : Relation A)
: IsHSet (Quotient R) := _.
Definition Quotient_ind@{i j k l}
{A : Type@{i}} (R : Relation@{i j} A)
(P : Quotient@{i j k} R -> Type@{l}) {sP : forall x, IsHSet (P x)}
(pclass : forall x, P (class_of R x))
(peq : forall x y (H : R x y), qglue H # pclass x = pclass y)
: forall q, P q.
eapply Trunc_ind, GraphQuotient_ind.
refine (transport_compose _ _ _ _ @ _).
Definition Quotient_ind_beta_qglue@{i j k l}
{A : Type@{i}} (R : Relation@{i j} A)
(P : Quotient@{i j k} R -> Type@{l}) {sP : forall x, IsHSet (P x)}
(pclass : forall x, P (class_of R x))
(peq : forall x y (H : R x y), qglue H # pclass x = pclass y)
(x y : A) (p : R x y)
: apD (Quotient_ind@{i j k l} R P pclass peq) (qglue p) = peq x y p.
refine (apD_compose' tr _ _ @ _).
refine (ap _ (GraphQuotient_ind_beta_gqglue _ pclass
(fun a b p0 => transport_compose P tr _ _ @ peq a b p0) _ _ _) @ _).
Definition Quotient_rec@{i j k l}
{A : Type@{i}} (R : Relation@{i j} A)
(P : Type@{l}) `{IsHSet P} (pclass : A -> P)
(peq : forall x y, R x y -> pclass x = pclass y)
: Quotient@{i j k} R -> P.
eapply Trunc_rec, GraphQuotient_rec.
Definition Quotient_rec_beta_qglue @{i j k l}
{A : Type@{i}} (R : Relation@{i j} A)
(P : Type@{l}) `{IsHSet P} (pclass : A -> P)
(peq : forall x y, R x y -> pclass x = pclass y)
(x y : A) (p : R x y)
: ap (Quotient_rec@{i j k l} R P pclass peq) (qglue p) = peq x y p.
refine ((ap_compose tr _ _)^ @ _).
srapply GraphQuotient_rec_beta_gqglue.
Arguments Quotient : simpl never.
Arguments class_of : simpl never.
Arguments qglue : simpl never.
Arguments Quotient_ind_beta_qglue : simpl never.
Arguments Quotient_rec_beta_qglue : simpl never.
Notation "A / R" := (Quotient (A:=A) R).
Context `{Univalence} {A : Type} (R : Relation A) `{is_mere_relation _ R}
`{Transitive _ R} `{Symmetric _ R} `{Reflexive _ R}.
(* The proposition of being in a given class in a quotient. *)
Definition in_class : A / R -> A -> HProp.
exact (Build_HProp (R a b)).
refine (transport_const _ _ @ _).
srapply equiv_iff_hprop; cbn.
1: apply (transitivity (symmetry _ _ p)).
(* Quotient induction into a hprop. *)
Definition Quotient_ind_hprop
(P : A / R -> Type) `{forall x, IsHProp (P x)}
(dclass : forall x, P (class_of R x)) : forall q, P q.
srapply (Quotient_ind R P dclass).
all: try (intro; apply trunc_succ).
(* Being in a class is decidable if the Relation is decidable. *)
Global Instance decidable_in_class `{forall x y, Decidable (R x y)}
: forall x a, Decidable (in_class x a).
by srapply Quotient_ind_hprop.
(* if x is in a class q, then the class of x is equal to q. *)
Lemma path_in_class_of : forall q x, in_class q x -> q = class_of R x.
Lemma related_quotient_paths : forall x y,
class_of R x = class_of R y -> R x y.
change (in_class (class_of R x) y).
Theorem path_quotient : forall x y,
R x y <~> (class_of R x = class_of R y).
apply related_quotient_paths.
Definition Quotient_rec2 `{Funext} {B : HSet} {dclass : A -> A -> B}
{dequiv : forall x x', R x x' -> forall y y',
R y y' -> dclass x y = dclass x' y'}
: A / R -> A / R -> B.
Definition Quotient_ind_hprop' (P : A / R -> Type)
`{forall x, IsHProp (P (class_of _ x))}
(dclass : forall x, P (class_of _ x)) : forall y, P y.
apply Quotient_ind with dclass.
1: intro; apply istrunc_succ.
intros ???; apply path_ishprop.
intros; apply path_ishprop.
(** The map class_of : A -> A/R is a surjection. *)
Global Instance issurj_class_of : IsSurjection (class_of R).
srapply Quotient_ind_hprop.
(* Universal property of quotient *)
(* Lemma 6.10.3 *)
Theorem equiv_quotient_ump (B : HSet)
: (A / R -> B) <~> {f : A -> B & forall x y, R x y -> f x = f y}.
srapply equiv_adjointify.
exists (compose f (class_of R)).
apply (Quotient_rec _ _ _ H').
by apply equiv_path_sigma_hprop.
srapply Quotient_ind_hprop.
(** TODO: The equivalence with VVquotient [A//R].
10.1.10.
Equivalence Relations are effective and there is an equivalence [A/R<~>A//R].
This will need propositional resizing if we don't want to raise the universe level.
*)
(**
The theory of canonical quotients is developed by C.Cohen:
http://perso.crans.org/cohen/work/quotients/
*)
(* TODO: Develop a notion of set with Relation and use that instead of manually adding Relation preserving conditions. *)
Definition Quotient_functor
{A : Type} (R : Relation A)
{B : Type} (S : Relation B)
(f : A -> B) (fresp : forall x y, R x y -> S (f x) (f y))
: Quotient R -> Quotient S.
refine (Quotient_rec R _ (class_of S o f) _).
Definition Quotient_functor_idmap
{A : Type} {R : Relation A}
: Quotient_functor R R idmap (fun x y => idmap) == idmap.
by srapply Quotient_ind_hprop.
Definition Quotient_functor_compose
{A : Type} {R : Relation A}
{B : Type} {S : Relation B}
{C : Type} {T : Relation C}
(f : A -> B) (fresp : forall x y, R x y -> S (f x) (f y))
(g : B -> C) (gresp : forall x y, S x y -> T (g x) (g y))
: Quotient_functor R T (g o f) (fun x y => (gresp _ _) o (fresp x y))
== Quotient_functor S T g gresp o Quotient_functor R S f fresp.
by srapply Quotient_ind_hprop.
Context {A : Type} (R : Relation A)
{B : Type} (S : Relation B).
Global Instance isequiv_quotient_functor (f : A -> B)
(fresp : forall x y, R x y <-> S (f x) (f y)) `{IsEquiv _ _ f}
: IsEquiv (Quotient_functor R S f (fun x y => fst (fresp x y))).
srapply (isequiv_adjointify _ (Quotient_functor S R f^-1 _)).
abstract (do 2 rewrite eisretr; apply s).
all: srapply Quotient_ind.
intros; apply path_ishprop.
intros; apply path_ishprop.
Definition equiv_quotient_functor (f : A -> B) `{IsEquiv _ _ f}
(fresp : forall x y, R x y <-> S (f x) (f y))
: Quotient R <~> Quotient S
:= Build_Equiv _ _ (Quotient_functor R S f (fun x y => fst (fresp x y))) _.
Definition equiv_quotient_functor' (f : A <~> B)
(fresp : forall x y, R x y <-> S (f x) (f y))
: Quotient R <~> Quotient S
:= equiv_quotient_functor f fresp.
(** ** Quotients of kernels of maps to sets give a surjection/mono factorization. *)
(** Because the statement uses nested Sigma types, we need several variables to serve as [max] and [u+1]. We write [ar] for [max(a,r)], [ar'] for [ar+1], etc. *)
Universes a r ar ar' b ab abr.
Constraint a <= ar, r <= ar, ar < ar', a <= ab, b <= ab, ab <= abr, ar <= abr.
(** A function we want to factor. *)
Context {A : Type@{a}} {B : Type@{b}} `{IsHSet B} (f : A -> B).
(** A mere Relation equivalent to its kernel. *)
Context (R : Relation@{a r} A)
(is_ker : forall x y, f x = f y <~> R x y).
(** The factorization theorem. An advantage of stating it as one bundled result is that it is easier to state variations as we do below. Disadvantages are that it requires more universe variables and that each piece of the answer depends on [Funext] and all of the universe variables, even when these aren't needed for that piece. Below we will clean up the universe variables slightly, so we make this version [Local]. *)
Local Definition quotient_kernel_factor_internal
: exists (C : Type@{ar}) (e : A -> C) (m : C -> B),
IsHSet C * IsSurjection e * IsEmbedding m * (f = m o e).
(* [exists (class_of R)] works, but the next line reduces the universe variables in a way that makes Coq 8.18 and 8.19 compatible. *)
refine (exist@{ar abr} _ (class_of R) _).
refine (Quotient_ind R (fun _ => B) f _).
lhs nrapply transport_const.
exact ((is_ker x y)^-1 p).
repeat split; try exact _.
apply path_sigma_hprop; simpl.
2: intros; apply path_ishprop.
2: intros; apply path_ishprop.
(** We clean up the universe variables here, using only those declared in this Section. *)
Definition quotient_kernel_factor_general@{|}
:= Eval unfold quotient_kernel_factor_internal in
quotient_kernel_factor_internal@{ar' ar abr abr ab}.
(** A common special case of [quotient_kernel_factor] is when we define [R] to be [f x = f y]. Then universes [r] and [b] are unified. *)
Definition quotient_kernel_factor@{a b ab ab' | a <= ab, b <= ab, ab < ab'}
`{Funext} {A : Type@{a}} {B : Type@{b}} `{IsHSet B} (f : A -> B)
: exists (C : Type@{ab}) (e : A -> C) (m : C -> B),
IsHSet C * IsSurjection e * IsEmbedding m * (f = m o e).
exact (quotient_kernel_factor_general@{a b ab ab' b ab ab}
f (fun x y => f x = f y) (fun x y => equiv_idmap)).
(** If we use propositional resizing, we can replace [f x = f y] with a proposition [R x y] in universe [a], so that the universe of [C] is the same as the universe of [A]. *)
Definition quotient_kernel_factor_small@{a a' b ab | a < a', a <= ab, b <= ab}
`{Funext} `{PropResizing}
{A : Type@{a}} {B : Type@{b}} `{IsHSet B} (f : A -> B)
: exists (C : Type@{a}) (e : A -> C) (m : C -> B),
IsHSet C * IsSurjection e * IsEmbedding m * (f = m o e).
exact (quotient_kernel_factor_general@{a a a a' b ab ab}
f (fun x y => resize_hprop@{b a} (f x = f y)) (fun x y => equiv_resize_hprop _)).