I am having trouble understanding the concept of multiple successes in Coq's (8.5p1, ch9.2) branching and backtracking behavior. For example, from the documentation:
Backtracking branching
We can branch with the following structure:
expr1 + expr2
Tactics can be seen as having several successes. When a tactic fails
it asks for more successes of the prior tactics. expr1 + expr2 has all
the successes of v1 followed by all the successes of v2.
What I don't understand, is why do we need multiple successes in the first place? Isn't one success good enough to finish a proof?
Also from the documentation, it seems that there are less costly branching rules that are somehow "biased", including
first [ expr1 | ::: | exprn ]
and
expr1 || expr2
Why do we need the more costly option + and not always use the latter, more efficient tacticals?
The problem is that you are sometimes trying to discharge a goal but further subgoals might lead to a solution you thought would work to be rejected. If you accumulate all the successes then you can backtrack to wherever you made a wrong choice and explore another branch of the search tree.
Here is a silly example. let's say I want to prove this goal:
Goal exists m, m = 1.
Now, it's a fairly simple goal so I could do it manually but let's not. Let's write a tactic that, when confronted with an exists, tries all the possible natural numbers. If I write:
Ltac existNatFrom n :=
exists n || existNatFrom (S n).
Ltac existNat := existNatFrom O.
then as soon as I have run existNat, the system commits to the first successful choice. In particular this means that despite the recursive definition of existNatFrom, when calling existNat I'll always get O and only O.
The goal cannot be solved:
Goal exists m, m = 1.
Fail (existNat; reflexivity).
Abort.
On the other hand, if I use (+) instead of (||), I'll go through all possible natural numbers (in a lazy manner, by using backtracking). So writing:
Ltac existNatFrom' n :=
exists n + existNatFrom' (S n).
Ltac existNat' := existNatFrom' O.
means that I can now prove the goal:
Goal exists m, m = 1.
existNat'; reflexivity.
Qed.
Related
I'm a beginner with Coq, I learnt the language quickly, to do proofs etc.
But I don't understand what can we do with this.
Ok we prove some definitions etc. But in which ways can we use them?
I saw that we can extract in Haskell files, but I don't understand it either.
Because I would like to use the language to prove CVE for example.
One of the uses of Coq is verifying software. This means writing down a program and showing that it satisfies some specification that you care about. What counts as a specification is rather open ended: you might want to show that a C program does not suffer from buffer overflows, or that a compiler produces object code that behaves according to the specification of the source language.
There are two main ways of verifying software in Coq.
Internal verification
One possibility is to implement the program as a functional program that can be executed inside of Coq, and prove properties about it. This program can be extracted to a more conventional programming language such as Haskell or OCaml. You can then link this code against other modules in the extraction target to produce a complete executable. This is the approach, for instance, followed by the CompCert C compiler.
For concreteness, suppose that we want to write a verified sorting algorithm. Here is an implementation of insertion sort in Coq that uses the Mathematical Components library:
From Coq Require Import Extraction.
From mathcomp Require Import all_ssreflect.
Fixpoint insert n ns :=
if ns is m :: ns then
if n <= m then n :: m :: ns
else m :: insert n ns
else [:: n].
Lemma sorted_insert n ns : sorted leq ns -> sorted leq (insert n ns).
Proof.
case: ns => //= m ns m_ns; rewrite fun_if /=.
case: ltngtP => // /ltnW m_n.
elim: ns => [|p ns IH] /= in m m_ns m_n *; first by rewrite m_n.
case/andP: m_ns => m_p m_ns; rewrite fun_if /= m_n m_p.
by case: ltngtP => //= /ltnW p_n; rewrite IH.
Qed.
Fixpoint insertion_sort ns :=
if ns is n :: ns then insert n (insertion_sort ns)
else [::].
Lemma sorted_insertion_sort ns : sorted leq (insertion_sort ns).
Proof.
by elim: ns => //= n ns IH; rewrite sorted_insert.
Qed.
Extraction "insertion.ml" insertion_sort.
If you compile this file, you will see that it will generate an insertion.ml file that contains a translation of this program in OCaml.
External verification
Another possibility is to give a mathematical description of the behavior of your program and prove that this description is correct. For example, we can use Coq to define the behavior of C programs as a mathematical relation between inputs and outputs, and then use this description to argue that a particular C program is correct (i.e., that its sequence of inputs and outputs satisfy some property). This particular C program might be translated from actual C source code into a form that Coq understands, as done by the Verified Software Toolchain.
What does this mean?
A Coq proof guarantees that certain bugs cannot arise in an idealized model of program execution. Regardless of which verification approach you chose, this model is much simpler than what happens when a program actually runs. For instance, we don't bother modelling the laws of physics that describe the circuits of the processor that is running the program, because that would be too complex. However, most bugs that we care about can be described in terms of fairly simple models -- for example, we don't need detailed laws of physics to explain why a buffer overflow occurs in some execution. This makes Coq and related tools very effective at preventing bugs in practice.
I have a hard time finding the available rewrite rules for my situation. As I don't want to bother you with each rewrite question, I was wondering do you have some tips for finding suitable rewrite rules?
Do you have any tips on how to solve and or search for rewriting the following example:
1 subgoal
H: P
H0: Q
__________
R
And say I have Lemma Join: P /\ Q = R
In order to do this rewrite, I suppose I need to get H and H0 first rewritten into P /\ Q.
So how would you solve or find the rewrite rules for such a case?
Another example
H: a <= b
____________
b < a
I am confident there should exists some commutativity rewrite rule for this, but how can I best find this rule?
Many thanks in advance!
First a tip so you don't run into this problem later: Don't confuse equality of types for logical equivalence. What you usually mean in your first example above is that P/\Q <-> R, not that the type P/\Q is definitionally the same type as R.
With regards to your question about finding lemmas in the library; yes, it is very important to be able to find things there. Coq's Search command lets you find all (Required) lemmas that contain a certain pattern somewhere in it, or some particular string. The latter is useful because the library tends to have a somewhat predicable naming scheme, for instance the names for lemmas about decidability often contains then string "dec", commutativity lemmas often are called something with "comm" etc.
Try for example to search for decidability lemmas about integers, i.e. lemmas that have the term Z somewhere inside them, and the name contains the string "dec".
Require Import ZArith.
Search "dec" Z.
Back to your question; in your case you want to find a lemma that ends with "something and something", so you can use the pattern ( _ /\ _ )
Search ( _ /\ _ ).
However, you get awfully many hits, because many lemmas ends with "something and something".
In your particular case, you perhaps want to narrow the search to
Search (?a -> ?b -> ?a /\ ?b).
but be careful when you are using pattern variables, because perhaps the lemma you was looking for had the arguments in the other order.
In this particular case you found the lemma
conj: forall [A B : Prop], A -> B -> A /\ B
which is not really a lemma but the actual constructor for the inductive type. It is just a function. And remember, every theorem/lemma etc. in type theory is "just a function". Even rewriting is just function application.
Anyway, take seriously the task of learning to find lemmas, and to read the output from Search. It will help you a lot.
Btw, the pattern matching syntax is like the term syntax but with holes or variables, which you will also use when you are writing Ltac tactics, so it is useful to know for many reasons.
I want to prove following lemma.
Require Import Reals.Reals.
Open Scope R_scope.
Lemma trivial_lemma (r1 r2:R) : r1 - (r1 - r2) = r2.
Proof.
rewrite <- Ropp_minus_distr.
rewrite Ropp_plus_distr.
rewrite Ropp_involutive.
rewrite Ropp_minus_distr'.
Abort.
I know Rplus_opp_l, but I cannot apply it to my goal because of r2.
Please tell me your solution.
First you should know that the automatic tactic ring solves this kind of goals autommatically. In the long run, you should rely on this tactic often if you wish to be productive.
Second, it appears (through Search) that the library does not contain many lemmas about subtraction. In this case, you may have to unfold this operator to end up with a goal that has the more primitive addition and opposite operations. Here is a sequence of rewrites that does your work.
unfold Rminus.
rewrite Ropp_plus_distr.
rewrite Ropp_involutive.
rewrite <- Rplus_assoc.
rewrite Rplus_opp_r.
rewrite Rplus_0_l.
easy.
The fact that the library does not contain basic lemmas like this is an indication that the library designers intend users to rely more on the ring tactic.
So, I've got a proof that looks like this:
induction t; intros; inversion H ; crush.
It solves all my goals, but when I do Qed, I get the following error:
Cannot guess decreasing argument of fix.
So somewhere in the generated proof term, there's non-well-founded recursion. The problem is, I have no idea where.
Is there a way to debug this kind of error, or to see the (possibly non halting) proof term that the tactics script generates?
You can use Show Proof. to view the proof term so far.
Another command that can help with seeing where the recursion went wrong is Guarded., which runs the termination checker on the proof term so far. You'll need to break apart the tactic script into independent sentences to use it, though. Here's an example:
Fixpoint f (n:nat) : nat.
Proof.
apply plus.
exact (f n).
Guarded.
(* fails with:
Error:
Recursive definition of f is ill-formed.
...
*)
Defined.
You can use the Show Proof. command inside proof mode to print the proof term produced so far.
In addition to the other excellent answers, I also want to point out that using induction inside an interactive-mode Fixpoint is usually a mistake, because you're recursing twice. Writing fixpoints in interactive mode is often tricky because most automation tools will happily make a recursive call at every possible opportunity, even when it would be ill-founded.
I would advise to use Definition instead of Fixpoint and use induction in the proof script. This invokes the explicit recursor, which allows for much better control of automation. The disadvantage is decreased flexibility since fixpoints have fewer restrictions than recursors - but as we've seen, that is both a blessing and a curse.
The documentation for Coq carries the general admonition not to rely on the builtin naming mechanism, but select one's own names, lest the changes in the naming mechanism render past proofs invalid.
When considering expressions of the form remember Expr as v, we set the variable v to the expression Expr. But the name of the assumption is selected automatically, and is something like Heqv, so we have:
Heqv: v = Expr
How can I select my own name instead of Heqv? I can always rename it to whatever I like using the rename command, but that doesn't keep my proofs independent of the hypothetical future changes in the builtin naming mechanism in Coq.
If you may get rid of the separate equality, try set (name := val). Use unfold instead of rewrite to get the value back in place.
If you need the equality for more than the rewrite <-, I know of no built in tactic that does this. You can do it manually, though, or build a tactic / notation. I just threw this together. (Note: I'm not an expert, this might be done more easily.)
Tactic Notation "remember_as_eq" constr(expr) ident(vname) ident(eqname) :=
let v := fresh in
let HHelp := fresh in
set (v := expr);
(assert (HHelp : sigT (fun x => x = v)) by ( apply (existT _ v); reflexivity));
inversion HHelp as [vname eqname];
unfold v in *; clear v HHelp;
rewrite <- eqname in *.
Use as remember_as_eq (2+2) four Heqfour to get the same result as with remember (2+2) as four.
Note: Updated to handle more cases, the old version failed on some combinations of value and goal type. Leave a comment if you find another case that works with rewrite but not this one.