Built with Alectryon, running Coq+SerAPI v8.18.0+0.18.3. Bubbles () indicate interactive fragments: hover for details, tap to reveal contents. Use Ctrl+↑ Ctrl+↓ to navigate, Ctrl+🖱️ to focus. On Mac, use instead of Ctrl.
(* -*- mode: coq; mode: visual-line -*- *)

[Loading ML file number_string_notation_plugin.cmxs (using legacy method) ... done]
Require Import Modalities.Modality. (* Users of this file almost always want to be able to write [Tr n] for both a [Modality] and a [ReflectiveSubuniverse], so they want the coercion [modality_to_reflective_subuniverse]: *) Require Export (coercions) Modalities.Modality. (** * Truncations of types, in all dimensions *) Local Open Scope path_scope. Generalizable Variables A X n. (** ** The definition *) (** The definition of [Trunc n], the n-truncation of a type. If Coq supported higher inductive types natively, we would construct this as somthing like: Inductive Trunc n (A : Type) : Type := | tr : A -> Trunc n A | istrunc_truncation : forall (f : Sphere n.+1 -> Trunc n A) (x : Sphere n.+1), f x = f North. However, while we are faking our higher-inductives anyway, we can take some shortcuts, rather than translating the definition above. Firstly, we directly posit a “constructor” giving truncatedness, rather than rephrasing it in terms of maps of spheres. Secondly, we omit the “computation rule” for this constructor, since it is implied by truncatedness of the result type (and, for essentially that reason, is never wanted in practice anyway). *) Module Export Trunc. Delimit Scope trunc_scope with trunc. Cumulative Private Inductive Trunc (n : trunc_index) (A :Type) : Type := tr : A -> Trunc n A. Bind Scope trunc_scope with Trunc. Arguments tr {n A} a. (** Without explicit universe parameters, this instance is insufficiently polymorphic. *)
n: trunc_index
A: Type

