I want to prove in Coq that:
convert l' + 1 + (convert l' + 1) = convert l' + convert l' + 1 + 1
only some parentheses is redundant and do not let me use reflexivity command; so what should I do?
All of the elements are nat (Natural) type so as convert l' is a function that will return a nat number and I do not want to use some powerful tactics like Omega and so on.
Omega is very useful, as it quickly lets you continue with the more interesting parts of the proof, but when one is learning I personally find it helpful to see a "simpler" proof (the omega-generated proof terms tend to be very long and unreadable).
First note that you will need to use associativity and commutativity of plus. Use Coq's search facilities to find useful lemmas. Use _ as a wild card character. You can find lemmas that contain structures that look like associativity like this:
SearchAbout (_ + (_ + _)= (_ + _) + _).
locates five lemmas that contain, among others, this:
plus_assoc: forall n m p : nat, n + (m + p) = n + m + p
In the same way you can find the commutativity lemma with
SearchAbout (_ + _ = _ + _).
And here it is:
plus_comm: forall n m : nat, n + m = m + n
You cannot apply them directly, but instead you can use the rewrite tactic that lets you work on sub-parts of the terms. I recommend that you play around with it to get a feeling for how it works.
Here is a proof of the desired lemma.
Require Import Arith.
Lemma nat_lemma: forall n, n + 1 + (n + 1) = n + n + 1 + 1.
intro n.
repeat rewrite <- plus_assoc. (* n + (1 + (n + 1)) = n + (n + (1 + 1)) *)
rewrite (plus_comm 1 (n+1)). (* uses (1 + (n + 1) = (n + 1) + 1 *)
repeat rewrite plus_assoc.
reflexivity.
Qed.
Now use this lemma to prove your theorem.
You can use the omega tactic. Just do Require Import Omega. at the beginning of your file and you should be good to go.
Related
Require Import PeanoNat.
Check PeanoNat.Nat.add_assoc.
Output:
Nat.add_assoc
: forall n m p : nat, n + (m + p) = n + m + p
So, the theorem is defined.
But when I create a theorem and try to use it, it gives an error:
Theorem a : forall a b c d e f,
a + b + c + d + e = f.
Proof.
intros.
PeanoNat.Nat.add_assoc a (b + c) d.
Error: The reference PeanoNat.Nat.add_assoc was not found in the
current environment.
Why can't it find the theorem?
What comes after Proof. is not the proof itself. It's a series of instructions, called tactics, that tells Coq how to build a proof. add_assoc is a proof, not a tactic that builds a proof. You would use the tactic rewrite (Nat.add_assoc a (b + c) d) to rewrite (any part of) the goal according to the equality
Nat.add_assoc a (b + c) d
: a + (b + c + d) = a + (b + c) + d
However, your goal a + b + c + d + e = f does not contain either of those terms—+ is left associative and your goal is actually (((a + b) + c) + d) + e = f—so this tactic will fail. In fact, your goal is unprovable, but I assume that it's just for example. You may also be interested in the tactic apply [prf]. It takes the conclusion (thing on the right side of all the ->s and foralls) of prf, matches it against the goal, and gives you subgoals for all of its hypotheses. See also: the Coq tactic reference.
Suppose I write a Fixpoint algorithm in Coq that sums up all the "halves" of a number:
Fixpoint sum_of_halves (a : nat) : nat :=
match a with
| 0 => 0
| 2 * k => a + (sum_of_halves k)
| S (2 * k) => a + (sum_of_halves k)
end.
Trying to evaluate the algorithm would get: Error: Invalid notation for pattern.
How can I get Coq to recognize that a is either an even or an odd number, and match it with either 2 * k or S (2 * k)?
Coq can only match on constructors. nat has two constructors, O and S, so you cannot match on 2 * k. You will have to use a non-match construct or a non-nat type or a different algorithm.
You need to prove that there are only three cases for a given natural number a. Either a is 0, either a is the double of another number k and k < a, or a is the double k + 1 and k < a, that the three cases are exclusive (this is important, otherwise making pattern matching possible would lead to an inconistency).
Fortunately, all this can be done. It is a bit advanced Coq programming, but it is somehow already done in ZArith. Here is a solution.
First note that the other number is already provided by one of the functions in the Coq library, div2.
Require Import Arith Nat.
Definition cases_div2 (a : nat) :
{k : nat | a = 2 * k /\ k < a}+{k : nat | a = S (2 * k) /\ k < a}+{a=0}.
destruct a as [ | a'].
right; reflexivity.
case_eq (odd (S a')); intros odd_a.
left; right; exists (div2 (S a')); rewrite (div2_odd (S a')) at 1.
split.
rewrite odd_a; simpl b2n; ring.
apply lt_div2; auto with arith.
left; left; exists (div2 (S a')); rewrite (div2_odd (S a')) at 1.
split.
rewrite odd_a; simpl b2n; ring.
apply lt_div2; auto with arith.
Defined.
Now, you can pattern match on your number a using cases_div2, but it is still not enough to define your function, because recursion using Fixpoint relies on recursive calls happening on the predecessor, and here k cannot be written as a predecessor pattern that will work for any input a. You need a stronger kind of recursion. I usually rely on Function or Fix for this kind of strong recursion. Here is an example with Fix
Definition sum_of_halves : nat -> nat :=
Fix Arith.Wf_nat.lt_wf (fun _ => nat)
(fun a (sum_of_halves' : forall y, y < a -> nat) =>
match cases_div2 a with
| inright h => 0
| inleft (inl (exist _ k (conj keq klt))) =>
a + sum_of_halves' k klt
| inleft (inr (exist _ k (conj keq klt))) =>
a + sum_of_halves' k klt
end).
Then to reason about sum_of_halves you will need to reason by well founded induction and use Fix_eq.
This is one possibility.
I'm using Coq 8.5pl1.
To make a contrived but illustrative example,
(* fix so simpl will automatically unfold. *)
Definition double := fix f n := 2*n.
Theorem contrived n : double (2 + n) = 2 + double (1 + n).
Now, I only want to simplify the arguments to double,
and not any part outside of it. (For example, because the
rest has already carefully been put into the correct form.)
simpl.
S (S (n + S (S (n + 0)))) = S (S (S (n + S (n + 0))))
This converted the outside (2 + ...) to (S (S ...)) as well as unfolding double.
I can match one of them by doing:
match goal with | |- (double ?A) = _ => simpl A end.
double (S (S n)) = 2 + double (1 + n)
How do I say that I want to simplify all of them?
That is, I want to get
double (S (S n)) = 2 + double (S n)
without having to put a separate pattern for each call to double.
I can simplify except for double itself with
remember double as x; simpl; subst x.
double (S (S n)) = S (S (double (S n)))
Opaque/Transparent approach
Combining the results of this answer and this one, we get the following solution:
Opaque double.
simpl (double _).
Transparent double.
We use the pattern capability of simpl to narrow down its "action domain", and Opaque/Transparent to forbid (allow resp.) unfolding of double.
Custom tactic approach
We can also define a custom tactic for simplifying arguments:
(* simplifies the first argument of a function *)
Ltac simpl_arg_of function :=
repeat multimatch goal with
| |- context [function ?A] =>
let A' := eval cbn -[function] in A in
change A with A'
end.
That let A' := ... construction is needed to protect nested functions from simplification. Here is a simple test:
Fact test n :
82 + double (2 + n)
=
double (1 + double (1 + 20)) + double (1 * n).
Proof.
simpl_arg_of double.
The above results in
82 + double (S (S n)) = double (S (double 21)) + double (n + 0)
Had we used something like context [function ?A] => simpl A in the definition of simpl_arg_of, we would've gotten
82 + double (S (S n)) = double 43 + double (n + 0)
instead.
Arguments directive approach
As suggested by #eponier in comments, we can take advantage of yet another form of simpl -- simpl <qualid>, which the manual defines as:
This applies simpl only to the applicative subterms whose head occurrence is the unfoldable constant qualid (the constant can be referred to by its notation using string if such a notation exists).
The Opaque/Transparent approach doesn't work with it, however we can block unfolding of double using the Arguments directive:
Arguments double : simpl never.
simpl double.
You may find the ssreflect pattern selection language and rewrite mechanism useful here. For instance, you can have a finer grained control with patterns + the simpl operator /=:
From mathcomp Require Import ssreflect.
Definition double := fix f n := 2*n.
Theorem contrived n : double (2 + n) = 2 + double (1 + n).
rewrite ![_+n]/=.
Will display:
n : nat
============================
double (S (S n)) = 2 + double (S n)
You can also use anonymous rewrite rules:
rewrite (_ : double (2+n) = 2 + double (1+n)) //.
I would personally factor the rewrite in smaller lemmas:
Lemma doubleE n : double n = n + n.
Proof. by elim: n => //= n ihn; rewrite -!plus_n_Sm -plus_n_O. Qed.
Lemma doubleS n : double (1 + n) = 2 + double n.
Proof. by rewrite !doubleE /= -plus_n_Sm. Qed.
Theorem contrived n : double (1+n) = 2 + double n.
rewrite doubleS.
I have the following Lemma with an incomplete proof:
Lemma s_is_plus_one : forall n:nat, S n = n + 1.
Proof.
intros.
reflexivity.
Qed.
This proof fails with
Unable to unify "n + 1" with "S n".
It seems like eq_S would be the way to prove this, but I can't apply it (it doesn't recognize n + 1 as S n: Error: Unable to find an instance for the variable y.). I've also tried ring, but it can't find a relation. When I use rewrite, it just reduces to the same final goal.
How can I finish this proof?
This is related to the way (+) is defined. You can access (+)'s underlying definition by turning notations off (in CoqIDE that's in View > Display notations), seeing that the notation (+) corresponds to the function Nat.add and then calling Print Nat.add which gives you:
Nat.add =
fix add (n m : nat) {struct n} : nat :=
match n with
| O => m
| S p => S (add p m)
end
You can see that (+) is defined by matching on its first argument which in n + 1 is the variable n. Because n does not start with either O or S (it's not "constructor-headed"), the match cannot reduce. Which means you won't be able to prove the equality just by saying that the two things compute to the same normal form (which is what reflexivity claims).
Instead you need to explain to coq why it is the case that for any n the equality will hold true. A classic move in the case of a recursive function like Nat.add is to proceed with a proof by induction. And it does indeed do the job here:
Lemma s_is_plus_one : forall n:nat, S n = n + 1.
Proof.
intros. induction n.
- reflexivity.
- simpl. rewrite <- IHn. reflexivity.
Qed.
Another thing you can do is notice that 1 on the other hand is constructor-headed which means that the match would fire if only you had 1 + n rather than n + 1. Well, we're in luck because in the standard library someone already has proven that Nat.add is commutative so we can just use that:
Lemma s_is_plus_one : forall n:nat, S n = n + 1.
Proof.
intros.
rewrite (Nat.add_comm n 1).
reflexivity.
Qed.
A last alternative: using SearchAbout (?n + 1), we can find all the theorems talking about the pattern ?n + 1 for some variable ?n (the question mark is important here). The first result is the really relevant lemma:
Nat.add_1_r: forall n : nat, n + 1 = S n
I have a proof in Coq where one of the hypothesis is:
H : m = pred q * n + (r + n)
And I have a proven lemma which states:
Lemma suma_conmutativa: forall m, forall n, m + n = n + m.
Where + is Notation for a function called suma that I defined:
Fixpoint suma (m:nat) (n:nat) : nat :=
match m with
| 0 => n
| S k => S (suma k n)
end.
Notation "m + n" := (suma m n).
For some reason when I try to rewrite suma_conmutativa with r n in H I get the following error:
Error: Found no subterm matching "r + n" in H.
However, there clearly is a subterm matching r + n in H. Why can't Coq find it?
Thank you.
I am not an expert of notations in Coq, but here is how I understand your problem.
Coq replaces the first occurrence of + with suma. suma binds its arguments to scope nat_scope. Classic notation + is bound to nat_scope and is prefered for the second occurrence of +.
The solution I propose is to bound your notation to nat_scope to completely hide the original notation. This gives:
Notation "m + n" := (suma m n) : nat_scope.