I am a beginner at coq.
I do not know the meaning of intros [=] and intros [= <- H] . and I could not find an easy explanation. Would someone explain these two to me please?
Regards
The documentation for this is here. I will add a little explanation note.
The first historical use of intro patterns is to decompose data that is packed in inductive objects on the fly. Here is a first easy example (tested with coq 8.13.2).
Lemma forall A B, A /\ B -> B /\ A.
Proof.
If you run the tactic intros A B H then the hypothesis H will be a proof of A /\ B. Morally, this contains knowledge that A holds, but it cannot be used as such, because it is a proof of a stronger fact. It is often the case that users want directly to decompose this hypothesis, this would normally be done by typing destruct H as [Ha Hb]. But if you know right away that you will not keep hypothesis H, why not find a shorter expression. This is what the intro pattern is used for.
So you type the following command and have the resulting goal:
Intros A B [Ha Hb].
(* resulting goal
A, B : Prop
Ha : A
Hb : B
============================
B /\ A
*)
Abort.
I will not finish this proof. But you get the idea of what intro patterns are for: decompose information on the fly when inductive types (like conjunction here) pack several pieces of information together.
Now, equality information also can pack several pieces of information together. Assume now that we are working with lists of natural numbers and we have the following equality.
Require Import List.
Lemma intro_pattern_example2 n m p q l1 l2 :
(n :: S m :: l1) = (p :: S q :: l2) -> q :: p :: l2 = m :: n :: l1.
The equality in the left-hand side of the implication is an equality between two lists, but it actually packs several more elementary pieces of information: n = p, m = q, and l1 = l2. If you just type intros H, you obtain the equality between two lists of length 3, but if you type intros [=], you ask the proof system to explore the structure of each equality member and check when constructors appear so that the smaller pieces of information can be placed in separate hypothesis instead of the big one. This is a short hand for the use of the injection tactic. Here is the example.
intros [= Hn Hm Hl1].
(*resulting goal:
n, m, p, q : nat
l1, l2 : list nat
Hn : n = p
Hm : m = q
Hl1 : l1 = l2
============================
q :: p :: l2 = m :: n :: l1
*)
So you see, this intro pattern unpacks information that would otherwise be stuck in a more complex hypothesis.
Now, when an hypothesis is an equality, there is another action you might want to perform right away. You might want to rewrite with it. In intro patterns, this is done by replacing the name you would give to that equality with an arrow. Let's test this on the previous goal.
Undo.
intros [= -> -> ->].
(* resulting goal
p, q : nat
l2 : list nat
============================
q :: p :: l2 = q :: p :: l2
*)
Now this goal can be solved quickly with reflexivity, trivial, or auto. Please note that the hypotheses were used to rewrite, but they were not kept in the goal context, so this possibility to rewrite directly from the intro pattern has to be used with caution, because you are actually losing some information.
The [= ] intro pattern is used especially for equalities and when both members are datatype constructors. It exploits the natural injectivity property of these constructors. there is another property that is respected by datatype constructors. It is the fact that two pieces of data with different head constructors can never be equal. This is exploited in Coq by the discriminate tactic. The [=] intro pattern is shorthand for both the injection and discriminate tactics.
Related
I was working through a simple lemma and came across a situation where neither the contradiction or injection tactics were as powerful as I might have expected.
Theorem list_app_single: forall (T : Type) (x : T) (l1 l2 : list T),
l1++[x] = l2++[x] -> l1 = l2.
Proof.
intros. generalize dependent l2. induction l1.
- intros. induction l2.
-- reflexivity.
-- inversion H.
Stopping here the proof state is:
1 subgoal
T : Type
x, x0 : T
l2 : list T
H : [ ] ++ [x] = (x0 :: l2) ++ [x]
IHl2 : [ ] ++ [x] = l2 ++ [x] -> [ ] = l2
H1 : x = x0
H2 : [ ] = l2 ++ [x0]
______________________________________(1/1)
[ ] = x0 :: l2
Clearly H2 is not true, but coq doesn't see this when applying the discriminate tactic. Is there a tactic that is more appropriate that can resolve that H2 is in fact false?
Edit: Made the question more focused on a specific tactic to overcome limitations of discriminate.
To complete #Andrey's answer, discriminate indeed applies on equalities featuring different constructors like [] = x :: l.
A solution to this problem can be achieved by adding another observation on top of your equality. Here for instance, you can observe that the lengths of such expressions wouldn't match:
From [] = l ++ [x] you obtain length [] = length (l ++ [x]) which simplifies to 0 = length l + 1.
From Coq Require Import List Lia.
Import ListNotations.
Lemma foo :
forall (A : Type) (l : list A) (x : A),
[] = l ++ [x] ->
False.
Proof.
intros A l x e.
apply (f_equal (#length A)) in e.
rewrite app_length in e. simpl in e. lia.
Qed.
Notice that in the end, I apply the lia tactic to derive a contradiction from 0 = n + 1.
This method can be very useful in cases where just destructing l wouldn't work right away.
If you have discriminations that you perform often, then it might be worth it to have your own discr tactic to do it for you.
To use the discriminate tactic, you need the "top" terms of parts your expression to be constructors (after simplifying). So, the discriminate can see [after some 'thinking'] that the constructors are different.
You do not have constructor on the top of the right part of equality in H2. Namely, l2 ++ [x0] is not a constructor. It is an application of function app (another name of ++ operator) which has two parameters, namely l2 and [x0]. So, your expression looks like
H2 : [ ] = app l2 [x0]
And the right part is obviously not a constructor.
What you can try is to destruct l2.. Since the app function works by matching its first argument then after the simplifying (in H2), top right part of H2 will be a constructor. And the discriminate will be able to finish the proof.
As for another, more smart tactic which able to do it: as far as I can see a general solution is impossible here (we should fall into the halting problem). But I think that after some research somebody could create something more smart then just discrimite. You can see an example of such tactic with good explanation of how it works (the tactic is named crush) in Certified Programming with Dependent Types book by Adam Chlipala.
Namely crush might not be able to solve this particular problem. But I think you could write example of such tactic using techniques the author suggests.
I'm partial to #Theo's solution. It is easy to start destructing terms to the left and to the right, but by doing that one starts to reason on a too low level - reasoning about the implementation of the data rather than about the properties, which makes it less likely for the proof to carry over to other situations.
So if you want just "one tactic that works" then destruct is often useful. You can solve you goal with
now destruct l2.
But if you want your proof to reason in the theory of the things you reason about - lists - then this proof does just that.
enough (#length T [] <> 0) by auto.
rewrite H2, app_length, PeanoNat.Nat.add_comm; auto.
I wanted to see a few hands on examples of Coq proofs of the form:
\exists A(x1,...,xn)
essentially where the Goal had an existential quantifier. I was having issues manipulating the goal in meaningful ways to make progress in my proof and wanted to see a few examples of common tactics to manipulate.
What are some good existential quantifiers examples in Coq to prove?
My specific example I had:
Theorem Big_Small_ForwardImpl :
forall (P : Program) (S' : State),
(BigStepR (B_PgmConf P) (B_StateConf S')) -> (ConfigEquivR (S_PgmConf P) (S_BlkConf EmptyBlk S')).
Proof.
intros.
induction P.
unfold ConfigEquivR.
refine (ex_intro _ _ _) .
my context and goals was:
1 subgoal
l : list string
s : Statement
S' : State
H : BigStepR (B_PgmConf (Pgm l s)) (B_StateConf S')
______________________________________(1/1)
exists N : nat, NSmallSteps N (S_PgmConf (Pgm l s)) (S_BlkConf EmptyBlk S')
but then changed to:
1 subgoal
l : list string
s : Statement
S' : State
H : BigStepR (B_PgmConf (Pgm l s)) (B_StateConf S')
______________________________________(1/1)
NSmallSteps ?Goal (S_PgmConf (Pgm l s)) (S_BlkConf EmptyBlk S')
after using the refine (ex_intro _ _ _) tactic. Since I am not sure what is going on I was hoping some simpler examples could show me how to manipulate existential quantifiers in my Coq goal.
helpful comment:
The ?Goal was introduced by Coq as a placeholder for some N that will have to be deduced later in the proof.
The following example is based on the code provided in this answer.
Suppose we have a type T and a binary relation R on elements of type T. For the purpose of this example, we can define those as follows.
Variable T : Type.
Variable R : T -> T -> Prop.
Let us prove the following simple theorem.
Theorem test : forall x y, R x y -> exists t, R x t.
Here is a possible solution.
Proof.
intros. exists y. apply H.
Qed.
Instead of explicitly specifying that y is the element we are looking for, we can rely on Coq's powerful automatic proof mechanisms in order to automatically deduce which variable satisfies R x t:
Proof.
intros.
eexists. (* Introduce a temporary placeholder of the form ?t *)
apply H. (* Coq can deduce from the hypothesis H that ?t must be y *)
Qed.
There exist numerous tactics that make ise of the same automated deduction mechanisms, such as eexists, eapply, eauto, etc.
Note that their names often correspond to usual tactics prefixed with an e.
In Software Foundations IndProp.v one is asked to prove the pigeonhole principle, and one may use excluded middle, but it is mentioned that it is not strictly necessary. I've been trying to prove it without EM, but my brain seems to be wired classically.
Q: How would one prove the theorem without using excluded middle? How should one generally approach proofs for types without decidable equality, where one can't easily reason by cases?
I'd be very happy for a complete proof to look at, but please avoid posting it "in the clear", so as to not spoil the exercise in the Software Foundations course.
The definition uses two inductive predicates, In and repeats.
Require Import Lists.List.
Import ListNotations.
Section Pigeon.
Variable (X:Type).
Implicit Type (x:X).
Fixpoint In x l : Prop := (*** In ***)
match l with
| nil => False
| (x'::l') => x' = x \/ In x l'
end.
Hypothesis in_split : forall x l, In x l -> exists l1 l2, l = l1 ++ x :: l2.
Hypothesis in_app: forall x l1 l2, In x (l1++l2) <-> In x l1 \/ In x l2.
Inductive repeats : list X -> Prop := (*** repeats ***)
repeats_hd l x : In x l -> repeats (x::l)
| repeats_tl l x : repeats l -> repeats (x::l).
Theorem pigeonhole_principle_NO_EM: (*** pigeonhole ***)
forall l1 l2,
length l2 < length l1 -> (* There are more pigeons than nests *)
(forall x, In x l1 -> In x l2) -> (* All pigeons are in some nest *)
repeats l1. (* Thus, some pigeons share nest *)
Proof.
(* ??? *)
I'll describe the thought process that led me to a solution, in case it helps. We may apply induction and it is straightforward to reduce to the case l1 = a::l1', l2 = a::l2'. Now l1' is a subset of a::l2'. My EM-trained intuition is that one of the following holds:
a is in l1'.
a is not in l1'.
In the latter case, each element of l1' is in a::l2' but differs from a, and therefore must be in l2'. Thus l1' is a subset of l2', and we can apply the inductive hypothesis.
Unfortunately if In is not decidable, the above can't be directly formalized. In particular if equality is not decidable for the given type, it's difficult to prove elements are unequal, and therefore difficult to prove a negative statement like ~(In a l1'). However, we wanted to use that negative statement to prove a positive one, namely
forall x, In x l1' -> In x l2'
By analogy, suppose we wanted to prove
P \/ Q
Q -> R
------
P \/ R
The above intuitive argument is like starting from P \/ ~P, and using ~P -> Q -> R in the second case. We can use a direct proof to avoid EM.
Quantifying over the list l1' makes this a bit more complicated, but still we can construct a direct proof using the following lemma, which can be proven by induction.
Lemma split_or {X} (l : list X) (P Q : X -> Prop) :
(forall x, In x l -> (P x \/ Q x)) ->
(exists x, In x l /\ P x) \/ (forall x, In x l -> Q x).
Finally note that the intuitive pigeonhole principle could also be formalized as the following way, which cannot be proven when the type has undecidable equality (note that it has a negative statement in the conclusion):
Definition pigeon2 {X} : Prop := forall (l1 l2 : list X),
length l2 < length l1 ->
(exists x, In x l1 /\ ~(In x l2)) \/ repeats l1.
A possible constructive proof goes like this:
We prove pigeonhole_principle_NO_EM by induction on l1. Only the non-empty case is possible because of the length constraint. So, assume l1 = x :: l1'. Now, check whether there is some element of l1' which is mapped by f : (forall x, In x l1 -> In x l2) to the same membership proof as x. If there is such an x' element, then it follows that x = x', therefore l1 repeats. If there is no such element, then we can get l2' by removing the element that x is mapped to from l2, and apply the induction hypothesis to l2' and the appropriate f' : forall x, In x l1' -> In x l2' function.
That's it, but I note that actually formalizing this proof is not easy with the definitions given, because we need to prove heterogeneous or dependent equalities, since we have to compare membership proofs for possibly different elements.
As to the question of getting the hang of constructive proofs in general, an important skill or habit is always examining what kind of data we have, not just what kind of logical facts we know. In this case, membership proofs are actually indices pointing into lists, bundled together with proofs that the pointed-to elements equal certain values. If membership proofs didn't tell where exactly elements are located then this proof would not be possible constructively.
Given any programming language, whenever a standard library function exists, we should most likely use it rather than write our own code. One would think that this advice applies equally to Coq. However, I recently forced myself to use the same_relation predicate of the Relation module, and I am left with the feeling of being worse off. So I must be missing something, hence my question. To illustrate what I mean let us consider to possible relations:
Require Import Relations. (* same_relation *)
Require Import Setoids.Setoid. (* seems to be needed for rewrite *)
Inductive rel1 {A:Type} : A -> A -> Prop :=
| rel1_refl : forall x:A, rel1 x x. (* for example *)
Inductive rel2 {A:Type} : A -> A -> Prop :=
| rel2_refl : forall x:A, rel2 x x. (* for example *)
The specific details of these relations do not matter here, as long as rel1 and rel2 are equivalent. Now, if I want to ignore the Coq library, I could simply state:
Lemma L1: forall (A:Type)(x y:A), rel1 x y <-> rel2 x y.
Proof.
(* some proof *)
Qed.
and if I want to follow my instinct and use the Coq library:
Lemma L2: forall (A:Type), same_relation A rel1 rel2.
Proof.
(* some proof *)
Qed.
In the simplest of cases, it seems that having proven lemma L1 or Lemma L2 is equally beneficial:
Lemma application1: forall (A:Type) (x y:A),
rel1 x y -> rel2 x y (* for example *)
Proof.
intros A x y H. apply L1 (* or L2 *) . exact H.
Qed.
Whether I decide to use apply L1 or apply L2 makes no difference...
However in practice, we are likely to be faced with a more complicated goal:
Lemma application2: forall (A:Type) (x y:A) (p:Prop),
p /\ rel1 x y -> p /\ rel2 x y.
Proof.
intros A x y p H. rewrite <- L1. exact H.
Qed.
My point here is that replacing rewrite <- L1 by rewrite <- L2 will fail. This is also true of the previous example, but at least I was able to use apply rather than rewrite. I cannot use apply in this case (unless I go through the trouble of splitting my goal). So it seems that I have lost the convenience of using rewrite, if I only have Lemma L2.
Using rewrite on results which are an equivalence (not just an equality) is very convenient. It seems that wrapping an equivalence into the predicate same_relation takes away this convenience. Was I right to follow my instinct and force myself to use same_relation? More generally, is it so true that if a construct is defined in the standard Coq library, I should use it, rather than define my own version of it?
You pose two questions, I try to answer separately:
Regarding your rewrite problem, this problem is natural as the definition of same_relation goes as double inclusion. I agree that maybe a definition using iff would be more convenient. It would really depend on the kind of goals you have. A possible solution for your problem is to define a view:
Lemma L1 {A:Type} {x y:A} : rel1 x y <-> rel2 x y.
Proof.
Admitted.
Lemma L2 {A:Type} : same_relation A rel1 rel2.
Proof.
Admitted.
Lemma U {T} {R1 R2 : relation T} :
same_relation _ R1 R2 -> forall x y, R1 x y <-> R2 x y.
Proof. now destruct 1; intros x y; split; auto. Qed.
Lemma application2 {A:Type} {x y:A} {p:Prop} :
p /\ rel1 x y -> p /\ rel2 x y.
Proof. now rewrite (U L2). Qed.
Note also that rewriting with a <-> relation is not really based on equality, but on "setoid rewriting". In fact, the following doesn't hold in Coq A <-> B -> A = B.
Regarding your second question, whether to use the Coq standard library is a highly subjective topic. I personally rarely use it, I prefer a different library called math-comp, but YMMV. Regarding relations, mathcomp is mostly specialized into boolean relations rel x y = x -> y -> bool, thus, equivalence is simply defined as equality, typically, given r1 r2 you'd write r1 =2 r2.
IMHO in the end, such choices are highly dependent on your application domain.
[edit]: Note that the Relation library is dated:
Naive set theory in Coq. Coq V6.1. This work was started in July 1993 by F. Prost.
So indeed, it may not be the best modern base to build Coq developments on.
From what I understand, function calls in Coq are opaque.
Sometimes, I need to use unfold to apply it and then fold to turn the function definition/body back to its name. This is often tedious. My question is, is there an easier way to let apply a specific instance of a function call?
As a minimal example, for a list l, to prove right-appending [] does not change l:
Theorem nil_right_app: forall {Y} (l: list Y), l ++ [] = l.
Proof.
induction l.
reflexivity.
This leaves:
1 subgoals
Y : Type
x : Y
l : list Y
IHl : l ++ [] = l
______________________________________(1/1)
(x :: l) ++ [] = x :: l
Now, I need to apply the definition of ++ (i.e. app) once (pretending there are other ++ in the goal which I don't want to apply/expand). Currently, the only way I know to implement this one time application is to first unfold ++ and then fold it:
unfold app at 1. fold (app l []).
giving:
______________________________________(1/1)
x :: l ++ [] = x :: l
But this is inconvenient as I have to figure out the form of the term to use in fold. I did the computation, not Coq. My question boils down to:
Is there a simpler way to implement this one-time function application to the same effect?
You can use simpl, compute or vm_compute if you want to ask Coq to perform some computation for you. If the definition of the function is Opaque, the above solution will fail, but you could first prove a rewriting lemma such as:
forall (A:Type) (a:A) (l1 l2: list A), (a :: l1) ++ l2 = a :: (l1 ++ l2).
using your technique, and then rewrite with it when necessary.
Here is an example using simpl:
Theorem nil_right_app: forall {Y} (l: list Y), l ++ nil = l.
Proof.
(* solve the first case directly *)
intros Y; induction l as [ | hd tl hi]; [reflexivity | ].
simpl app. (* or simply "simpl." *)
rewrite hi.
reflexivity.
Qed.
To answer your comment, I don't know how to tell cbv or compute to only compute a certain symbol. Note that in your case, they seem to compute too eagerly and simpl works better.