IsTrunc n (Trunc n A)
Admitted. Definition Trunc_ind {n A} (P : Trunc n A -> Type) {Pt : forall aa, IsTrunc n (P aa)} : (forall a, P (tr a)) -> (forall aa, P aa) := (fun f aa => match aa with tr a => fun _ => f a end Pt). End Trunc. (** The non-dependent version of the eliminator. *) Definition Trunc_rec {n A X} `{IsTrunc n X} : (A -> X) -> (Trunc n A -> X) := Trunc_ind (fun _ => X). Definition Trunc_rec_tr n {A : Type} : Trunc_rec (A:=A) (tr (n:=n)) == idmap := Trunc_ind _ (fun a => idpath). (** ** [Trunc] is a modality *)
n: trunc_index

Modality
n: trunc_index

Modality
n: trunc_index

forall T U : Type, IsTrunc n T -> forall f : T -> U, IsEquiv f -> IsTrunc n U
n: trunc_index
Type -> Type
n: trunc_index
forall T : Type, IsTrunc n (?Goal0 T)
n: trunc_index
forall T : Type, T -> ?Goal0 T
n: trunc_index
forall (A : Type) (B : ?Goal0 A -> Type), (forall oa : ?Goal0 A, IsTrunc n (B oa)) -> (forall a : A, B (?Goal2 A a)) -> forall z : ?Goal0 A, B z
n: trunc_index
forall (A : Type) (B : ?Goal0 A -> Type) (B_inO : forall oa : ?Goal0 A, IsTrunc n (B oa)) (f : forall a : A, B (?Goal2 A a)) (a : A), ?Goal3 A B B_inO f (?Goal2 A a) = f a
n: trunc_index
forall A : Type, IsTrunc n A -> forall z z' : A, IsTrunc n (z = z')
n: trunc_index

forall T U : Type, IsTrunc n T -> forall f : T -> U, IsEquiv f -> IsTrunc n U
intros A B ? f ?; rapply (istrunc_isequiv_istrunc A f).
n: trunc_index

Type -> Type
exact (Trunc n).
n: trunc_index

forall T : Type, IsTrunc n (Trunc n T)
intros; apply istrunc_truncation.
n: trunc_index

forall T : Type, T -> Trunc n T
intros A; apply tr.
n: trunc_index

forall (A : Type) (B : Trunc n A -> Type), (forall oa : Trunc n A, IsTrunc n (B oa)) -> (forall a : A, B ((fun A0 : Type => tr) A a)) -> forall z : Trunc n A, B z
n: trunc_index
A: Type
B: Trunc n A -> Type
B_inO: forall oa : Trunc n A, IsTrunc n (B oa)
f: forall a : A, B (tr a)
oa: Trunc n A

B oa
exact (Trunc_ind B f oa).
n: trunc_index

forall (A : Type) (B : Trunc n A -> Type) (B_inO : forall oa : Trunc n A, IsTrunc n (B oa)) (f : forall a : A, B ((fun A0 : Type => tr) A a)) (a : A), (fun (A0 : Type) (B0 : Trunc n A0 -> Type) (B_inO0 : forall oa : Trunc n A0, IsTrunc n (B0 oa)) (f0 : forall a0 : A0, B0 ((fun A1 : Type => tr) A0 a0)) (oa : Trunc n A0) => Trunc_ind B0 f0 oa : B0 oa) A B B_inO f ((fun A0 : Type => tr) A a) = f a
intros; reflexivity.
n: trunc_index

forall A : Type, IsTrunc n A -> forall z z' : A, IsTrunc n (z = z')
exact (@istrunc_paths' n). Defined. (** We don't usually declare modalities as coercions, but this particular one is convenient so that lemmas about (for instance) connected maps can be applied to truncation modalities without the user/reader needing to be (particularly) aware of the general notion of modality. *) Coercion Tr : trunc_index >-> Modality. (** However, if the coercion is not printed, then we get things like [Tr (-1) X] being printed as [(-1) X], which is terribly confusing. So we tell Coq to always print this coercion. This does mean that although the user can type things like [IsConnected n X], it will always be displayed back as [IsConnected (Tr n) X]. *) Add Printing Coercion Tr. Section TruncationModality. Context (n : trunc_index). Definition trunc_iff_isequiv_truncation (A : Type) : IsTrunc n A <-> IsEquiv (@tr n A) := inO_iff_isequiv_to_O (Tr n) A. Global Instance isequiv_tr A `{IsTrunc n A} : IsEquiv (@tr n A) := fst (trunc_iff_isequiv_truncation A) _. Definition equiv_tr (A : Type) `{IsTrunc n A} : A <~> Tr n A := Build_Equiv _ _ (@tr n A) _. Definition untrunc_istrunc {A : Type} `{IsTrunc n A} : Tr n A -> A := (@tr n A)^-1. (** ** Functoriality *) (** Since a modality lives on a single universe, by default if we simply define [Trunc_functor] to be [O_functor] then it would force [X] and [Y] to live in the same universe. But since we defined [Trunc] as a cumulative inductive, if we add universe annotations we can make [Trunc_functor] more universe-polymorphic than [O_functor] is. This is sometimes useful. *) Definition Trunc_functor@{i j k} {X : Type@{i}} {Y : Type@{j}} (f : X -> Y) : Tr@{i} n X -> Tr@{j} n Y := O_functor@{k k k} (Tr n) f. Global Instance is0functor_Tr : Is0Functor (Tr n) := Build_Is0Functor _ _ _ _ (Tr n) (@Trunc_functor). Global Instance Trunc_functor_isequiv {X Y : Type} (f : X -> Y) `{IsEquiv _ _ f} : IsEquiv (Trunc_functor f) := isequiv_O_functor (Tr n) f. Definition Trunc_functor_equiv {X Y : Type} (f : X <~> Y) : Tr n X <~> Tr n Y := equiv_O_functor (Tr n) f. Definition Trunc_functor_compose {X Y Z} (f : X -> Y) (g : Y -> Z) : Trunc_functor (g o f) == Trunc_functor g o Trunc_functor f := O_functor_compose (Tr n) f g. Definition Trunc_functor_idmap (X : Type) : @Trunc_functor X X idmap == idmap := O_functor_idmap (Tr n) X. Definition isequiv_Trunc_functor {X Y} (f : X -> Y) `{IsEquiv _ _ f} : IsEquiv (Trunc_functor f) := isequiv_O_functor (Tr n) f. Definition equiv_Trunc_prod_cmp {X Y} : Tr n (X * Y) <~> Tr n X * Tr n Y := equiv_O_prod_cmp (Tr n) X Y.
n: trunc_index

