I writing a proof in coq and I'm trying to use the rewrite tactic. I wanted to include a minimal working example but there are quite a lot of things I would have to include (this proof is building on previous work of my own). Let me know if it is necessary and I can get a working example uploaded. Otherwise:
My current goal is:
1 subgoal
A : Type
a : A
h : eq_refl a = eq_refl a
______________________________________(1/1)
eq_refl (eq_refl a) * h * eq_refl (eq_refl a) = h
I have defined the notation * to be path concatenation (or just using transativity on proofs of equality). Now is where I look to apply rewrite on the lhs of the goal equality. I have a path from the term on the lhs to h * eq_refl given by ap(fun (p : eq_refl a = eq_refl a) => p * eq_refl(eq_refl a)) (pinv (refllid h))) (sorry for the notation, I'm doing HoTT. ap takes p : a = b to (ap f p) : f a = f b) for any f). I can confirm this with Check:
ap (fun (p : eq_refl = eq_refl) => p * eq_refl) (pinv (refllid h))
: eq_refl * h * eq_refl = h * eq_refl
I also made sure to check that the eq_refl s are really eq_refl (eq_refl a) by checking things with all implicit arguments printed. But, if I try
rewrite (ap(fun (p : eq_refl a = eq_refl a) => p * eq_refl(eq_refl a)) (pinv (refllid h))).
I get the error
Found no subterm matching "eq_refl * h * eq_refl" in the current goal.
But there is quite clearly a subterm of this form. I don't understand why Coq is getting snagged here.
** Edit ** I was able to (laboriously) get the proof to work by using eq_rect. But if I'm not mistaken, rewrite is based on eq_rect. Also I really don't want to have to use eq_rect each time. So I'd still love any input on what went wrong with rewrite.
Related
Given the definition:
Definition cast (a b:Type) (p:a = b) (x:a) : b :=
match p with
| eq_refl _ => x
end.
I was hoping that the following lemma would be provable:
Lemma cast_cast_is_id : forall (a b:Type) (x:a) (p:a = b) (q:b = a),
cast b a q (cast a b p x) = x.
However, I do not seem to be able to carry out a proof for this. I can destruct p successfully, but cannot destruct q after that. Replacing the lemma's statement with eq_sym p instead of arbitrary q does not help me either it seems.
I fear I have unwittingly stumbled into some subtle point of HoTT.
Can anyone prove this lemma or is it known to be unprovable without further axioms?
I am not completely sure, but it seems to me that what you are trying to prove is no different from forall a (p:a=a), p = eq_refl. If so, you cannot prove it in Coq, unless you know something about a, e.g., decidable equality. In that case, you can use the results on UIP (unicity of identity proofs) from the standard library.
When proving in Coq, it's nice to be able to prove one little piece at a time, and have Coq help keep track of the obligations.
Theorem ModusPonens: forall (A B : Prop), ((A -> B) /\ A) -> B.
Proof.
intros A B [H1 H2].
apply H1.
At this point I can see the proof state to know what is required to finish the proof:
context
H2: B
------
goal: B
But when writing Gallina, do we have to solve the whole thing in one bang, or make lots of little helper functions? I'd love to be able to put use a question mark to ask Coq what it's looking for:
Definition ModusPonens' := fun (A B : Prop) (H : (A -> B) /\ A) =>
match H with
| conj H1 H2 => H1 {?} (* hole of type B *)
end.
It really seems like Coq should be able to do this, because I can even put ltac in there and Coq will find what it needs:
Definition ModusPonens' := fun (A B : Prop) (H : (A -> B) /\ A) =>
match H with
| conj H1 H2 => H1 ltac:(assumption)
end.
If Coq is smart enough to finish writing the definition for me, it's probably smart enough to tell me what I need to write in order to finish the function myself, at least in simple cases like this.
So how do I do this? Does Coq have this kind of feature?
You can use refine for this. You can write underscores which will turn into obligations for you to solve later.
Definition ModusPonens: forall (A B : Prop), ((A -> B) /\ A) -> B.
refine (fun A B H =>
match H with
| conj H1 H2 => H1 _ (* hole of type A *)
end).
Now your goal is to provide an A. This can be discharged with exact H2. Defined.
Use an underscore
Definition ModusPonens' := fun (A B : Prop) (H : (A -> B) /\ A) =>
match H with
| conj H1 H2 => H1 _ (* hole of type A *)
end.
(*
Error: Cannot infer this placeholder of type
"A" in environment:
A, B : Prop
H : (A -> B) /\ A
H1 : A -> B
H2 : A
*)
or use Program
Require Import Program.
Obligation Tactic := idtac. (* By default Program tries to be smart and solve simple obligations automatically. This commands disables it. *)
Program Definition ModusPonens' := fun (A B : Prop) (H : (A -> B) /\ A) =>
match H with
| conj H1 H2 => H1 _ (* hole of type A *)
end.
Next Obligation. intros. (* See the type of the hole *)
In Coq I have
Definition f (s:Unit) : tt=tt := match s with tt => idpath end.
Definition g (p:tt=tt) : Unit := match p with idpath => tt end.
and I would like to prove forall (p:tt=tt), (f o g) p = p.
I want to do it using the path induction described in 1.12.1 in HoTT's book.
It is clear that for the case in which p is idpath, we can prove
assert( (f o g) idpath = idpath).
simpl.
reflexivity.
But how do I use path induction in Coq to package together the whole proof?
The whole proof until now: (What to put instead of admit?)
Require Import HoTT.
Definition f (s:Unit) : tt=tt := match s with tt => idpath end.
Definition g (p:tt=tt) : Unit := match p with idpath => tt end.
Theorem myTheorem : forall (p:tt=tt), (f o g) p = p.
assert( (f o g) idpath = idpath).
simpl.
reflexivity.
admit.
The analog of path induction in Coq is the match construct. Here is how we can use it to define (based) path induction as described in the HoTT book.
Set Implicit Arguments.
Definition J {A} {x : A} (P : forall y, x = y -> Type)
(H : P x eq_refl) : forall y p, P y p :=
fun y p => match p with eq_refl => H end.
The type of this definition says that, whenever we want to prove P y p, where
y : A,
p : x = y, and
P : forall y, x = y -> Type,
it suffices to show that P x eq_refl holds. We can use J to show that your g function is constant. (I have rephrased the definitions to match the ones given by the Coq standard library.)
Definition f (s : unit) : tt = tt := match s with tt => eq_refl end.
Definition g (p : tt = tt) : unit := match p return unit with eq_refl => tt end.
Definition g_tt p : g p = tt :=
J (fun y q => match q return unit with eq_refl => tt end = tt)
eq_refl p.
The tricky part of this proof is finding out what the P parameter of J should be, which is also the case of other proofs that proceed by path induction. Here, I had to unfold the definition of g, because it requires an argument of type tt = tt, whereas the q used above has type tt = y. In any case, you can see that P tt p is definitionally equal to g p = tt, which is what we want to prove.
We can play trick to show that p = eq_refl for any p : tt = tt. Combined with the previous result, it will give exactly what you want.
Definition result (p : tt = tt) : p = eq_refl :=
J (fun y q =>
unit_rect (fun z => tt = z -> Prop)
(fun u => u = eq_refl)
y q)
eq_refl p.
Once again, the crux is the P parameter. We make use of the induction principle for unit, which says that we can define something of type T x (for T : unit -> Type and x : tt) whenever we can find an element of T tt. Recall that the result of this application of J should have type
P tt p
which in this case is just
unit_rect (fun z => tt = z -> Prop)
(fun u => u = eq_refl)
tt p
= (p = eq_refl)
by the computation rules for unit_rect.
Unfortunately, this sort of proof is difficult to replicate with Coq's tactic language, because it often has trouble inferring what P should be. It is often easier to figure out what this value should be yourself and write down the proof term explicitly.
I don't quite understand why, but Coq is also much better at figuring out this annotation if you write down the proof term with match. Compare:
Definition result' (p : tt = tt) : p = eq_refl :=
match p with eq_refl => eq_refl end.
Although this looks much simpler, you will see that the actual term inferred by Coq is much more complicated when you try to print it. Try it!
Edit
Ah, I just realized that you were trying to use the HoTT version of Coq. I don't have that version installed, but I think it shouldn't be too hard to adapt my solution to it.
I realize this question is super old and has long been solved but I do want to note that HoTT path induction is done slightly differently than Arthur's answer prescribes. I think this is helpful to see for two reasons: (i) the way HoTT sets things up is a bit less complicated and (ii) it is more in line with how path induction is actually used in HoTT and so it will be easier to translate into their library. Both of these points are mostly for people like me who come upon this question years later.
First, the symbol equality symbol is redefined in HoTT to denote the path space, which is defined as being the inductive type with one generator refl x for each point in a type A.
So in HoTT we have
Inductive paths {A : UU} (x : A) := A -> UU
| refl : paths a a.
Based path induction is then just the function paths_rect which is automatically generated by the Coq system. Path induction can then be defined as an instance of Based Path induction, as is done in The HoTT Book.
This can all be seen in the UniMath file "Preamble" in the Foundations directory.
In Coq, I'm having problems with applying the rewrite tactic in the following situation:
Section Test.
Hypothesis s t : nat -> nat.
Hypothesis s_ext_eq_t : forall (x : nat), s x = t x.
Definition dummy_s : nat -> nat :=
fun n => match n with
| O => 42
| S np => s np
end.
Definition dummy_t : nat -> nat :=
fun n => match n with
| O => 42
| S np => t np
end.
Goal forall (n : nat), dummy_s n = dummy_t n.
Proof.
intro n. unfold dummy_s. unfold dummy_t.
At that stage, the local context and current goal look as follows:
1 subgoals, subgoal 1 (ID 6)
s : nat -> nat
t : nat -> nat
s_ext_eq_t : forall x : nat, s x = t x
n : nat
============================
match n with
| 0 => 42
| S np => s np
end = match n with
| 0 => 42
| S np => t np
end
Now it should be possible to apply the rewrite tactic to replace the occurence of s np in the goal by t np, thereby making it possible to solve the goal using reflexivity. However,
rewrite s_ext_eq_t.
gives
Toplevel input, characters 0-18:
Error: Found no subterm matching "s ?190" in the current goal.
What am I doing wrong? One can get into a situation where rewrite is applicable via
destruct n.
(* n = 0 *)
reflexivity.
(* n > 0 *)
rewrite s_ext_eq_t.
reflexivity.
Qed.
but in the actual situation I am facing, several such destructs would be necessary, and I wonder whether rewrite or a variant of it is able to do this automatically.
Addendum The above situation naturally occurs when proving that a function defined via well-founded recursion has the desired fixed point property:
Suppose A: Type and that R: A -> A -> Prop is a well-founded relation, i.e. we have Rwf: well_founded R. Then, given a type family P: A -> Type we may construct a section
Fix : forall (x : A), P a
through recursion over R, with the recursion step given as a function
F : forall x:A, (forall y:A, R y x -> P y) -> P x
See https://coq.inria.fr/library/Coq.Init.Wf.html However, to show that Fix indeed has the fixed point property
forall (x : A), Fix x = F (fun (y:A) _ => Fix y)`
we need to provide a witness
F_ext : forall (x:A) (f g:forall y:A, R y x -> P y),
(forall (y:A) (p:R y x), f y p = g y p) -> F f = F g.
i.e. we have to show that F does not use anything else from the given f: forall y:A, R y x -> P y but its values. Of course, in any concrete situation, this should be trivial to verify, but when one tries to prove it, one runs into a situation a minimal example of which I have presented above: One is facing a huge equality of two copies of the code for the recursion step, one time with f and another time with g. Your assumption tells that f and g are extensionally equal, so one should be able to rewrite them. However, in the code for the recursion step, there might be a large number of pattern matchings and new variables that doesn't make sense in the local context, hence it would be (unnecessarily?) quite tedious to destruct dozens of times before being allowed to apply rewrite.
As mentioned in a comment above, it is not possible to perform the rewrite directly on the branch of the match statement, because np is not in scope in the top-level environment. As far as Coq's theory is concerned, a proof of your statement will have to destruct n at some point.
Although I am not aware of any tactics for automating this kind of problem, it is not too hard to come up with some custom ltac code for solving your problem without too much pain:
Ltac solve_eq :=
try reflexivity;
match goal with
| |- match ?x with _ => _ end
= match ?x with _ => _ end =>
destruct x; auto
end.
Goal forall (n : nat), dummy_s n = dummy_t n.
Proof.
intro n. unfold dummy_s. unfold dummy_t.
solve_eq.
Qed.
If your extensional equality results are hypotheses that appear in your context, then solve_eq should be able to solve many goals of this shape; if not, you might have to add extra lemmas to your hint database.
Suppose I have two functions f and g and I know f = g. Is there a forward reasoning 'function application' tactic that will allow me to add f a = g a to the context for some a in their common domain? In this contrived example, I could use assert (f a = g a) followed by f_equal. But I want to do something like this in more complex situations; e.g.,
Lemma fapp : forall (A B : Type) (P Q : A -> B) (a : A),
(fun (a : A) => P a) = (fun (a : A) => Q a) ->
P a = Q a.
I think I can't correctly infer the general problem that you have, given your description and example.
If you already know H : f = g, you can use that to rewrite H wherever you want to show something about f and g, or just elim H to rewrite everything at once. You don't need to assert a helper theorem and if you do, you'll obviously need something like assert or pose proof.
If that equality is hidden underneath some eta-expansion, like in your example, remove that layer and then proceed as above. Here are two (out of many) possible ways of doing that:
intros A B P Q a H. assert (P = Q) as H0 by apply H. rewrite H0; reflexivity.
This solves your example proof by asserting the equality, then rewriting. Another possibility is to define eta reduction helpers (haven't found predefined ones) and using these. That will be more verbose, but might work in more complex cases.
If you define
Lemma eta_reduce : forall (A B : Type) (f : A -> B),
(fun x => f x) = f.
intros. reflexivity.
Defined.
Tactic Notation "eta" constr(f) "in" ident(H) :=
pattern (fun x => f x) in H;
rewrite -> eta_reduce in H.
you can do the following:
intros A B P Q a H. eta P in H. eta Q in H. rewrite H; reflexivity.
(That notation is a bit of a loose cannon and might rewrite in the wrong places. Don't rely on it and in case of anomalies do the pattern and rewrite manually.)
I don't have a lot of experience with Coq or its tactics, but why not just use an auxiliary theorem?
Theorem fapp': forall (t0 t1: Type) (f0 f1: t0 -> t1),
f0 = f1 -> forall (x0: t0), f0 x0 = f1 x0.
Proof.
intros.
rewrite H.
trivial.
Qed.
Lemma fapp : forall (A B : Type) (P Q : A -> B) (a : A),
(fun (a : A) => P a) = (fun (a : A) => Q a) ->
P a = Q a.
Proof.
intros.
apply fapp' with (x0 := a) in H.
trivial.
Qed.