Let’s define [circle1] and [circle2] with
Inductive circle1 :=
| base1 : circle1
| loop1 : base1 ~~> base1
Inductive circle2 :=
| base2 : circle2
| loop2 : base2 ~~> base2
Prove that [circle1] and [circle2] are equivalent.
> In particular I managed to define the infinite dimensional sphere (using
> higher inductive types) and I proved its contractibility.
Ah, that’s very nice!
> NB: I’m using a slightly different (but completely equivalent) type for the
> computation rules for paths and the proof of the non-dependent computation
> rule from the dependent one is now much shorter (compare "Coq/HIT/Circle.v"
> and "Coq/Experimental/Circle.v").
Hmmm, that’s interesting! (Code excerpted below for comparison.)
Yes, it does simplify the proofs — and also, perhaps, would be better
than our older one if one did want to make this rule an actual
computation rule, since it better fits the general pattern that a
computation rule should be of the form:
(eliminator applied to intro form) → stuff
If I recall correctly, the older form in Coq/HIT/Circle.v was dimly
motivated by the idea that a computation rule should be of the form:
(stuff involving an eliminator applied to intro form) → an input of
the eliminator
which was perhaps mistaken. Comparing them like this, the former
seems to make much more sense, and like it would have a much better
chance of giving good computational properties (some kind of
normalisation, etc.).
Cheers,
–p.
====8<----
-- Guillaume’s version, from Coq/Experimental/Circle.v:
Axiom compute_loop : forall P pt lp,
map_dep (circle_rect P pt lp) loop
~~> map (transport loop) (compute_base P pt lp) @ lp @ !compute_base P pt lp.
-- Older version, from Coq/HIT/Circle.v:
Axiom compute_loop' :
forall (P : circle -> Type) (pt : P base) (lp : transport loop pt ~~> pt),
(! map (transport loop) (compute_base P pt lp)
@ (map_dep (circle_rect P pt lp) loop)
@ (compute_base P pt lp))
~~> lp.
====8<----
Thanks :-)
> > NB: I’m using a slightly different (but completely equivalent) type for the
> > computation rules for paths and the proof of the non-dependent computation
> > rule from the dependent one is now much shorter (compare "Coq/HIT/Circle.v"
> > and "Coq/Experimental/Circle.v").
>
> Hmmm, that’s interesting! (Code excerpted below for comparison.)
> Yes, it does simplify the proofs — and also, perhaps, would be better
> than our older one if one did want to make this rule an actual
> computation rule, since it better fits the general pattern that a
> computation rule should be of the form:
>
> (eliminator applied to intro form) → stuff
>
> If I recall correctly, the older form in Coq/HIT/Circle.v was dimly
> motivated by the idea that a computation rule should be of the form:
>
> (stuff involving an eliminator applied to intro form) → an input of
> the eliminator
>
> which was perhaps mistaken. Comparing them like this, the former
> seems to make much more sense, and like it would have a much better
> chance of giving good computational properties (some kind of
> normalisation, etc.).
Yes, while proving various things about higher inductive types I
noticed that it was a lot easier to use the computation rules for
paths as rules saying what [map_dep (eliminator) constructor] should
reduce to.
Also, when proving (for instance) that two HIT are equivalent, the
same pattern is used everytime:
* reduce the innermost [map] with the computation rule for paths
* push every [map] and [!] inside the concatenations
* simplify stuff depending on what you’re trying to prove
* repeat the three previous steps one time
* now try to convince Coq that the result is now obvious (for example
with [cancel_opposites], unfortunately this tactic almost never works
on big lambda terms)
In particular the two first steps really look like a normalisation process.
If I have time and if I understand how tactics work, I'll try to write
tactics to do this automatically.
There is also another pattern present everywhere: when you want to
prove something about the circle (or any other HIT), you want to find
a section of a fibration [P_something : circle -> Type]. You then need
to prove it for the points and the paths of the HIT.
For the points you just prove it as you can, but for the paths you
need to prove something of the form [transport (P := P_something) loop
x ~~> y] where [x] and [y] are instances of what you just proved for
the points and [loop] is a path constructor of the HIT.
But given that you don’t know anything about [loop], it seems that the
only way to prove it is to prove the following lemma first:
Lemma something_transp : forall u v : circle, forall p : u ~~> v,
forall q : P_something u,
transport (P := P_something) p q ~~> {result}.
"{result}" is a term of type [P_something v] and can usually easily be
found (at least if [P_something] is simple), and there is probably
even an algorithm computing it automatically from [P_something], and
the lemma is usually trivial to prove (it’s just [path_induction]
followed by [cancel_units]).
After that, you can apply [something_transp] to the special case [p :=
loop] [q := x] and try to prove that the result is equal to [y].
I noticed this when I tried to prove that there is a group structure
on the circle because there are many small results to prove and I was
always using this method (it isn’t yet on my GitHub because it’s a
mess and it’s not finished at all, but I’ll try to put it soon).
Cheers,
Guillaume
> Cheers,
> –p.
>
> ====8<----
> -- Guillaume’s version, from Coq/Experimental/Circle.v:
> Axiom compute_loop : forall P pt lp,
> map_dep (circle_rect P pt lp) loop
> ~~> map (transport loop) (compute_base P pt lp) @ lp @ !compute_base P pt lp.
>
> -- Older version, from Coq/HIT/Circle.v:
> Axiom compute_loop' :
> forall (P : circle -> Type) (pt : P base) (lp : transport loop pt ~~> pt),
> (! map (transport loop) (compute_base P pt lp)
> @ (map_dep (circle_rect P pt lp) loop)
> @ (compute_base P pt lp))
> ~~> lp.
> ====8<----
>
> --
> You received this message because you are subscribed to the Google Groups "Homotopy Type Theory" group.
> To post to this group, send email to HomotopyT...@googlegroups.com.
> To unsubscribe from this group, send email to HomotopyTypeThe...@googlegroups.com.
> For more options, visit this group at http://groups.google.com/group/HomotopyTypeTheory?hl=en.
>
I would like to understand better the developments happening in the higher inductive types. Could you write explicitly the introduction/elimination/computation rules which you think one should associate with 2-sphere?
Vladimir.
> There is also another pattern present everywhere: when you want to
> prove something about the circle (or any other HIT), you want to find
> a section of a fibration [P_something : circle -> Type]. You then need
> […] to prove the following lemma first:
>
> Lemma something_transp : forall u v : circle, forall p : u ~~> v,
> forall q : P_something u,
> transport (P := P_something) p q ~~> {result}.
>
> "{result}" is a term of type [P_something v] and can usually easily be
> found (at least if [P_something] is simple), and there is probably
> even an algorithm computing it automatically from [P_something], and
> the lemma is usually trivial to prove (it’s just [path_induction]
> followed by [cancel_units]).
Yes — I’ve found this sort of lemma coming up all the time too, not
just with higher inductive types, but for all sorts of fibrations. I
think you’re right that there should be an algorithm for it: modulo
technical differences in the setting, it should be something like a
version of the “observational equality” of Altenkirch, McBride, Oury,
Swirstra (and others?), which implements equality types and their
elimination rules as constructed types/terms using other constructors;
their clauses for implementing the elimination rule should give us
clauses for working out how transport/subst will act on constructed
fibrations.
I wonder if this could somehow be implemented as a tactic in Coq —
taking a fibration, and using an OTT-like algorithm to (partially?)
unwind what transport will look like in it. It would need some fairly
sophisticated Ltac, I think, but would be very handy indeed.
–p.
Do you think this could also tell us how to add HITs to the
"computational univalence" setting of Harper and Licata?
Mike
2011/10/6 Vladimir Voevodsky <vlad...@ias.edu>:
Inductive sphere : Type :=
| pt0 : sphere
| pt1 : sphere
| lp0 : pt0 ~~> pt1
| lp1 : pt0 ~~> pt1
| sf0 : lp0 ~~> lp1
| sf1 : lp0 ~~> lp1
(* Introduction rules *)
sphere : Type
pt0 : sphere
pt1 : sphere
lp0 : pt0 ~~> pt1
lp1 : pt0 ~~> pt1
sf0 : lp0 ~~> lp1
sf1 : lp0 ~~> lp1
(* Elimination rule *)
sphere_rect :
forall P : sphere -> Type,
forall x0 : P pt0,
forall x1 : P pt1,
forall p0 : transport P lp0 x0 ~~> x1,
forall p1 : transport P lp1 x0 ~~> x1,
forall s0 : transport (fun a => transport P a x0 ~~> x1) sf0 p0 ~~> p1,
forall s1 : transport (fun a => transport P a x0 ~~> x1) sf1 p0 ~~> p1,
(forall x : sphere, P x).
(* Computation rules for points *)
(sphere_rect P x0 x1 p0 p1 s0 s1) pt0 == x0
(sphere_rect P x0 x1 p0 p1 s0 s1) pt1 == x1
(* Computation rules for paths *)
map_dep P (sphere_rect P x0 x1 p0 p1 s0 s1) lp0 == p0
map_dep P (sphere_rect P x0 x1 p0 p1 s0 s1) lp1 == p1
(* Computation rules for 2-paths *)
map_dep (fun a => transport P a x0 ~~> x1) (map_dep P (sphere_rect P x0 x1 p0 p1 s0 s1)) sf0 == s0
map_dep (fun a => transport P a x0 ~~> x1) (map_dep P (sphere_rect P x0 x1 p0 p1 s0 s1)) sf1 == s1
(* Propositional computation rules for points *)
compute_pt0 : forall P x0 x1 p0 p1 s0 s1, (sphere_rect P x0 x1 p0 p1 s0 s1) pt0 ~~> x0
compute_pt1 : forall P x0 x1 p0 p1 s0 s1, (sphere_rect P x0 x1 p0 p1 s0 s1) pt1 ~~> x1
(* Propositional computation rules for paths *)
compute_lp0 : forall P x0 x1 p0 p1 s0 s1,
map_dep P (sphere_rect P x0 x1 p0 p1 s0 s1) lp0 ~~>
map (transport P lp0) (compute_pt0 P x0 x1 p0 p1 s0 s1)
@ p0
@ !compute_pt1 P x0 x1 p0 p1 s0 s1
compute_lp1 : forall P x0 x1 p0 p1 s0 s1,
map_dep P (sphere_rect P x0 x1 p0 p1 s0 s1) lp1 ~~>
map (transport P lp1) (compute_pt0 P x0 x1 p0 p1 s0 s1)
@ p1
@ !compute_pt1 P x0 x1 p0 p1 s0 s1
(* Propositional computation rules for 2-paths *)
compute_sf0 : forall P x0 x1 p0 p1 s0 s1,
map_dep (fun a => transport P a x0 ~~> x1)
(fun a => !map (transport P a) (compute_pt0 P x0 x1 p0 p1 s0 s1)
@ map_dep P (sphere_rect P x0 x1 p0 p1 s0 s1) a
@ compute_pt1 P x0 x1 p0 p1 s0 s1) sf0
~~> map (transport (fun a => transport P a x0 ~~> x1) sf0)
(compute_lp0' P x0 x1 p0 p1 s0 s1)
@ s0
@ !compute_lp1' P x0 x1 p0 p1 s0 s1.
compute_sf1 : forall P x0 x1 p0 p1 s0 s1,
map_dep (fun a => transport P a x0 ~~> x1)
(fun a => !map (transport P a) (compute_pt0 P x0 x1 p0 p1 s0 s1)
@ map_dep P (sphere_rect P x0 x1 p0 p1 s0 s1) a
@ compute_pt1 P x0 x1 p0 p1 s0 s1) sf1
~~> map (transport (fun a => transport P a x0 ~~> x1) sf1)
(compute_lp0' P x0 x1 p0 p1 s0 s1)
@ s1
@ !compute_lp1' P x0 x1 p0 p1 s0 s1.
Inductive suspension (A : Type) : Type :=
| north_susp : suspension A
| south_susp : suspension A
| paths_susp : A -> (north_susp ~~> south_susp).
Axiom compute_loop : forall P pt lp,
map_dep (circle_rect P pt lp) loop
~~> lp.
Yes?
So the question is, which side should the coercions go on when the
beta-rule for points is propositional?
-Dan
On Oct05, Peter LeFanu Lumsdaine wrote:
> On Mon, Oct 3, 2011 at 9:42 PM, Guillaume Brunerie
> <guillaume...@gmail.com> wrote:
>
> > In particular I managed to define the infinite dimensional sphere (using
> > higher inductive types) and I proved its contractibility.
>
> Ah, that’s very nice!
>
> > NB: I’m using a slightly different (but completely equivalent) type for the
> > computation rules for paths and the proof of the non-dependent computation
> > rule from the dependent one is now much shorter (compare "Coq/HIT/Circle.v"
> > and "Coq/Experimental/Circle.v").
>
> Hmmm, that’s interesting! (Code excerpted below for comparison.)
> Yes, it does simplify the proofs — and also, perhaps, would be better
> than our older one if one did want to make this rule an actual
> computation rule, since it better fits the general pattern that a
> computation rule should be of the form:
>
> (eliminator applied to intro form) → stuff
>
> If I recall correctly, the older form in Coq/HIT/Circle.v was dimly
> motivated by the idea that a computation rule should be of the form:
>
> (stuff involving an eliminator applied to intro form) → an input of
> the eliminator
>
> which was perhaps mistaken. Comparing them like this, the former
> seems to make much more sense, and like it would have a much better
> chance of giving good computational properties (some kind of
> normalisation, etc.).
>
> ====8<----
> -- Guillaume#s version, from Coq/Experimental/Circle.v:
Let me try to recast your comments in indexed categories terminology, as
opposed to fibrations, to see if I've understood. If I'm reading your
Coq code correctly, then the 'something_transp' lemma is expanding the
definition of the functorial action on morphisms of P_something.
Whenever you have a family of types P : A -> type, 'transport' (derived
from J) postulates an action on morphisms (paths in A). But when P is
built out of known type constructors, you know how the functorial action
is defined. For example:
x : A |- B1 x B2 type the functorial action is given by applying the
functorial action of B1 to the first component of the pair, and
the functorial action of B2 to the second component of the pair
x : A |- B1 -> B2 type the functorial action is given by
precomposing with the functorial action of B1 (on !p) and post-composing
with the functorial action of B2
x : A |- C type, x not free in C the functorial action is the identity,
because C is a constant functor
etc.
So, I agree with Peter that there should be a 'something_transp' lemma
whenever P_something is built out of known type constructors, because we
know what the functorial action of each type constructor is.
In fact, Bob Harper and I have a recent paper
(http://www.cs.cmu.edu/~drl/pubs/lh112tt/lh112tt.pdf) showing that these
equations (plus some others) are sufficient to prove a canonicity result
for a 2-dimensional type theory with a simple universe of sets
considered modulo isomorphism. 'something_transp' shows up in the
0-resp rules on pages 4 and 13 (2TT is somewhat stricter than
intensional type theory, in that we take these equations to be
equalities, rather than equivalences).
From a computational perspective, the need for the 'something_transp'
lemmas is clear: In intensional type theory,
'transport (P := P_something) p q' only computes when 'p' is
reflexivity.
But higher-dimensional types add new ways to construct paths (e.g. 'p'
might be an application of univalence), so with only the computation
rule for reflexivity, 'transport' sometimes gets stuck.
In 2TT, transport additionally computes based on the structure of P,
using the definition of the functorial action of each type constructor.
There are similar rules saying that what you call 'map' (and we call
'resp') computes based on the structure of the term being congruenced on
to both sides of the path. These rules suffice to get all transport's
and map's out of your way in a closed term, in the sense that every
closed term of type boolean is definitionally equal to either true or
false.
2TT essentially ports the constructs and equations of Hofmann and
Streicher's groupoid interpretation into the syntax of a type theory.
We thought this made a nice first step towards addressing the harder
question of the computational interpretation of the infinite-dimensional
univalence axiom.
-Dan
I don't have the rules written up in a document, but you can add, say,
the interval or the circle to 2TT fairly easily. But 2TT is
2-dimensional, and very strict, so you just take all of the beta-rules
(for points and for paths) as definitional equalities. I'm not sure
what you'd do in a weaker or higher-dimensional setting.
-Dan
> Just to check that I've understood correctly: if the beta-rule for
> circle_rect on the point were definitional, rather than propositional,
> then we could use
>
> Axiom compute_loop : forall P pt lp,
> map_dep (circle_rect P pt lp) loop
> ~~> lp.
>
> Yes?
yes