Is1Functor (Tr n)
n: trunc_index

Is1Functor (Tr n)
n: trunc_index

forall (a b : Type) (f g : a $-> b), f $== g -> fmap (Tr n) f $== fmap (Tr n) g
n: trunc_index
forall a : Type, fmap (Tr n) (Id a) $== Id (Tr n a)
n: trunc_index
forall (a b c : Type) (f : a $-> b) (g : b $-> c), fmap (Tr n) (g $o f) $== fmap (Tr n) g $o fmap (Tr n) f
n: trunc_index

forall (a b : Type) (f g : a $-> b), f $== g -> fmap (Tr n) f $== fmap (Tr n) g
apply @O_functor_homotopy.
n: trunc_index

forall a : Type, fmap (Tr n) (Id a) $== Id (Tr n a)
apply @Trunc_functor_idmap.
n: trunc_index

forall (a b c : Type) (f : a $-> b) (g : b $-> c), fmap (Tr n) (g $o f) $== fmap (Tr n) g $o fmap (Tr n) f
apply @Trunc_functor_compose. Defined. End TruncationModality. (** We have to teach Coq to translate back and forth between [IsTrunc n] and [In (Tr n)]. *)
n: trunc_index
A: Type
IsTrunc0: IsTrunc n A

In (Tr n) A
n: trunc_index
A: Type
IsTrunc0: IsTrunc n A

In (Tr n) A
assumption. Defined. (** Having both of these as [Instance]s would cause infinite loops. *)
n: trunc_index
A: Type
H: In (Tr n) A

IsTrunc n A
n: trunc_index
A: Type
H: In (Tr n) A

