Built with Alectryon, running Coq+SerAPI v8.19.0+0.19.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.
(** * The groupoid structure of paths *)
[Loading ML file number_string_notation_plugin.cmxs (using legacy method) ... done]
LocalOpen Scope path_scope.(** ** Naming conventions We need good naming conventions that allow us to name theorems without looking them up. The names should indicate the structure of the theorem, but they may sometimes be ambiguous, in which case you just have to know what is going on. We shall adopt the following principles: - we are not afraid of long names - we are not afraid of short names when they are used frequently - we use underscores - name of theorems and lemmas are lower-case - records and other types may be upper or lower case Theorems about concatenation of paths are called [concat_XXX] where [XXX] tells us what is on the left-hand side of the equation. You have to guess the right-hand side. We use the following symbols in [XXX]: - [1] means the identity path, or sometimes the identity function - [p] means 'the path' - [V] means 'the inverse path' - [A] means '[ap]' - [M] means the thing we are moving across equality - [x] means 'the point' which is not a path, e.g. in [transport p x] - [2] means relating to 2-dimensional paths - [3] means relating to 3-dimensional paths, and so on Associativity is indicated with an underscore. Here are some examples of how the name gives hints about the left-hand side of the equation. - [concat_1p] means [1 @ p] - [concat_Vp] means [p^ @ p] - [concat_p_pp] means [p @ (q @ r)] - [concat_pp_p] means [(p @ q) @ r] - [concat_V_pp] means [p^ @ (p @ q)] - [concat_pV_p] means [(q @ p^) @ p] or [(p @ p^) @ q], but probably the former because for the latter you could just use [concat_pV]. Laws about inverse of something are of the form [inv_XXX], and those about [ap] are of the form [ap_XXX], and so on. For example: - [inv_pp] is about [(p @ q)^] - [inv_V] is about [(p^)^] - [inv_A] is about [(ap f p)^] - [ap_V] is about [ap f (p^)] - [ap_pp] is about [ap f (p @ q)] - [ap_idmap] is about [ap idmap p] - [ap_1] is about [ap f 1] - [ap02_p2p] is about [ap02 f (p @@ q)] Then we have laws which move things around in an equation. The naming scheme here is [moveD_XXX]. The direction [D] indicates where to move to: [L] means that we move something to the left-hand side, whereas [R] means we are moving something to the right-hand side. The part [XXX] describes the shape of the side _from_ which we are moving where the thing that is getting moves is called [M]. The presence of 1 next to an [M] generally indicates an *implied* identity path which is inserted automatically after the movement. Examples: - [moveL_pM] means that we transform [p = q @ r] to [p @ r^ = q] because we are moving something to the left-hand side, and we are moving the right argument of [concat]. - [moveR_Mp] means that we transform [p @ q = r] to [q = p^ @ r] because we move to the right-hand side, and we are moving the left argument of [concat]. - [moveR_1M] means that we transform [p = q] (rather than [p = 1 @ q]) to [p @ q^ = 1]. There are also cancellation laws called [cancelR] and [cancelL], which are inverse to the 2-dimensional 'whiskering' operations [whiskerR] and [whiskerL].*)(** ** The 1-dimensional groupoid structure. *)(** Partially applied versions of [concat]. The first is a synonym for [concat p], but we include it to parallel the second one. *)Definitionconcat_l {A : Type} {xyz : A} (p : x = y)
: (y = z) -> (x = z)
:= concat p.Definitionconcat_r {A : Type} {xyz : A} (q : y = z)
: (x = y) -> (x = z)
:= funp => p @ q.(** The operation of composing a path on two sides. *)Definitionconcat_lr {A : Type} {wxyz : A} (p : w = x) (r : y = z)
: (x = y) -> (w = z)
:= funq => p @ q @ r.(** The "/" indicates that these should be unfolded by [cbn] and [simpl] when the specified arguments are given. *)Arguments concat_l {A x y z} p q /.Arguments concat_r {A x y z} q p /.Arguments concat_lr {A w x y z} p r q /.(** The identity path is a right unit. *)Definitionconcat_p1 {A : Type} {xy : A} (p : x = y) :
p @ 1 = p
:=
match p with idpath => 1end.(** The identity is a left unit. *)Definitionconcat_1p {A : Type} {xy : A} (p : x = y) :
1 @ p = p
:=
match p with idpath => 1end.(** It's common to need to use both. *)Definitionconcat_p1_1p {A : Type} {xy : A} (p : x = y)
: p @ 1 = 1 @ p
:= concat_p1 p @ (concat_1p p)^.Definitionconcat_1p_p1 {A : Type} {xy : A} (p : x = y)
: 1 @ p = p @ 1
:= concat_1p p @ (concat_p1 p)^.(** Concatenation is associative. *)Definitionconcat_p_pp {A : Type} {xyzt : A} (p : x = y) (q : y = z) (r : z = t) :
p @ (q @ r) = (p @ q) @ r :=
match r with idpath =>
match q with idpath =>
match p with idpath => 1endendend.Definitionconcat_pp_p {A : Type} {xyzt : A} (p : x = y) (q : y = z) (r : z = t) :
(p @ q) @ r = p @ (q @ r) :=
match r with idpath =>
match q with idpath =>
match p with idpath => 1endendend.(** The left inverse law. *)Definitionconcat_pV {A : Type} {xy : A} (p : x = y) :
p @ p^ = 1
:=
match p with idpath => 1end.(** The right inverse law. *)Definitionconcat_Vp {A : Type} {xy : A} (p : x = y) :
p^ @ p = 1
:=
match p with idpath => 1end.(** Several auxiliary theorems about canceling inverses across associativity. These are somewhat redundant, following from earlier theorems. *)Definitionconcat_V_pp {A : Type} {xyz : A} (p : x = y) (q : y = z) :
p^ @ (p @ q) = q
:=
match q with idpath =>
match p with idpath => 1endend.Definitionconcat_p_Vp {A : Type} {xyz : A} (p : x = y) (q : x = z) :
p @ (p^ @ q) = q
:=
match q with idpath =>
match p with idpath => 1endend.Definitionconcat_pp_V {A : Type} {xyz : A} (p : x = y) (q : y = z) :
(p @ q) @ q^ = p
:=
match q with idpath =>
match p with idpath => 1endend.Definitionconcat_pV_p {A : Type} {xyz : A} (p : x = z) (q : y = z) :
(p @ q^) @ q = p
:=
(match q as i returnforallp, (p @ i^) @ i = p with
idpath =>
funp =>
match p with idpath => 1endend) p.(** Inverse distributes over concatenation *)Definitioninv_pp {A : Type} {xyz : A} (p : x = y) (q : y = z) :
(p @ q)^ = q^ @ p^
:=
match q with idpath =>
match p with idpath => 1endend.Definitioninv_Vp {A : Type} {xyz : A} (p : y = x) (q : y = z) :
(p^ @ q)^ = q^ @ p
:=
match q with idpath =>
match p with idpath => 1endend.
A: Type x, y, z: A p: x = y q: z = y
(p @ q^)^ = q @ p^
A: Type x, y, z: A p: x = y q: z = y
(p @ q^)^ = q @ p^
A: Type x, z: A q: z = x
(1 @ q^)^ = q @ 1^
A: Type z: A
(1 @ 1^)^ = 1 @ 1^
reflexivity.Defined.
A: Type x, y, z: A p: y = x q: z = y
(p^ @ q^)^ = q @ p
A: Type x, y, z: A p: y = x q: z = y
(p^ @ q^)^ = q @ p
A: Type y, z: A q: z = y
(1^ @ q^)^ = q @ 1
A: Type z: A
(1^ @ 1^)^ = 1 @ 1
reflexivity.Defined.(** Inverse is an involution. *)Definitioninv_V {A : Type} {xy : A} (p : x = y) :
p^^ = p
:=
match p with idpath => 1end.(** *** Theorems for moving things around in equations. *)
exact (concat_r (concat_1p _)).Defined.(* In general, the path we want to move might be arbitrarily deeply nested at the beginning of a long concatenation. Thus, instead of defining functions such as [moveL_Mp_p], we define a tactical that can repeatedly rewrite with associativity to expose it. *)Ltacwith_rassoc tac :=
repeatrewrite concat_pp_p;
tac;
(* After moving, we reassociate to the left (the canonical direction for paths). *)repeatrewrite concat_p_pp.Ltacrewrite_moveL_Mp_p := with_rassoc ltac:(apply moveL_Mp).Ltacrewrite_moveL_Vp_p := with_rassoc ltac:(apply moveL_Vp).Ltacrewrite_moveR_Mp_p := with_rassoc ltac:(apply moveR_Mp).Ltacrewrite_moveR_Vp_p := with_rassoc ltac:(apply moveR_Vp).
A: Type P: A -> Type x, y: A p: x = y u: P x v: P y
u = transport P p^ v -> transport P p u = v
A: Type P: A -> Type x, y: A p: x = y u: P x v: P y
u = transport P p^ v -> transport P p u = v
A: Type P: A -> Type x: A u, v: P x
u = transport P 1^ v -> transport P 1 u = v
exact idmap.Defined.
A: Type P: A -> Type x, y: A p: y = x u: P x v: P y
u = transport P p v -> transport P p^ u = v
A: Type P: A -> Type x, y: A p: y = x u: P x v: P y
u = transport P p v -> transport P p^ u = v
A: Type P: A -> Type y: A u, v: P y
u = transport P 1 v -> transport P 1^ u = v
exact idmap.Defined.
A: Type P: A -> Type x, y: A p: x = y u: P x v: P y
transport P p u = v -> u = transport P p^ v
A: Type P: A -> Type x, y: A p: x = y u: P x v: P y
transport P p u = v -> u = transport P p^ v
A: Type P: A -> Type x: A u, v: P x
transport P 1 u = v -> u = transport P 1^ v
exact idmap.Defined.
A: Type P: A -> Type x, y: A p: y = x u: P x v: P y
transport P p^ u = v -> u = transport P p v
A: Type P: A -> Type x, y: A p: y = x u: P x v: P y
transport P p^ u = v -> u = transport P p v
A: Type P: A -> Type y: A u, v: P y
transport P 1^ u = v -> u = transport P 1 v
exact idmap.Defined.(* We have some coherences between those proofs. *)
A: Type P: A -> Type x, y: A p: x = y u: P x v: P y q: u = transport P p^ v
(moveR_transport_p P p u v q)^ =
moveL_transport_p P p v u q^
A: Type P: A -> Type x, y: A p: x = y u: P x v: P y q: u = transport P p^ v
(moveR_transport_p P p u v q)^ =
moveL_transport_p P p v u q^
destruct p; reflexivity.Defined.
A: Type P: A -> Type x, y: A p: y = x u: P x v: P y q: u = transport P p v
(moveR_transport_V P p u v q)^ =
moveL_transport_V P p v u q^
A: Type P: A -> Type x, y: A p: y = x u: P x v: P y q: u = transport P p v
(moveR_transport_V P p u v q)^ =
moveL_transport_V P p v u q^
destruct p; reflexivity.Defined.
A: Type P: A -> Type x, y: A p: x = y u: P x v: P y q: transport P p u = v
(moveL_transport_V P p u v q)^ =
moveR_transport_V P p v u q^
A: Type P: A -> Type x, y: A p: x = y u: P x v: P y q: transport P p u = v
(moveL_transport_V P p u v q)^ =
moveR_transport_V P p v u q^
destruct p; reflexivity.Defined.
A: Type P: A -> Type x, y: A p: y = x u: P x v: P y q: transport P p^ u = v
(moveL_transport_p P p u v q)^ =
moveR_transport_p P p v u q^
A: Type P: A -> Type x, y: A p: y = x u: P x v: P y q: transport P p^ u = v
(moveL_transport_p P p u v q)^ =
moveR_transport_p P p v u q^
destruct p; reflexivity.Defined.(** *** Functoriality of functions *)(** Here we prove that functions behave like functors between groupoids, and that [ap] itself is functorial. *)(** Functions take identity paths to identity paths. *)Definitionap_1 {AB : Type} (x : A) (f : A -> B) :
ap f 1 = 1 :> (f x = f x)
:=
1.DefinitionapD_1 {AB} (x : A) (f : forallx : A, B x) :
apD f 1 = 1 :> (f x = f x)
:=
1.(** Functions commute with concatenation. *)Definitionap_pp {AB : Type} (f : A -> B) {xyz : A} (p : x = y) (q : y = z) :
ap f (p @ q) = (ap f p) @ (ap f q)
:=
match q with
idpath =>
match p with idpath => 1endend.
A, B: Type f: A -> B w: B x, y, z: A r: w = f x p: x = y q: y = z
r @ ap f (p @ q) = (r @ ap f p) @ ap f q
A, B: Type f: A -> B w: B x, y, z: A r: w = f x p: x = y q: y = z
r @ ap f (p @ q) = (r @ ap f p) @ ap f q
A, B: Type f: A -> B w: B x: A r: w = f x
r @ ap f (1 @ 1) = (r @ ap f 1) @ ap f 1
A, B: Type f: A -> B w: B x: A r: w = f x
r @ 1 = (r @ 1) @ 1
exact (concat_p_pp r 11).Defined.
A, B: Type f: A -> B x, y, z: A w: B p: x = y q: y = z r: f z = w
ap f (p @ q) @ r = ap f p @ (ap f q @ r)
A, B: Type f: A -> B x, y, z: A w: B p: x = y q: y = z r: f z = w
ap f (p @ q) @ r = ap f p @ (ap f q @ r)
A, B: Type f: A -> B x: A w: B r: f x = w
ap f (1 @ 1) @ r = ap f 1 @ (ap f 1 @ r)
A, B: Type f: A -> B x: A w: B r: f x = w
1 @ r = 1 @ (1 @ r)
exact (concat_pp_p 11 r).Defined.(** Functions commute with path inverses. *)Definitioninverse_ap {AB : Type} (f : A -> B) {xy : A} (p : x = y) :
(ap f p)^ = ap f (p^)
:=
match p with idpath => 1end.Definitionap_V {AB : Type} (f : A -> B) {xy : A} (p : x = y) :
ap f (p^) = (ap f p)^
:=
match p with idpath => 1end.(** [ap] itself is functorial in the first argument. *)Definitionap_idmap {A : Type} {xy : A} (p : x = y) :
ap idmap p = p
:=
match p with idpath => 1end.Definitionap_compose {ABC : Type} (f : A -> B) (g : B -> C) {xy : A} (p : x = y) :
ap (g o f) p = ap g (ap f p)
:=
match p with idpath => 1end.(** Sometimes we don't have the actual function [compose]. *)Definitionap_compose' {ABC : Type} (f : A -> B) (g : B -> C) {xy : A} (p : x = y) :
ap (funa => g (f a)) p = ap g (ap f p)
:=
match p with idpath => 1end.(** The action of constant maps. *)Definitionap_const {AB : Type} {xy : A} (p : x = y) (z : B) :
ap (fun_ => z) p = 1
:=
match p with idpath => idpath end.(** Naturality of [ap]. *)Definitionconcat_Ap {AB : Type} {fg : A -> B} (p : forallx, f x = g x) {xy : A} (q : x = y) :
(ap f q) @ (p y) = (p x) @ (ap g q)
:=
match q with
| idpath => concat_1p_p1 _
end.(** A useful variant of [concat_Ap]. *)
A, B: Type f, g: A -> B p: forallx : A, f x = g x x, y: A q: x = y
ap f q = (p x @ ap g q) @ (p y)^
A, B: Type f, g: A -> B p: forallx : A, f x = g x x, y: A q: x = y
ap f q = (p x @ ap g q) @ (p y)^
A, B: Type f, g: A -> B p: forallx : A, f x = g x x, y: A q: x = y
ap f q @ p y = p x @ ap g q
apply concat_Ap.Defined.(** Naturality of [ap] at identity. *)Definitionconcat_A1p {A : Type} {f : A -> A} (p : forallx, f x = x) {xy : A} (q : x = y) :
(ap f q) @ (p y) = (p x) @ q
:=
match q with
| idpath => concat_1p_p1 _
end.(** The corresponding variant of [concat_A1p]. *)
A: Type f: A -> A p: forallx : A, f x = x x, y: A q: x = y
ap f q = (p x @ q) @ (p y)^
A: Type f: A -> A p: forallx : A, f x = x x, y: A q: x = y
ap f q = (p x @ q) @ (p y)^
A: Type f: A -> A p: forallx : A, f x = x x, y: A q: x = y
ap f q @ p y = p x @ q
apply concat_A1p.Defined.Definitionconcat_pA1 {A : Type} {f : A -> A} (p : forallx, x = f x) {xy : A} (q : x = y) :
(p x) @ (ap f q) = q @ (p y)
:=
match q as i in (_ = y) return (p x @ ap f i = i @ p y) with
| idpath => concat_p1_1p _
end.
A: Type B: A -> Type f, g: forallx : A, B x p: forallx : A, f x = g x x, y: A q: x = y
apD f q @ p y = ap (transport B q) (p x) @ apD g q
A: Type B: A -> Type f, g: forallx : A, B x p: forallx : A, f x = g x x, y: A q: x = y
apD f q @ p y = ap (transport B q) (p x) @ apD g q
A: Type B: A -> Type f, g: forallx : A, B x p: forallx : A, f x = g x x: A
apD f 1 @ p x = ap (transport B 1) (p x) @ apD g 1
A: Type B: A -> Type f, g: forallx : A, B x p: forallx : A, f x = g x x: A
A: Type B: A -> Type f, g: forallx : A, B x p: forallx : A, f x = g x x, y: A q: x = y
apD f q =
(ap (transport B q) (p x) @ apD g q) @ (p y)^
A: Type B: A -> Type f, g: forallx : A, B x p: forallx : A, f x = g x x, y: A q: x = y
apD f q =
(ap (transport B q) (p x) @ apD g q) @ (p y)^
apply moveL_pV, apD_natural.Defined.(** Naturality with other paths hanging around. *)
A, B: Type f, g: A -> B p: forallx : A, f x = g x x, y: A q: x = y w, z: B r: w = f x s: g y = z
(r @ ap f q) @ (p y @ s) = (r @ p x) @ (ap g q @ s)
A, B: Type f, g: A -> B p: forallx : A, f x = g x x, y: A q: x = y w, z: B r: w = f x s: g y = z
(r @ ap f q) @ (p y @ s) = (r @ p x) @ (ap g q @ s)
A, B: Type f, g: A -> B p: forallx : A, f x = g x x: A w: B r: w = f x
(r @ 1) @ (p x @ 1) = (r @ p x) @ 1
A, B: Type f, g: A -> B p: forallx : A, f x = g x x: A w: B r: w = f x
(r @ 1) @ (1 @ 1) = (r @ 1) @ 1
reflexivity.Defined.
A, B: Type f, g: A -> B p: forallx : A, f x = g x x, y: A q: x = y w: B r: w = f x
(r @ ap f q) @ p y = (r @ p x) @ ap g q
A, B: Type f, g: A -> B p: forallx : A, f x = g x x, y: A q: x = y w: B r: w = f x
(r @ ap f q) @ p y = (r @ p x) @ ap g q
A, B: Type f, g: A -> B p: forallx : A, f x = g x x: A w: B r: w = f x
(r @ 1) @ p x = (r @ p x) @ 1
A, B: Type f, g: A -> B p: forallx : A, f x = g x x: A w: B r: w = f x
(r @ 1) @ 1 = (r @ 1) @ 1
reflexivity.Defined.
A, B: Type f, g: A -> B p: forallx : A, f x = g x x, y: A q: x = y z: B s: g y = z
ap f q @ (p y @ s) = p x @ (ap g q @ s)
A, B: Type f, g: A -> B p: forallx : A, f x = g x x, y: A q: x = y z: B s: g y = z
ap f q @ (p y @ s) = p x @ (ap g q @ s)
A, B: Type f, g: A -> B p: forallx : A, f x = g x x: A
1 @ (p x @ 1) = p x @ 1
apply concat_1p.Defined.
A: Type f: A -> A p: forallx : A, f x = x x, y: A q: x = y w, z: A r: w = f x s: y = z
(r @ ap f q) @ (p y @ s) = (r @ p x) @ (q @ s)
A: Type f: A -> A p: forallx : A, f x = x x, y: A q: x = y w, z: A r: w = f x s: y = z
(r @ ap f q) @ (p y @ s) = (r @ p x) @ (q @ s)
A: Type f: A -> A p: forallx : A, f x = x x, w: A r: w = f x
(r @ 1) @ (p x @ 1) = (r @ p x) @ 1
A: Type f: A -> A p: forallx : A, f x = x x, w: A r: w = f x
(r @ 1) @ (1 @ 1) = (r @ 1) @ 1
reflexivity.Defined.
A: Type g: A -> A p: forallx : A, x = g x x, y: A q: x = y w, z: A r: w = x s: g y = z
(r @ p x) @ (ap g q @ s) = (r @ q) @ (p y @ s)
A: Type g: A -> A p: forallx : A, x = g x x, y: A q: x = y w, z: A r: w = x s: g y = z
(r @ p x) @ (ap g q @ s) = (r @ q) @ (p y @ s)
A: Type g: A -> A p: forallx : A, x = g x x, w: A r: w = x
(r @ p x) @ 1 = (r @ 1) @ (p x @ 1)
A: Type g: A -> A p: forallx : A, x = g x x, w: A r: w = x
(r @ 1) @ 1 = (r @ 1) @ (1 @ 1)
reflexivity.Defined.
A: Type f: A -> A p: forallx : A, f x = x x, y: A q: x = y w: A r: w = f x
(r @ ap f q) @ p y = (r @ p x) @ q
A: Type f: A -> A p: forallx : A, f x = x x, y: A q: x = y w: A r: w = f x
(r @ ap f q) @ p y = (r @ p x) @ q
A: Type f: A -> A p: forallx : A, f x = x x, w: A r: w = f x
(r @ 1) @ p x = (r @ p x) @ 1
A: Type f: A -> A p: forallx : A, f x = x x, w: A r: w = f x
(r @ 1) @ 1 = (r @ 1) @ 1
reflexivity.Defined.
A: Type f: A -> A p: forallx : A, f x = x x, y: A q: x = y z: A s: y = z
ap f q @ (p y @ s) = p x @ (q @ s)
A: Type f: A -> A p: forallx : A, f x = x x, y: A q: x = y z: A s: y = z
ap f q @ (p y @ s) = p x @ (q @ s)
A: Type f: A -> A p: forallx : A, f x = x x: A
1 @ (p x @ 1) = p x @ 1
apply concat_1p.Defined.
A: Type g: A -> A p: forallx : A, x = g x x, y: A q: x = y w: A r: w = x
(r @ p x) @ ap g q = (r @ q) @ p y
A: Type g: A -> A p: forallx : A, x = g x x, y: A q: x = y w: A r: w = x
(r @ p x) @ ap g q = (r @ q) @ p y
A: Type g: A -> A p: forallx : A, x = g x x, w: A r: w = x
(r @ p x) @ 1 = (r @ 1) @ p x
A: Type g: A -> A p: forallx : A, x = g x x, w: A r: w = x
(r @ 1) @ 1 = (r @ 1) @ 1
reflexivity.Defined.
A: Type g: A -> A p: forallx : A, x = g x x, y: A q: x = y z: A s: g y = z
p x @ (ap g q @ s) = q @ (p y @ s)
A: Type g: A -> A p: forallx : A, x = g x x, y: A q: x = y z: A s: g y = z
p x @ (ap g q @ s) = q @ (p y @ s)
A: Type g: A -> A p: forallx : A, x = g x x: A
p x @ 1 = 1 @ (p x @ 1)
symmetry; apply concat_1p.Defined.(** Some coherence lemmas for functoriality *)
A: Type x: A p: x = x q: p = 1
concat_1p p @ q = ap (funp' : x = x => 1 @ p') q
A: Type x: A p: x = x q: p = 1
concat_1p p @ q = ap (funp' : x = x => 1 @ p') q
A: Type x: A p: x = x q: p = 1
concat_1p p @ (q^)^ =
ap (funp' : x = x => 1 @ p') (q^)^
A: Type x: A p: x = x q: p = 1 r:= q^: 1 = p
concat_1p p @ r^ = ap (funp' : x = x => 1 @ p') r^
A: Type x: A
concat_1p 1 @ 1^ = ap (funp' : x = x => 1 @ p') 1^
reflexivity.Defined.
A: Type x: A p: x = x q: p = 1
concat_p1 p @ q = ap (funp' : x = x => p' @ 1) q
A: Type x: A p: x = x q: p = 1
concat_p1 p @ q = ap (funp' : x = x => p' @ 1) q
A: Type x: A p: x = x q: p = 1
concat_p1 p @ (q^)^ =
ap (funp' : x = x => p' @ 1) (q^)^
A: Type x: A p: x = x q: p = 1 r:= q^: 1 = p
concat_p1 p @ r^ = ap (funp' : x = x => p' @ 1) r^
A: Type x: A
concat_p1 1 @ 1^ = ap (funp' : x = x => p' @ 1) 1^
reflexivity.Defined.(** *** Action of [apD10] and [ap10] on paths. *)(** Application of paths between functions preserves the groupoid structure *)DefinitionapD10_1 {A} {B:A->Type} (f : forallx, B x) (x:A)
: apD10 (idpath f) x = 1
:= 1.
A: Type B: A -> Type f, f', f'': forallx : A, B x h: f = f' h': f' = f'' x: A
apD10 (h @ h') x = apD10 h x @ apD10 h' x
A: Type B: A -> Type f, f', f'': forallx : A, B x h: f = f' h': f' = f'' x: A
apD10 (h @ h') x = apD10 h x @ apD10 h' x
case h, h'; reflexivity.Defined.DefinitionapD10_V {A} {B:A->Type} {fg : forallx, B x} (h:f=g) (x:A)
: apD10 (h^) x = (apD10 h x)^
:= match h with idpath => 1end.Definitionap10_1 {AB} {f:A->B} (x:A) : ap10 (idpath f) x = 1
:= 1.Definitionap10_pp {AB} {ff'f'':A->B} (h:f=f') (h':f'=f'') (x:A)
: ap10 (h @ h') x = ap10 h x @ ap10 h' x
:= apD10_pp h h' x.Definitionap10_V {AB} {fg : A->B} (h : f = g) (x:A)
: ap10 (h^) x = (ap10 h x)^
:= apD10_V h x.(** [apD10] and [ap10] also behave nicely on paths produced by [ap] *)
A, B: Type C: B -> Type f: A -> B g, g': forallx : B, C x p: g = g' a: A
apD10 (ap (funh : forallx : B, C x => h oD f) p) a =
apD10 p (f a)
A, B: Type C: B -> Type f: A -> B g, g': forallx : B, C x p: g = g' a: A
apD10 (ap (funh : forallx : B, C x => h oD f) p) a =
apD10 p (f a)
destruct p; reflexivity.Defined.Definitionap10_ap_precompose {ABC} (f : A -> B) {gg' : B -> C} (p : g = g') a
: ap10 (ap (funh : B -> C => h o f) p) a = ap10 p (f a)
:= apD10_ap_precompose f p a.
A: Type B: A -> Type C: Type f: forallx : A, B x -> C g, g': forallx : A, B x p: g = g' a: A
apD10
(ap
(fun (h : forallx : A, B x) (x : A) => f x (h x))
p) a = ap (f a) (apD10 p a)
A: Type B: A -> Type C: Type f: forallx : A, B x -> C g, g': forallx : A, B x p: g = g' a: A
apD10
(ap
(fun (h : forallx : A, B x) (x : A) => f x (h x))
p) a = ap (f a) (apD10 p a)
destruct p; reflexivity.Defined.Definitionap10_ap_postcompose {ABC} (f : B -> C) {gg' : A -> B} (p : g = g') a
: ap10 (ap (funh : A -> B => f o h) p) a = ap f (ap10 p a)
:= apD10_ap_postcompose (funa => f) p a.Definitionap100 {XYZ : Type} {fg : X -> Y -> Z} (p : f = g) (x : X) (y : Y)
: f x y = g x y := (ap10 (ap10 p x) y).(** *** Transport and the groupoid structure of paths *)Definitiontransport_1 {A : Type} (P : A -> Type) {x : A} (u : P x)
: 1 # u = u
:= 1.Definitiontransport_pp {A : Type} (P : A -> Type) {xyz : A} (p : x = y) (q : y = z) (u : P x) :
p @ q # u = q # p # u :=
match q with idpath =>
match p with idpath => 1endend.Definitiontransport_pV {A : Type} (P : A -> Type) {xy : A} (p : x = y) (z : P y)
: p # p^ # z = z
:= (transport_pp P p^ p z)^
@ ap (funr => transport P r z) (concat_Vp p).Definitiontransport_Vp {A : Type} (P : A -> Type) {xy : A} (p : x = y) (z : P x)
: p^ # p # z = z
:= (transport_pp P p p^ z)^
@ ap (funr => transport P r z) (concat_pV p).(** In the future, we may expect to need some higher coherence for transport: for instance, that transport acting on the associator is trivial. *)
A: Type P: A -> Type x, y, z, w: A p: x = y q: y = z r: z = w u: P x
(ap (fune : x = w => transport P e u)
(concat_p_pp p q r) @ transport_pp P (p @ q) r u) @
ap (transport P r) (transport_pp P p q u) =
transport_pp P p (q @ r) u @
transport_pp P q r (transport P p u)
A: Type P: A -> Type x, y, z, w: A p: x = y q: y = z r: z = w u: P x
(ap (fune : x = w => transport P e u)
(concat_p_pp p q r) @ transport_pp P (p @ q) r u) @
ap (transport P r) (transport_pp P p q u) =
transport_pp P p (q @ r) u @
transport_pp P q r (transport P p u)
A: Type P: A -> Type x: A u: P x
(ap (fune : x = x => transport P e u)
(concat_p_pp 111) @ transport_pp P (1 @ 1) 1 u) @
ap (transport P 1) (transport_pp P 11 u) =
transport_pp P 1 (1 @ 1) u @
transport_pp P 11 (transport P 1 u)
A: Type P: A -> Type x: A u: P x
1 = 1
exact1.Defined.(* Here are other coherence lemmas for transport. *)
A: Type P: A -> Type x, y: A p: x = y z: P x
transport_pV P p (transport P p z) =
ap (transport P p) (transport_Vp P p z)
A: Type P: A -> Type x, y: A p: x = y z: P x
transport_pV P p (transport P p z) =
ap (transport P p) (transport_Vp P p z)
destruct p; reflexivity.Defined.
A: Type P: A -> Type x, y: A p: x = y z: P y
transport_Vp P p (transport P p^ z) =
ap (transport P p^) (transport_pV P p z)
A: Type P: A -> Type x, y: A p: x = y z: P y
transport_Vp P p (transport P p^ z) =
ap (transport P p^) (transport_pV P p z)
destruct p; reflexivity.Defined.
A: Type P: A -> Type x, y: A p: x = y u: P x v: P y e: transport P p u = v
ap (transport P p) (moveL_transport_V P p u v e) @
transport_pV P p v = e
A: Type P: A -> Type x, y: A p: x = y u: P x v: P y e: transport P p u = v
ap (transport P p) (moveL_transport_V P p u v e) @
transport_pV P p v = e
bydestruct e, p.Defined.
A: Type P: A -> Type x, y: A p: x = y u: P x
moveL_transport_V P p u (transport P p u) 1 =
(transport_Vp P p u)^
(* moveL_transport_V P p (transport P p^ v) (transport P p (transport P p^ v)) 1 *)(* = ap (transport P p^) (transport_pV P p v)^. *)
A: Type P: A -> Type x, y: A p: x = y u: P x
moveL_transport_V P p u (transport P p u) 1 =
(transport_Vp P p u)^
(* pose (u := p^ # v). *)(* assert (moveL_transport_V P p u (p # u) 1 = (transport_Vp P p u)^). *)destruct p; reflexivity.(* subst u. rewrite X. *)Defined.(** Occasionally the induction principles for the identity type show up explicitly; these let us turn them into transport. *)Definitionpaths_rect_transport {A : Type} (P : A -> Type) {xy : A}
(p : x = y) (u : P x)
: paths_rect A x (funa_ => P a) u y p = transport P p u
:= 1.Definitionpaths_ind_transport {A : Type} (P : A -> Type) {xy : A}
(p : x = y) (u : P x)
: paths_ind x (funa_ => P a) u y p = transport P p u
:= 1.
A: Type P: A -> Type x, y: A p: x = y u: P y
paths_ind_r y (fun (b : A) (_ : b = y) => P b) u x p =
transport P p^ u
A: Type P: A -> Type x, y: A p: x = y u: P y
paths_ind_r y (fun (b : A) (_ : b = y) => P b) u x p =
transport P p^ u
bydestruct p.Defined.(** ** [ap11] *)
A, B: Type f, g: A -> B h: f = g x, y: A p: x = y
ap11 h p = ap10 h x @ ap g p
A, B: Type f, g: A -> B h: f = g x, y: A p: x = y
ap11 h p = ap10 h x @ ap g p
by path_induction.Defined.(** Dependent transport in doubly dependent types and more. *)(** Singly dependent transport over doubly dependent types. *)DefinitiontransportD {A : Type} (B : A -> Type) (C : foralla:A, B a -> Type)
{x1x2 : A} (p : x1 = x2) (y : B x1) (z : C x1 y)
: C x2 (p # y)
:=
match p with idpath => z end.(** Singly dependent transport over doubly dependent types of 2 variables. *)DefinitiontransportD2 {A : Type} (BC : A -> Type) (D : foralla:A, B a -> C a -> Type)
{x1x2 : A} (p : x1 = x2) (y : B x1) (z : C x1) (w : D x1 y z)
: D x2 (p # y) (p # z)
:=
match p with idpath => w end.(** Doubly dependent transport over doubly dependent types. *)DefinitiontransportDD {A : Type} (B : A -> Type) (C : foralla : A, B a -> Type)
{a1a2 : A} (pA : a1 = a2)
{b1 : B a1} {b2 : B a2} (pB : transport B pA b1 = b2)
(c1 : C a1 b1)
: C a2 b2
:= transport (C a2) pB (transportD B C pA b1 c1).(** *** [ap] for curried two variable functions *)
A, B, C: Type f: A -> B -> C x, x': A y, y': B p: x = x' q: y = y'
f x y = f x' y'
A, B, C: Type f: A -> B -> C x, x': A y, y': B p: x = x' q: y = y'
f x y = f x' y'
A, B, C: Type f: A -> B -> C x: A y, y': B q: y = y'
f x y = f x y'
A, B, C: Type f: A -> B -> C x: A y, y': B q: y = y'
y = y'
exact q.Defined.
A, B, C: Type f: A -> B -> C x, x': A y, y': B p: x = x' q: y = y'
ap011 f p^ q^ = (ap011 f p q)^
A, B, C: Type f: A -> B -> C x, x': A y, y': B p: x = x' q: y = y'
ap011 f p^ q^ = (ap011 f p q)^
A, B, C: Type f: A -> B -> C x: A y, y': B q: y = y'
ap011 f 1^ q^ = (ap011 f 1 q)^
apply ap_V.Defined.
A, B, C: Type f: A -> B -> C x, x', x'': A y, y', y'': B p: x = x' p': x' = x'' q: y = y' q': y' = y''
ap011 f (p @ p') (q @ q') =
ap011 f p q @ ap011 f p' q'
A, B, C: Type f: A -> B -> C x, x', x'': A y, y', y'': B p: x = x' p': x' = x'' q: y = y' q': y' = y''
ap011 f (p @ p') (q @ q') =
ap011 f p q @ ap011 f p' q'
A, B, C: Type f: A -> B -> C x: A y, y', y'': B q: y = y' q': y' = y''
ap011 f (1 @ 1) (q @ q') = ap011 f 1 q @ ap011 f 1 q'
apply ap_pp.Defined.
A, B, C, D: Type f: A -> B -> C g: C -> D x, x': A y, y': B p: x = x' q: y = y'
ap011 (fun (x : A) (y : B) => g (f x y)) p q =
ap g (ap011 f p q)
A, B, C, D: Type f: A -> B -> C g: C -> D x, x': A y, y': B p: x = x' q: y = y'
ap011 (fun (x : A) (y : B) => g (f x y)) p q =
ap g (ap011 f p q)
A, B, C, D: Type f: A -> B -> C g: C -> D x: A y, y': B q: y = y'
ap (funy : B => g (f x y)) q = ap g (ap (f x) q)
apply ap_compose.Defined.
A, B, C, D, E: Type f: A -> B -> C g: D -> A h: E -> B x, x': D y, y': E p: x = x' q: y = y'
ap011 (fun (x : D) (y : E) => f (g x) (h y)) p q =
ap011 f (ap g p) (ap h q)
A, B, C, D, E: Type f: A -> B -> C g: D -> A h: E -> B x, x': D y, y': E p: x = x' q: y = y'
ap011 (fun (x : D) (y : E) => f (g x) (h y)) p q =
ap011 f (ap g p) (ap h q)
A, B, C, D, E: Type f: A -> B -> C g: D -> A h: E -> B x: D y, y': E q: y = y'
ap (funy : E => f (g x) (h y)) q =
ap (f (g x)) (ap h q)
apply ap_compose.Defined.
A, B, C: Type f: A -> B -> C x, x': A y, y': B p: x = x' q: y = y'
ap011 f p q =
ap (funx : A => f x y) p @ ap (funy : B => f x' y) q
A, B, C: Type f: A -> B -> C x, x': A y, y': B p: x = x' q: y = y'
ap011 f p q =
ap (funx : A => f x y) p @ ap (funy : B => f x' y) q
A, B, C: Type f: A -> B -> C x: A y, y': B q: y = y'
ap011 f 1 q =
ap (funx : A => f x y) 1 @ ap (funy : B => f x y) q
A, B, C: Type f: A -> B -> C x: A y, y': B q: y = y'
ap (funx : A => f x y) 1 @ ap (funy : B => f x y) q =
ap011 f 1 q
apply concat_1p.Defined.(** It would be nice to have a consistent way to name the different ways in which this can be dependent. The following are a sort of half-hearted attempt. *)
A: Type B: A -> Type C: Type f: foralla : A, B a -> C x, x': A p: x = x' y: B x y': B x' q: transport B p y = y'
f x y = f x' y'
A: Type B: A -> Type C: Type f: foralla : A, B a -> C x, x': A p: x = x' y: B x y': B x' q: transport B p y = y'
f x y = f x' y'
destruct p, q; reflexivity.Defined.
A: Type B, C: A -> Type f: foralla : A, B a -> C a x, x': A p: x = x' y: B x y': B x' q: transport B p y = y'
transport C p (f x y) = f x' y'
A: Type B, C: A -> Type f: foralla : A, B a -> C a x, x': A p: x = x' y: B x y': B x' q: transport B p y = y'
transport C p (f x y) = f x' y'
destruct p, q; reflexivity.Defined.
A: Type B: A -> Type C: forallx : A, B x -> Type f: forall (a : A) (b : B a), C a b x, x': A p: x = x' y: B x y': B x' q: transport B p y = y'
transport (C x') q (transportD B C p y (f x y)) =
f x' y'
A: Type B: A -> Type C: forallx : A, B x -> Type f: forall (a : A) (b : B a), C a b x, x': A p: x = x' y: B x y': B x' q: transport B p y = y'
transport (C x') q (transportD B C p y (f x y)) =
f x' y'
destruct p, q; reflexivity.Defined.(** Transporting along two 1-dimensional paths *)Definitiontransport011 {AB} (P : A -> B -> Type) {x1x2 : A} {y1y2 : B}
(p : x1 = x2) (q : y1 = y2) (z : P x1 y1)
: P x2 y2
:= transport (funx => P x y2) p (transport (funy => P x1 y) q z).
A, B: Type P: A -> B -> Type x1, x2, x3: A y1, y2, y3: B p1: x1 = x2 p2: x2 = x3 q1: y1 = y2 q2: y2 = y3 z: P x1 y1
transport011 P (p1 @ p2) (q1 @ q2) z =
transport011 P p2 q2 (transport011 P p1 q1 z)
A, B: Type P: A -> B -> Type x1, x2, x3: A y1, y2, y3: B p1: x1 = x2 p2: x2 = x3 q1: y1 = y2 q2: y2 = y3 z: P x1 y1
transport011 P (p1 @ p2) (q1 @ q2) z =
transport011 P p2 q2 (transport011 P p1 q1 z)
destruct p1, p2, q1, q2; reflexivity.Defined.
A, B, A', B': Type P: A -> B -> Type f: A' -> A g: B' -> B x1, x2: A' y1, y2: B' p: x1 = x2 q: y1 = y2 z: P (f x1) (g y1)
transport011 (fun (x : A') (y : B') => P (f x) (g y))
p q z = transport011 P (ap f p) (ap g q) z
A, B, A', B': Type P: A -> B -> Type f: A' -> A g: B' -> B x1, x2: A' y1, y2: B' p: x1 = x2 q: y1 = y2 z: P (f x1) (g y1)
transport011 (fun (x : A') (y : B') => P (f x) (g y))
p q z = transport011 P (ap f p) (ap g q) z
destruct p, q; reflexivity.Defined.(** Naturality of [transport011]. *)
A, B: Type P, Q: A -> B -> Type a1, a2: A b1, b2: B p: a1 = a2 q: b1 = b2 f: forall (a : A) (b : B), P a b -> Q a b x: P a1 b1
f a2 b2 (transport011 P p q x) =
transport011 Q p q (f a1 b1 x)
A, B: Type P, Q: A -> B -> Type a1, a2: A b1, b2: B p: a1 = a2 q: b1 = b2 f: forall (a : A) (b : B), P a b -> Q a b x: P a1 b1
f a2 b2 (transport011 P p q x) =
transport011 Q p q (f a1 b1 x)
destruct p, q; reflexivity.Defined.(** Transporting along higher-dimensional paths *)Definitiontransport2 {A : Type} (P : A -> Type) {xy : A} {pq : x = y}
(r : p = q) (z : P x)
: p # z = q # z
:= ap (funp' => p' # z) r.(** An alternative definition. *)Definitiontransport2_is_ap10 {A : Type} (Q : A -> Type) {xy : A} {pq : x = y}
(r : p = q) (z : Q x)
: transport2 Q r z = ap10 (ap (transport Q) r) z
:= match r with idpath => 1end.
A: Type P: A -> Type x, y: A p1, p2, p3: x = y r1: p1 = p2 r2: p2 = p3 z: P x
transport2 P (r1 @ r2) z =
transport2 P r1 z @ transport2 P r2 z
A: Type P: A -> Type x, y: A p1, p2, p3: x = y r1: p1 = p2 r2: p2 = p3 z: P x
transport2 P (r1 @ r2) z =
transport2 P r1 z @ transport2 P r2 z
destruct r1, r2; reflexivity.Defined.Definitiontransport2_V {A : Type} (Q : A -> Type) {xy : A} {pq : x = y}
(r : p = q) (z : Q x)
: transport2 Q (r^) z = (transport2 Q r z)^
:= match r with idpath => 1end.Definitionconcat_AT {A : Type} (P : A -> Type) {xy : A} {pq : x = y}
{zw : P x} (r : p = q) (s : z = w)
: ap (transport P p) s @ transport2 P r w
= transport2 P r z @ ap (transport P q) s
:= match r with idpath => (concat_p1_1p _) end.
A: Type P: A -> Type a, b: A p: a = b x: P a
transport_pp P p 1 x = transport2 P (concat_p1 p) x
A: Type P: A -> Type a, b: A p: a = b x: P a
transport_pp P p 1 x = transport2 P (concat_p1 p) x
byinduction p.Defined.(* Naturality of transport. TODO: What should this be called? [transport_postcompose]? *)
A: Type P, Q: A -> Type x, y: A p: x = y f: forallx : A, P x -> Q x z: P x
f y (transport P p z) = transport Q p (f x z)
A: Type P, Q: A -> Type x, y: A p: x = y f: forallx : A, P x -> Q x z: P x
f y (transport P p z) = transport Q p (f x z)
byinduction p.Defined.
A: Type B: A -> Type C1, C2: foralla : A, B a -> Type f: forall (a : A) (b : B a), C1 a b -> C2 a b x1, x2: A p: x1 = x2 y: B x1 z: C1 x1 y
f x2 (transport B p y) (transportD B C1 p y z) =
transportD B C2 p y (f x1 y z)
A: Type B: A -> Type C1, C2: foralla : A, B a -> Type f: forall (a : A) (b : B a), C1 a b -> C2 a b x1, x2: A p: x1 = x2 y: B x1 z: C1 x1 y
f x2 (transport B p y) (transportD B C1 p y z) =
transportD B C2 p y (f x1 y z)
byinduction p.Defined.
A: Type B, C: A -> Type D1, D2: foralla : A, B a -> C a -> Type f: forall (a : A) (b : B a) (c : C a),
D1 a b c -> D2 a b c x1, x2: A p: x1 = x2 y: B x1 z: C x1 w: D1 x1 y z
f x2 (transport B p y) (transport C p z)
(transportD2 B C D1 p y z w) =
transportD2 B C D2 p y z (f x1 y z w)
A: Type B, C: A -> Type D1, D2: foralla : A, B a -> C a -> Type f: forall (a : A) (b : B a) (c : C a),
D1 a b c -> D2 a b c x1, x2: A p: x1 = x2 y: B x1 z: C x1 w: D1 x1 y z
f x2 (transport B p y) (transport C p z)
(transportD2 B C D1 p y z w) =
transportD2 B C D2 p y z (f x1 y z w)
byinduction p.Defined.(* TODO: What should this be called? *)
X: Type Y: X -> Type x1, x2: X p: x1 = x2 y1, y2: Y x2 q: y1 = y2
ap (transport Y p) (ap (transport Y p^) q) =
(transport_pV Y p y1 @ q) @ (transport_pV Y p y2)^
X: Type Y: X -> Type x1, x2: X p: x1 = x2 y1, y2: Y x2 q: y1 = y2
ap (transport Y p) (ap (transport Y p^) q) =
(transport_pV Y p y1 @ q) @ (transport_pV Y p y2)^
destruct p, q; reflexivity.Defined.(* TODO: And this? *)
X: Type P: X -> Type f: forallx : X, P x x1, x2: X p: x1 = x2
ap (transport P p) (apD f p^) @ apD f p =
transport_pV P p (f x2)
X: Type P: X -> Type f: forallx : X, P x x1, x2: X p: x1 = x2
ap (transport P p) (apD f p^) @ apD f p =
transport_pV P p (f x2)
destruct p; reflexivity.Defined.
A: Type P: A -> Type f: forallx : A, P x x, y, z: A p: x = y q: y = z
apD f (p @ q) =
(transport_pp P p q (f x) @
ap (transport P q) (apD f p)) @ apD f q
A: Type P: A -> Type f: forallx : A, P x x, y, z: A p: x = y q: y = z
apD f (p @ q) =
(transport_pp P p q (f x) @
ap (transport P q) (apD f p)) @ apD f q
destruct p, q; reflexivity.Defined.
A: Type P: A -> Type f: forallx : A, P x x, y: A p: x = y
apD f p^ =
moveR_transport_V P p (f y) (f x) (apD f p)^
A: Type P: A -> Type f: forallx : A, P x x, y: A p: x = y
apD f p^ =
moveR_transport_V P p (f y) (f x) (apD f p)^
destruct p; reflexivity.Defined.(** *** Transporting in particular fibrations. *)(** One frequently needs lemmas showing that transport in a certain dependent type is equal to some more explicitly defined operation, defined according to the structure of that dependent type. For most dependent types, we prove these lemmas in the appropriate file in the types/ subdirectory. Here we consider only the most basic cases. *)(** Transporting in a constant fibration. *)
A, B: Type x1, x2: A p: x1 = x2 y: B
transport (fun_ : A => B) p y = y
A, B: Type x1, x2: A p: x1 = x2 y: B
transport (fun_ : A => B) p y = y
A, B: Type x1: A y: B
transport (fun_ : A => B) 1 y = y
exact1.Defined.Definitiontransport2_const {AB : Type} {x1x2 : A} {pq : x1 = x2}
(r : p = q) (y : B)
: transport_const p y = transport2 (fun_ => B) r y @ transport_const q y
:= match r with idpath => (concat_1p _)^ end.
A: Type B: A -> Type C: Type x1, x2: A p: x1 = x2 y: B x1 z: C
transportD B (fun (a : A) (_ : B a) => C) p y z = z
A: Type B: A -> Type C: Type x1, x2: A p: x1 = x2 y: B x1 z: C
transportD B (fun (a : A) (_ : B a) => C) p y z = z
bydestruct p.Defined.
A, B: Type C: A -> B -> Type x1, x2: A p: x1 = x2 y: B z: C x1 y
transportD (fun_ : A => B) C p y z =
transport
(funx : A => C x (transport (fun_ : A => B) p y))
p (transport (C x1) (transport_const p y)^ z)
A, B: Type C: A -> B -> Type x1, x2: A p: x1 = x2 y: B z: C x1 y
transportD (fun_ : A => B) C p y z =
transport
(funx : A => C x (transport (fun_ : A => B) p y))
p (transport (C x1) (transport_const p y)^ z)
bydestruct p.Defined.
A: Type B: A -> Type C: Type a1, a2: A pA: a1 = a2 b1: B a1 b2: B a2 pB: transport B pA b1 = b2 c1: C
transportDD B (fun (a : A) (_ : B a) => C) pA pB c1 =
c1
A: Type B: A -> Type C: Type a1, a2: A pA: a1 = a2 b1: B a1 b2: B a2 pB: transport B pA b1 = b2 c1: C
transportDD B (fun (a : A) (_ : B a) => C) pA pB c1 =
c1
bydestruct pB, pA.Defined.(** Transporting in a pulled back fibration. *)
A, B: Type x, y: A P: B -> Type f: A -> B p: x = y z: P (f x)
transport (funx : A => P (f x)) p z =
transport P (ap f p) z
A, B: Type x, y: A P: B -> Type f: A -> B p: x = y z: P (f x)
transport (funx : A => P (f x)) p z =
transport P (ap f p) z
destruct p; reflexivity.Defined.
A, A': Type B: A' -> Type x, x': A C: forallx : A', B x -> Type f: A -> A' p: x = x' y: B (f x) z: C (f x) y
transportD (B o f) (C oD f) p y z =
transport (C (f x')) (transport_compose B f p y)^
(transportD B C (ap f p) y z)
A, A': Type B: A' -> Type x, x': A C: forallx : A', B x -> Type f: A -> A' p: x = x' y: B (f x) z: C (f x) y
transportD (B o f) (C oD f) p y z =
transport (C (f x')) (transport_compose B f p y)^
(transportD B C (ap f p) y z)
destruct p; reflexivity.Defined.(* TODO: Is there a lemma like [transportD_compose], but for [apD], which subsumes this? *)
A: Type B: A -> Type f: forallx : A, B x C: forallx : A, B x -> Type x1, x2: A p: x1 = x2 z: C x1 (f x1)
transport (C x2) (apD f p) (transportD B C p (f x1) z) =
transport (funx : A => C x (f x)) p z
A: Type B: A -> Type f: forallx : A, B x C: forallx : A, B x -> Type x1, x2: A p: x1 = x2 z: C x1 (f x1)
transport (C x2) (apD f p) (transportD B C p (f x1) z) =
transport (funx : A => C x (f x)) p z
destruct p; reflexivity.Defined.
A, B, C: Type f: A -> B g, g': B -> C p: g = g'
transport (funh : B -> C => g o f = h o f) p 1 =
ap (funh : B -> C => h o f) p
A, B, C: Type f: A -> B g, g': B -> C p: g = g'
transport (funh : B -> C => g o f = h o f) p 1 =
ap (funh : B -> C => h o f) p
destruct p; reflexivity.Defined.(** A special case of [transport_compose] which seems to come up a lot. *)Definitiontransport_idmap_ap {A} (P : A -> Type) {xy : A} (p : x = y) (u : P x)
: transport P p u = transport idmap (ap P p) u
:= match p with idpath => idpath end.(** A combination of [transport_compose] with [transport2]. *)Definitiontransport_compose_path_ap {XY : Type} (P : Y -> Type) (g : X -> Y)
{x0x1 : X} {p : x0 = x1} {r : g x0 = g x1} (s : ap g p = r)
(z : P (g x0))
: transport (P o g) p z = transport P r z
:= transport_compose P g p z @ transport2 P s z.(** Sometimes, it's useful to have the goal be in terms of [ap], so we can use lemmas about [ap]. However, we can't just [rewrite !transport_idmap_ap], as that's likely to loop. So, instead, we provide a tactic [transport_to_ap], that replaces all [transport P p u] with [transport idmap (ap P p) u] for non-[idmap] [P]. *)Ltactransport_to_ap :=
repeatmatch goal with
| [ |- context[transport ?P?p?u] ]
=> match P with
| idmap => fail1(* we don't want to turn [transport idmap (ap _ _)] into [transport idmap (ap idmap (ap _ _))] *)
| _ => idtacend;
progressrewrite (transport_idmap_ap P p u)
end.(** Transporting in a fibration dependent on two independent types commutes. *)
A, B: Type C: A -> B -> Type x1, x2: A p: x1 = x2 y1, y2: B q: y1 = y2 c: C x1 y1
transport (C x2) q
(transport (funx : A => C x y1) p c) =
transport (funx : A => C x y2) p
(transport (C x1) q c)
A, B: Type C: A -> B -> Type x1, x2: A p: x1 = x2 y1, y2: B q: y1 = y2 c: C x1 y1
transport (C x2) q
(transport (funx : A => C x y1) p c) =
transport (funx : A => C x y2) p
(transport (C x1) q c)
destruct p, q; reflexivity.Defined.(** *** The behavior of [ap] and [apD]. *)(** In a constant fibration, [apD] reduces to [ap], modulo [transport_const]. *)
A, B: Type x, y: A f: A -> B p: x = y
apD f p = transport_const p (f x) @ ap f p
A, B: Type x, y: A f: A -> B p: x = y
apD f p = transport_const p (f x) @ ap f p
destruct p; reflexivity.Defined.
A, A': Type B: A' -> Type g: A -> A' f: foralla : A', B a x, y: A p: x = y
apD (f o g) p =
transport_compose B g p (f (g x)) @ apD f (ap g p)
A, A': Type B: A' -> Type g: A -> A' f: foralla : A', B a x, y: A p: x = y
apD (f o g) p =
transport_compose B g p (f (g x)) @ apD f (ap g p)
bydestruct p.Defined.
A, A': Type B: A' -> Type g: A -> A' f: foralla : A', B a x, y: A p: x = y
apD f (ap g p) =
(transport_compose B g p (f (g x)))^ @ apD (f o g) p
A, A': Type B: A' -> Type g: A -> A' f: foralla : A', B a x, y: A p: x = y
apD f (ap g p) =
(transport_compose B g p (f (g x)))^ @ apD (f o g) p
bydestruct p.Defined.(** ** The 2-dimensional groupoid structure *)(** Horizontal composition of 2-dimensional paths. *)Definitionconcat2 {A} {xyz : A} {pp' : x = y} {qq' : y = z} (h : p = p') (h' : q = q')
: p @ q = p' @ q'
:= match h, h' with idpath, idpath => 1end.Notation"p @@ q" := (concat2 p q)%path : path_scope.Arguments concat2 : simpl nomatch.
A, B: Type x', y', z': B f: A -> x' = y' g: A -> y' = z' x, y: A p: x = y
ap f p @@ ap g p = ap (funu : A => f u @ g u) p
A, B: Type x', y', z': B f: A -> x' = y' g: A -> y' = z' x, y: A p: x = y
ap f p @@ ap g p = ap (funu : A => f u @ g u) p
by path_induction.Defined.(** 2-dimensional path inversion *)Definitioninverse2 {A : Type} {xy : A} {pq : x = y} (h : p = q)
: p^ = q^
:= ap inverse h.(** Two common combinations of [ap_pp] and [ap_V]. *)Definitionap_pV {AB : Type} (f : A -> B) {a0a1a0' : A} (p : a0 = a1) (q : a0' = a1)
: ap f (p @ q^) = ap f p @ (ap f q)^
:= ap_pp f p q^ @ (1 @@ ap_V f q).Definitionap_Vp {AB : Type} (f : A -> B) {a0a1a1' : A} (p : a0 = a1) (q : a0 = a1')
: ap f (p^ @ q) = (ap f p)^ @ ap f q
:= ap_pp f p^ q @ (ap_V f p @@ 1).(** Some higher coherences *)
A, B: Type f: A -> B a, b: A p: a = b
ap_pp f p 1 @ concat_p1 (ap f p) =
ap (ap f) (concat_p1 p)
A, B: Type f: A -> B a, b: A p: a = b
ap_pp f p 1 @ concat_p1 (ap f p) =
ap (ap f) (concat_p1 p)
destruct p; reflexivity.Defined.
A, B: Type f: A -> B a, b: A p: a = b
ap_pp f 1 p @ concat_1p (ap f p) =
ap (ap f) (concat_1p p)
A, B: Type f: A -> B a, b: A p: a = b
ap_pp f 1 p @ concat_1p (ap f p) =
ap (ap f) (concat_1p p)
destruct p; reflexivity.Defined.
A, B: Type f: A -> B x, y: A p: x = y
ap_pV f p p @ concat_pV (ap f p) =
ap (ap f) (concat_pV p)
A, B: Type f: A -> B x, y: A p: x = y
ap_pV f p p @ concat_pV (ap f p) =
ap (ap f) (concat_pV p)
destruct p; reflexivity.Defined.
A, B: Type f: A -> B x, y: A p: x = y
ap_Vp f p p @ concat_Vp (ap f p) =
ap (ap f) (concat_Vp p)
A, B: Type f: A -> B x, y: A p: x = y
ap_Vp f p p @ concat_Vp (ap f p) =
ap (ap f) (concat_Vp p)
destruct p; reflexivity.Defined.
A: Type x, y: A p, q: x = y r: p = q
(r @@ inverse2 r) @ concat_pV q = concat_pV p
A: Type x, y: A p, q: x = y r: p = q
(r @@ inverse2 r) @ concat_pV q = concat_pV p
destruct r, p; reflexivity.Defined.
A: Type x, y: A p, q: x = y r: p = q
(inverse2 r @@ r) @ concat_Vp q = concat_Vp p
A: Type x, y: A p, q: x = y r: p = q
(inverse2 r @@ r) @ concat_Vp q = concat_Vp p
destruct r, p; reflexivity.Defined.(** Often [ap_pV_concat_pV] is combined with [concat_pV_inverse2] using a beta rule for [ap f p]. This and several above are best read from right-to-left, and the name here reflects the right-hand-side. *)Definitionap_ap_concat_pV {AB} (f : A -> B) {xy : A} (p : x = y)
(q : f x = f y) (r : ap f p = q)
: ap_pV f p p @ ((r @@ inverse2 r) @ concat_pV q) = ap (ap f) (concat_pV p)
:= (1 @@ concat_pV_inverse2 _ q r) @ ap_pV_concat_pV f p.Definitionap_ap_concat_Vp {AB} (f : A -> B) {xy : A} (p : x = y)
(q : f x = f y) (r : ap f p = q)
: ap_Vp f p p @ ((inverse2 r @@ r) @ concat_Vp q) = ap (ap f) (concat_Vp p)
:= (1 @@ concat_Vp_inverse2 _ q r) @ ap_Vp_concat_Vp f p.(** *** Whiskering *)DefinitionwhiskerL {A : Type} {xyz : A} (p : x = y)
{qr : y = z} (h : q = r) : p @ q = p @ r
:= 1 @@ h.DefinitionwhiskerR {A : Type} {xyz : A} {pq : x = y}
(h : p = q) (r : y = z) : p @ r = q @ r
:= h @@ 1.(** *** Unwhiskering, a.k.a. cancelling. *)DefinitioncancelL {A} {xyz : A} (p : x = y) (qr : y = z)
: (p @ q = p @ r) -> (q = r)
:= funh => (concat_V_pp p q)^ @ whiskerL p^ h @ (concat_V_pp p r).DefinitioncancelR {A} {xyz : A} (pq : x = y) (r : y = z)
: (p @ r = q @ r) -> (p = q)
:= funh => (concat_pp_V p r)^ @ whiskerR h r^ @ (concat_pp_V q r).(** Whiskering and identity paths. *)DefinitionwhiskerR_p1 {A : Type} {xy : A} {pq : x = y} (h : p = q) :
(concat_p1 p)^ @ whiskerR h 1 @ concat_p1 q = h
:=
match h with idpath =>
match p with idpath =>
1endend.DefinitionwhiskerR_1p {A : Type} {xyz : A} (p : x = y) (q : y = z) :
whiskerR 1 q = 1 :> (p @ q = p @ q)
:=
match q with idpath => 1end.DefinitionwhiskerL_p1 {A : Type} {xyz : A} (p : x = y) (q : y = z) :
whiskerL p 1 = 1 :> (p @ q = p @ q)
:=
match q with idpath => 1end.DefinitionwhiskerL_1p {A : Type} {xy : A} {pq : x = y} (h : p = q) :
(concat_1p p) ^ @ whiskerL 1 h @ concat_1p q = h
:=
match h with idpath =>
match p with idpath =>
1endend.
A: Type x: A q': x = x h, k: 1 = q' r: 1 @@ h = 1 @@ k
(concat_1p 1)^ @ whiskerL 1 h =
(concat_1p 1)^ @ whiskerL 1 k
A: Type x: A q': x = x h, k: 1 = q' r: 1 @@ h = 1 @@ k
whiskerL 1 h = whiskerL 1 k
exact r.Defined.
A: Type x, y, z: A p, p': x = y q, q': y = z g, h: p = p' k: q = q'
g @@ k = h @@ k -> g = h
A: Type x, y, z: A p, p': x = y q, q': y = z g, h: p = p' k: q = q'
g @@ k = h @@ k -> g = h
A: Type x, y, z: A p, p': x = y q, q': y = z g, h: p = p' k: q = q' r: g @@ k = h @@ k
g = h
A: Type x: A p': x = x g, h: 1 = p' r: g @@ 1 = h @@ 1
g = h
A: Type x: A p': x = x g, h: 1 = p' r: g @@ 1 = h @@ 1
((concat_p1 1)^ @ whiskerR g 1) @ concat_p1 p' = h
A: Type x: A p': x = x g, h: 1 = p' r: g @@ 1 = h @@ 1
((concat_p1 1)^ @ whiskerR g 1) @ concat_p1 p' =
((concat_p1 1)^ @ whiskerR h 1) @ concat_p1 p'
A: Type x: A p': x = x g, h: 1 = p' r: g @@ 1 = h @@ 1
(concat_p1 1)^ @ whiskerR g 1 =
(concat_p1 1)^ @ whiskerR h 1
A: Type x: A p': x = x g, h: 1 = p' r: g @@ 1 = h @@ 1
whiskerR g 1 = whiskerR h 1
exact r.Defined.(** Whiskering and composition *)(* The naming scheme for these is a little unclear; should [pp] refer to concatenation of the 2-paths being whiskered or of the paths we are whiskering by? *)
A: Type x, y, z: A p: x = y q, q', q'': y = z r: q = q' s: q' = q''
whiskerL p (r @ s) = whiskerL p r @ whiskerL p s
A: Type x, y, z: A p: x = y q, q', q'': y = z r: q = q' s: q' = q''
whiskerL p (r @ s) = whiskerL p r @ whiskerL p s
destruct p, r, s; reflexivity.Defined.
A: Type x, y, z: A p, p', p'': x = y q: y = z r: p = p' s: p' = p''
whiskerR (r @ s) q = whiskerR r q @ whiskerR s q
A: Type x, y, z: A p, p', p'': x = y q: y = z r: p = p' s: p' = p''
whiskerR (r @ s) q = whiskerR r q @ whiskerR s q
destruct q, r, s; reflexivity.Defined.(* For now, I've put an [L] or [R] to mark when we're referring to the whiskering paths. *)
A: Type x, y, z: A p: x = y q, q': y = z r: q = q'
((concat_V_pp p q)^ @ whiskerL p^ (whiskerL p r)) @
concat_V_pp p q' = r
A: Type x, y, z: A p: x = y q, q': y = z r: q = q'
((concat_V_pp p q)^ @ whiskerL p^ (whiskerL p r)) @
concat_V_pp p q' = r
reflexivity.Defined.(** Naturality of [concat_p_pp] in left-most argument. *)
A: Type w, x, y, z: A p, p': w = x h: p = p' q: x = y r: y = z
whiskerR h (q @ r) @ concat_p_pp p' q r =
concat_p_pp p q r @ whiskerR (whiskerR h q) r
A: Type w, x, y, z: A p, p': w = x h: p = p' q: x = y r: y = z
whiskerR h (q @ r) @ concat_p_pp p' q r =
concat_p_pp p q r @ whiskerR (whiskerR h q) r
bydestruct h, p, q, r.Defined.(** Naturality of [concat_p_pp] in middle argument. *)
A: Type w, x, y, z: A p: w = x q, q': x = y h: q = q' r: y = z
whiskerL p (whiskerR h r) @ concat_p_pp p q' r =
concat_p_pp p q r @ whiskerR (whiskerL p h) r
A: Type w, x, y, z: A p: w = x q, q': x = y h: q = q' r: y = z
whiskerL p (whiskerR h r) @ concat_p_pp p q' r =
concat_p_pp p q r @ whiskerR (whiskerL p h) r
bydestruct h, p, q, r.Defined.(** Naturality of [concat_p_pp] in right-most argument. *)
A: Type w, x, y, z: A p: w = x q: x = y r, r': y = z h: r = r'
whiskerL p (whiskerL q h) @ concat_p_pp p q r' =
concat_p_pp p q r @ whiskerL (p @ q) h
A: Type w, x, y, z: A p: w = x q: x = y r, r': y = z h: r = r'
whiskerL p (whiskerL q h) @ concat_p_pp p q r' =
concat_p_pp p q r @ whiskerL (p @ q) h
bydestruct h, p, q, r.Defined.(** The interchange law for concatenation. *)
A: Type x, y, z: A p, p', p'': x = y q, q', q'': y = z a: p = p' b: p' = p'' c: q = q' d: q' = q''
(a @@ c) @ (b @@ d) = (a @ b) @@ (c @ d)
A: Type x, y, z: A p, p', p'': x = y q, q', q'': y = z a: p = p' b: p' = p'' c: q = q' d: q' = q''
(a @@ c) @ (b @@ d) = (a @ b) @@ (c @ d)
A: Type x, y, z: A p, p', p'': x = y q, q', q'': y = z a: p = p' b: p' = p'' c: q = q' d: q' = q''
(a @@ c) @ (b @@ 1) = (a @ b) @@ (c @ 1)
A: Type x, y, z: A p, p', p'': x = y q, q', q'': y = z a: p = p' b: p' = p'' c: q = q' d: q' = q''
(a @@ 1) @ (b @@ 1) = (a @ b) @@ (1 @ 1)
A: Type x, y, z: A p, p', p'': x = y q, q', q'': y = z a: p = p' b: p' = p'' c: q = q' d: q' = q''
(a @@ 1) @ (1 @@ 1) = (a @ 1) @@ (1 @ 1)
A: Type x, y, z: A p, p', p'': x = y q, q', q'': y = z a: p = p' b: p' = p'' c: q = q' d: q' = q''
(1 @@ 1) @ (1 @@ 1) = (1 @ 1) @@ (1 @ 1)
reflexivity.Defined.(** The interchange law for whiskering. Special case of [concat_concat2]. *)Definitionconcat_whisker {A} {xyz : A} (pp' : x = y) (qq' : y = z) (a : p = p') (b : q = q') :
(whiskerR a q) @ (whiskerL p' b) = (whiskerL p b) @ (whiskerR a q')
:=
match b with
idpath =>
match a with idpath =>
(concat_1p _)^
endend.(** Structure corresponding to the coherence equations of a bicategory. *)(** The "pentagonator": the 3-cell witnessing the associativity pentagon. *)
A: Type v, w, x, y, z: A p: v = w q: w = x r: x = y s: y = z
(whiskerL p (concat_p_pp q r s) @
concat_p_pp p (q @ r) s) @
whiskerR (concat_p_pp p q r) s =
concat_p_pp p q (r @ s) @ concat_p_pp (p @ q) r s
A: Type v, w, x, y, z: A p: v = w q: w = x r: x = y s: y = z
(whiskerL p (concat_p_pp q r s) @
concat_p_pp p (q @ r) s) @
whiskerR (concat_p_pp p q r) s =
concat_p_pp p q (r @ s) @ concat_p_pp (p @ q) r s
reflexivity.Defined.(** The Eckmann-Hilton argument *)Definitioneckmann_hilton {A : Type} {x:A} (pq : 1 = 1 :> (x = x)) : p @ q = q @ p :=
(whiskerR_p1 p @@ whiskerL_1p q)^
@ (concat_p1 _ @@ concat_p1 _)
@ (concat_1p _ @@ concat_1p _)
@ (concat_whisker _ _ _ _ p q)
@ (concat_1p _ @@ concat_1p _)^
@ (concat_p1 _ @@ concat_p1 _)^
@ (whiskerL_1p q @@ whiskerR_p1 p).(** The action of functions on 2-dimensional paths *)Definitionap02 {AB : Type} (f:A->B) {xy:A} {pq:x=y} (r:p=q) : ap f p = ap f q
:= ap (ap f) r.Definitionap02_pp {AB} (f:A->B) {xy:A} {pp'p'':x=y} (r:p=p') (r':p'=p'')
: ap02 f (r @ r') = ap02 f r @ ap02 f r'
:= ap_pp (ap f) r r'.
A, B: Type f: A -> B x, y, z: A p, p': x = y q, q': y = z r: p = p' s: q = q'
ap02 f (r @@ s) =
(ap_pp f p q @ (ap02 f r @@ ap02 f s)) @
(ap_pp f p' q')^
A, B: Type f: A -> B x, y, z: A p, p': x = y q, q': y = z r: p = p' s: q = q'
ap02 f (r @@ s) =
(ap_pp f p q @ (ap02 f r @@ ap02 f s)) @
(ap_pp f p' q')^
A, B: Type f: A -> B x: A
ap02 f (1 @@ 1) =
(ap_pp f 11 @ (ap02 f 1 @@ ap02 f 1)) @
(ap_pp f 11)^
reflexivity.Defined.DefinitionapD02 {A : Type} {B : A -> Type} {xy : A} {pq : x = y}
(f : forallx, B x) (r : p = q)
: apD f p = transport2 B r (f x) @ apD f q
:= match r with idpath => (concat_1p _)^ end.DefinitionapD02_const {AB : Type} (f : A -> B) {xy : A} {pq : x = y} (r : p = q)
: apD02 f r = (apD_const f p)
@ (transport2_const r (f x) @@ ap02 f r)
@ (concat_p_pp _ _ _)^
@ (whiskerL (transport2 _ r (f x)) (apD_const f q)^)
:= match r with idpath =>
match p with idpath => 1endend.(* And now for a lemma whose statement is much longer than its proof. *)
A: Type B: A -> Type f: forallx : A, B x x, y: A p1, p2, p3: x = y r1: p1 = p2 r2: p2 = p3
apD02 f (r1 @ r2) =
((apD02 f r1 @
whiskerL (transport2 B r1 (f x)) (apD02 f r2)) @
concat_p_pp (transport2 B r1 (f x))
(transport2 B r2 (f x)) (apD f p3)) @
whiskerR (transport2_p2p B r1 r2 (f x))^ (apD f p3)
A: Type B: A -> Type f: forallx : A, B x x, y: A p1, p2, p3: x = y r1: p1 = p2 r2: p2 = p3
apD02 f (r1 @ r2) =
((apD02 f r1 @
whiskerL (transport2 B r1 (f x)) (apD02 f r2)) @
concat_p_pp (transport2 B r1 (f x))
(transport2 B r2 (f x)) (apD f p3)) @
whiskerR (transport2_p2p B r1 r2 (f x))^ (apD f p3)
A: Type B: A -> Type f: forallx : A, B x x, y: A p1: x = y
apD02 f (1 @ 1) =
((apD02 f 1 @
whiskerL (transport2 B 1 (f x)) (apD02 f 1)) @
concat_p_pp (transport2 B 1 (f x))
(transport2 B 1 (f x)) (apD f p1)) @
whiskerR (transport2_p2p B 11 (f x))^ (apD f p1)
A: Type B: A -> Type f: forallx : A, B x x: A
apD02 f (1 @ 1) =
((apD02 f 1 @
whiskerL (transport2 B 1 (f x)) (apD02 f 1)) @
concat_p_pp (transport2 B 1 (f x))
(transport2 B 1 (f x)) (apD f 1)) @
whiskerR (transport2_p2p B 11 (f x))^ (apD f 1)
reflexivity.Defined.
A, B, C: Type f: A -> B -> C x, x': A y, y': B p, p': x = x' r: p = p' q, q': y = y' s: q = q'
ap011 f p q = ap011 f p' q'
A, B, C: Type f: A -> B -> C x, x': A y, y': B p, p': x = x' r: p = p' q, q': y = y' s: q = q'
ap011 f p q = ap011 f p' q'
A, B, C: Type f: A -> B -> C x: A y, y': B q, q': y = y' s: q = q'
ap011 f 1 q = ap011 f 1 q'
A, B, C: Type f: A -> B -> C x: A y, y': B q, q': y = y' s: q = q'
q = q'
exact s.Defined.(** These lemmas need better names. *)
A, B: Type p, q: A = B r: q = p z: A
(ap (transport idmap q^)
(ap (funs : A = B => transport idmap s z) r) @
ap
(funs : B = A =>
transport idmap s (transport idmap p z))
(inverse2 r)) @ transport_Vp idmap p z =
transport_Vp idmap q z
A, B: Type p, q: A = B r: q = p z: A
(ap (transport idmap q^)
(ap (funs : A = B => transport idmap s z) r) @
ap
(funs : B = A =>
transport idmap s (transport idmap p z))
(inverse2 r)) @ transport_Vp idmap p z =
transport_Vp idmap q z
by path_induction.Defined.
A, B: Type p, q: A = B r: q = p z: B
(ap (transport idmap q)
(ap (funs : A = B => transport idmap s^ z) r) @
ap
(funs : A = B =>
transport idmap s (transport idmap p^ z)) r) @
transport_pV idmap p z = transport_pV idmap q z
A, B: Type p, q: A = B r: q = p z: B
(ap (transport idmap q)
(ap (funs : A = B => transport idmap s^ z) r) @
ap
(funs : A = B =>
transport idmap s (transport idmap p^ z)) r) @
transport_pV idmap p z = transport_pV idmap q z
by path_induction.Defined.(** ** Hints *)(** We declare some more [Hint Resolve] hints, now in the "hint database" [path_hints]. In general various hints (resolve, rewrite, unfold hints) can be grouped into "databases". This is necessary as sometimes different kinds of hints cannot be mixed, for example because they would cause a combinatorial explosion or rewriting cycles. A specific [Hint Resolve] database [db] can be used with [auto with db]. The hints in [path_hints] are designed to push concatenation *outwards*, eliminate identities and inverses, and associate to the left as far as possible. *)#[export]
Hint Resolve
inverse
concat_1p concat_p1 concat_p_pp
inv_pp inv_V
: path_hints.(* First try at a paths db. We want the RHS of the equation to become strictly simpler. *)#[export]
Hint Rewrite
@concat_p1
@concat_1p
@concat_p_pp (* there is a choice here !*)
@concat_pV
@concat_Vp
@concat_V_pp
@concat_p_Vp
@concat_pp_V
@concat_pV_p
(*@inv_pp*)(* I am not sure about this one *)
@inv_V
@moveR_Mp
@moveR_pM
@moveL_Mp
@moveL_pM
@moveL_1M
@moveL_M1
@moveR_M1
@moveR_1M
@ap_1
(* @ap_pp @ap_p_pp ?*)
@inverse_ap
@ap_idmap
(* @ap_compose @ap_compose'*)
@ap_const
(* Unsure about naturality of [ap], was absent in the old implementation. *)
@apD10_1
: paths.Ltachott_simpl :=
autorewrite with paths in * |- * ; auto with path_hints.