IsTrunc n A
assumption. Defined. (** Instead, we make the latter an immediate instance, but with high cost (i.e. low priority) so that it doesn't override the ordinary lemmas about truncation. Unfortunately, [Hint Immediate] doesn't allow specifying a cost, so we use [Hint Extern] instead. *) (** Hint Immediate istrunc_inO_tr : typeclass_instances. *) (** See https://github.com/coq/coq/issues/11697 *) #[export] Hint Extern 1000 (IsTrunc _ _) => simple apply istrunc_inO_tr; solve [ trivial ] : typeclass_instances. (** This doesn't seem to be quite the same as [Hint Immediate] with a different cost either, though. *) (** Unfortunately, this isn't perfect; Coq still can't always find [In n] hypotheses in the context when it wants [IsTrunc]. You can always apply [istrunc_inO_tr] explicitly, but sometimes it also works to just [pose] it into the context. *) (** We do the same for [IsTruncMap n] and [MapIn (Tr n)]. *)
n: trunc_index
A, B: Type
f: A -> B
H: IsTruncMap n f

MapIn (Tr n) f
n: trunc_index
A, B: Type
f: A -> B
H: IsTruncMap n f

MapIn (Tr n) f
assumption. Defined.
n: trunc_index
A, B: Type
f: A -> B
H: MapIn (Tr n) f

IsTruncMap n f
n: trunc_index
A, B: Type
f: A -> B
H: MapIn (Tr n) f

IsTruncMap n f
assumption. Defined. #[export] Hint Immediate istruncmap_mapinO_tr : typeclass_instances. (** ** A few special things about the (-1)-truncation *) Local Open Scope trunc_scope. (** We define [merely A] to be an inhabitant of the universe [hProp] of hprops, rather than a type. We can always treat it as a type because there is a coercion, but this means that if we need an element of [hProp] then we don't need a separate name for it. *) Definition merely (A : Type@{i}) : HProp@{i} := Build_HProp (Tr (-1) A). Definition hexists {X} (P : X -> Type) : HProp := merely (sig P). Definition hor (P Q : Type) : HProp := merely (P + Q). Declare Scope hprop_scope. Notation "A \/ B" := (hor A B) : hprop_scope. Definition himage {X Y} (f : X -> Y) := image (Tr (-1)) f.
A: Type
IsHProp0: IsHProp A
ma: merely A

Contr A
A: Type
IsHProp0: IsHProp A
ma: merely A

Contr A
A: Type
IsHProp0: IsHProp A
ma: merely A

IsConnected (Tr (-1)) A
refine (contr_inhabited_hprop _ ma). Defined. (** A stable type is logically equivalent to its (-1)-truncation. (It follows that this is true for decidable types as well.) *)
A: Type
A_stable: Stable A

Tr (-1) A <-> A
A: Type
A_stable: Stable A

Tr (-1) A <-> A
A: Type
A_stable: Stable A

Tr (-1) A -> A
A: Type
A_stable: Stable A
ma: Tr (-1) A

A
A: Type
A_stable: Stable A
ma: Tr (-1) A
na: ~ A

Empty
revert ma; rapply Trunc_ind; exact na. Defined. (** Surjections are the (-1)-connected maps, but they can be characterized more simply since an inhabited hprop is automatically contractible. *) Notation IsSurjection := (IsConnMap (Tr (-1))).
A, B: Type
f: A -> B

(forall b : B, merely (hfiber f b)) -> IsConnMap (Tr (-1)) f
A, B: Type
f: A -> B

(forall b : B, merely (hfiber f b)) -> IsConnMap (Tr (-1)) f
A, B: Type
f: A -> B
H: forall b : B, merely (hfiber f b)
b: B

Tr (-1) (hfiber f b)
apply H. Defined. (** A family of types is pointwise merely inhabited if and only if the corresponding fibration is surjective. *)
X: Type
P: X -> Type

(forall x : X, merely (P x)) <-> IsConnMap (Tr (-1)) (pr1 : {x : X & P x} -> X)
X: Type
P: X -> Type

(forall x : X, merely (P x)) <-> IsConnMap (Tr (-1)) (pr1 : {x : X & P x} -> X)
X: Type
P: X -> Type

(forall x : X, merely (P x)) <-> (forall a : X, In (Conn (Tr (-1))) (P a))
X: Type
P: X -> Type
a: X

merely (P a) <-> In (Conn (Tr (-1))) (P a)
symmetry; apply (iff_contr_hprop (Tr (-1) (P a))). Defined.
H: Funext
X: Type
P: X -> Type

(forall x : X, merely (P x)) <~> IsConnMap (Tr (-1)) (pr1 : {x : X & P x} -> X)
H: Funext
X: Type
P: X -> Type

(forall x : X, merely (P x)) <~> IsConnMap (Tr (-1)) (pr1 : {x : X & P x} -> X)
exact (equiv_iff_hprop_uncurried (iff_merely_issurjection P)). Defined. (** Surjections cancel on the right *)
A, B, C: Type
f: A -> B
g: B -> C
isconn: IsConnMap (Tr (-1)) (g o f)

IsConnMap (Tr (-1)) g
A, B, C: Type
f: A -> B
g: B -> C
isconn: IsConnMap (Tr (-1)) (g o f)

IsConnMap (Tr (-1)) g
A, B, C: Type
f: A -> B
g: B -> C
isconn: IsConnMap (Tr (-1)) (g o f)
c: C

IsConnected (Tr (-1)) (hfiber g c)
A, B, C: Type
f: A -> B
g: B -> C
isconn: IsConnMap (Tr (-1)) (g o f)
c: C

Tr (-1) (hfiber g c)
A, B, C: Type
f: A -> B
g: B -> C
isconn: IsConnMap (Tr (-1)) (g o f)
c: C

hfiber (fun x : A => g (f x)) c -> hfiber g c
A, B, C: Type
f: A -> B
g: B -> C
isconn: IsConnMap (Tr (-1)) (g o f)
c: C
Tr (-1) (hfiber (fun x : A => g (f x)) c)
A, B, C: Type
f: A -> B
g: B -> C
isconn: IsConnMap (Tr (-1)) (g o f)
c: C

hfiber (fun x : A => g (f x)) c -> hfiber g c
A, B, C: Type
f: A -> B
g: B -> C
isconn: IsConnMap (Tr (-1)) (g o f)
c: C
a: A
p: g (f a) = c

hfiber g c
exact (f a; p).
A, B, C: Type
f: A -> B
g: B -> C
isconn: IsConnMap (Tr (-1)) (g o f)
c: C

Tr (-1) (hfiber (fun x : A => g (f x)) c)
apply center, isconn. Defined. (** Retractions are surjective. *)
X, Y: Type
r: X -> Y
s: Y -> X
h: forall y : Y, r (s y) = y

IsConnMap (Tr (-1)) r
X, Y: Type
r: X -> Y
s: Y -> X
h: forall y : Y, r (s y) = y

IsConnMap (Tr (-1)) r
X, Y: Type
r: X -> Y
s: Y -> X
h: forall y : Y, r (s y) = y
y: Y

IsConnected (Tr (-1)) (hfiber r y)
X, Y: Type
r: X -> Y
s: Y -> X
h: forall y : Y, r (s y) = y
y: Y

Tr (-1) (hfiber r y)
exact (tr (s y; h y)). Defined. (** Since embeddings are the (-1)-truncated maps, a map that is both a surjection and an embedding is an equivalence. *)
A, B: Type
f: A -> B
IsSurjection0: IsConnMap (Tr (-1)) f
IsEmbedding0: IsEmbedding f

IsEquiv f
A, B: Type
f: A -> B
IsSurjection0: IsConnMap (Tr (-1)) f
IsEmbedding0: IsEmbedding f

IsEquiv f
apply (@isequiv_conn_ino_map (Tr (-1))); assumption. Defined. (** If [X] is a set and [f : Y -> Z] is a surjection, then [- o f] is an embedding. *)
H: Funext
X, Y, Z: Type
IsHSet0: IsHSet X
f: Y -> Z
IsSurjection0: IsConnMap (Tr (-1)) f

IsEmbedding (fun phi : Z -> X => phi o f)
H: Funext
X, Y, Z: Type
IsHSet0: IsHSet X
f: Y -> Z
IsSurjection0: IsConnMap (Tr (-1)) f

IsEmbedding (fun phi : Z -> X => phi o f)
H: Funext
X, Y, Z: Type
IsHSet0: IsHSet X
f: Y -> Z
IsSurjection0: IsConnMap (Tr (-1)) f
phi: Y -> X

forall (x : hfiber (fun (phi : Z -> X) (x : Y) => phi (f x)) phi) (y : hfiber (fun (phi : Z -> X) (x0 : Y) => phi (f x0)) phi), Contr (x = y)
H: Funext
X, Y, Z: Type
IsHSet0: IsHSet X
f: Y -> Z
IsSurjection0: IsConnMap (Tr (-1)) f
phi: Y -> X
g0, g1: hfiber (fun (phi : Z -> X) (x : Y) => phi (f x)) phi

Contr (g0 = g1)
H: Funext
X, Y, Z: Type
IsHSet0: IsHSet X
f: Y -> Z
IsSurjection0: IsConnMap (Tr (-1)) f
phi: Y -> X
g0, g1: hfiber (fun (phi : Z -> X) (x : Y) => phi (f x)) phi

g0 = g1
H: Funext
X, Y, Z: Type
IsHSet0: IsHSet X
f: Y -> Z
IsSurjection0: IsConnMap (Tr (-1)) f
phi: Y -> X
g0, g1: hfiber (fun (phi : Z -> X) (x : Y) => phi (f x)) phi

g0.1 == g1.1
H: Funext
X, Y, Z: Type
IsHSet0: IsHSet X
f: Y -> Z
IsSurjection0: IsConnMap (Tr (-1)) f
phi: Y -> X
g0, g1: hfiber (fun (phi : Z -> X) (x : Y) => phi (f x)) phi
y: Y

g0.1 (f y) = g1.1 (f y)
exact (ap10 (g0.2 @ g1.2^) y). Defined. (** ** Tactic to remove truncations in hypotheses if possible See [strip_reflections] and [strip_modalities] for generalizations to other reflective subuniverses and modalities. *) Ltac strip_truncations := (** search for truncated hypotheses *) progress repeat match goal with | [ T : _ |- _ ] => revert_opaque T; refine (@Trunc_ind _ _ _ _ _); (** ensure that we didn't generate more than one subgoal, i.e. that the goal was appropriately truncated *) []; intro T end. (** We would like to define this in terms of the [strip_modalities] tactic, however [O_ind] uses more universes than [Trunc_ind] which causes some problems down the line. *) (* Ltac strip_truncations := strip_modalities. *) (** ** Iterated truncations *) (** Compare to [O_leq_Tr] and [O_strong_leq_Tr] in SeparatedTrunc.v. *)
n, m: trunc_index
Hmn: m <= n

O_leq (Tr m) (Tr n)
n, m: trunc_index
Hmn: m <= n

O_leq (Tr m) (Tr n)
intros A; rapply istrunc_leq. Defined.
n, m: trunc_index
X: Type

Tr (trunc_index_min n m) X <~> Tr n (Tr m X)
n, m: trunc_index
X: Type

Tr (trunc_index_min n m) X <~> Tr n (Tr m X)
n, m: trunc_index
X: Type
p: trunc_index_min n m = n

Tr (trunc_index_min n m) X <~> Tr n (Tr m X)
n, m: trunc_index
X: Type
q: trunc_index_min n m = m
Tr (trunc_index_min n m) X <~> Tr n (Tr m X)
n, m: trunc_index
X: Type
p: trunc_index_min n m = n

Tr (trunc_index_min n m) X <~> Tr n (Tr m X)
n, m: trunc_index
X: Type
p: trunc_index_min n m = n
l: trunc_index_min n m <= m

Tr (trunc_index_min n m) X <~> Tr n (Tr m X)
n, m: trunc_index
X: Type
l: n <= m

Tr n X <~> Tr n (Tr m X)
n, m: trunc_index
X: Type
l: n <= m

IsEquiv (Trunc_functor n tr)
n, m: trunc_index
X: Type
l: n <= m

IsConnMap (Tr n) tr
n, m: trunc_index
X: Type
l: n <= m

O_leq (Tr n) (Tr m)
rapply O_leq_Tr_leq.
n, m: trunc_index
X: Type
q: trunc_index_min n m = m

Tr (trunc_index_min n m) X <~> Tr n (Tr m X)
n, m: trunc_index
X: Type
q: trunc_index_min n m = m
l: trunc_index_min n m <= n

Tr (trunc_index_min n m) X <~> Tr n (Tr m X)
n, m: trunc_index
X: Type
l: m <= n

Tr m X <~> Tr n (Tr m X)
n, m: trunc_index
X: Type
l: m <= n

IsTrunc n (Tr m X)
srapply istrunc_leq. Defined.
n, m: trunc_index
X: Type

Tr n (Tr m X) <~> Tr m (Tr n X)
n, m: trunc_index
X: Type

Tr n (Tr m X) <~> Tr m (Tr n X)
n, m: trunc_index
X: Type

trunc_index_min n m = trunc_index_min m n
apply trunc_index_min_swap. Defined. (** If you are looking for a theorem about truncation, you may want to read the note "Finding Theorems" in "STYLE.md". *)