Coq - proving something which has already been defined? - coq

Taking the very straightforward proof of "the sum of two naturals is odd if one of them is even and the other odd":
Require Import Arith.
Require Import Coq.omega.Omega.
Definition even (n: nat) := exists k, n = 2 * k.
Definition odd (n: nat) := exists k, n = 2 * k + 1.
Lemma sum_odd_even : forall n m, odd (n + m) -> odd n /\ even m \/ even n /\ odd m.
Proof.
intros n. intros m. left.
destruct H. firstorder.
The state at the end of this block of code is:
2 subgoals
n, m, x : nat
H : n + m = 2 * x + 1
______________________________________(1/2)
odd n
______________________________________(2/2)
even m
To my understanding, it is telling me that I need to prove to it that I have an odd number n and an even number m through the hypothesis? Even though I have already stated than n is odd and m is even? How do I proceed from here?
UPDATE:
After a bit of fidgeting around (in light of the comments), I guess I would have to do something like this?
Lemma even_or_odd: forall (n: nat), even n \/ odd n.
Proof.
induction n as [|n IHn].
(* Base Case *)
left. unfold even. exists 0. firstorder.
(* step case *)
destruct IHn as [IHeven | IHodd].
right. unfold even in IHeven. destruct IHeven as [k Heq].
unfold odd. exists k. firstorder.
left. unfold odd in IHodd. destruct IHodd as [k Heq].
unfold even. exists (k + 1). firstorder.
Qed.
Which means that now:
Lemma sum_odd : forall n m, odd (n + m) -> odd n /\ even m \/ even n /\ odd m.
Proof.
intros n. intros m. left. destruct H. firstorder.
pose proof (even_or_odd n). pose proof (even_or_odd m).
Result:
2 subgoals
n, m, x : nat
H : n + m = 2 * x + 1
H0 : even n \/ odd n
H1 : even m \/ odd m
______________________________________(1/2)
odd n
______________________________________(2/2)
even m
Intuitively, all that I have done is saying that every number is either even or odd. Now I have to tell coq that my odd and even numbers are indeed odd and even (I guess?).
UPDATE 2:
As an aside, the problem is solvable with just firstorder:
Lemma sum_odd : forall n m, odd (n + m) -> odd n /\ even m \/ even n /\ odd m.
Proof.
intros n. intros m. firstorder.
pose proof (even_or_odd n). pose proof (even_or_odd m).
destruct H0 as [Even_n | Odd_n]. destruct H1 as [Even_m | Odd_m].
exfalso. firstorder.
right. auto.
destruct H1. left. auto.
exfalso. firstorder.
Qed.

Your use of left is still incorrect and keeps you from completing the proof. You apply it to the following goal:
odd (n + m) -> odd n /\ even m \/ even n /\ odd m
and it gives:
H : odd (n + m)
______________________________________(1/1)
odd n /\ even m
You are committing to proving that if n + m is odd, then n is odd and m is even. But this is not true: n might be odd and m might be even. Only apply left or right once you have enough information in the context to be sure which one you want to prove.
So let's restart without left:
Lemma sum_odd : forall n m, odd (n + m) -> odd n /\ even m \/ even n /\ odd m.
Proof.
intros n. intros m. firstorder.
pose proof (even_or_odd n). pose proof (even_or_odd m).
At this point we are at:
H : n + m = 2 * x + 1
H0 : even n \/ odd n
H1 : even m \/ odd m
______________________________________(1/1)
odd n /\ even m \/ even n /\ odd m
Now you want to prove something from disjunctions. In order to prove something of the form A \/ B -> C in Coq's constructive logic, you must prove both A -> C and B -> C. You do this by case analysis on the A \/ B (using destruct or other tactics). In this case we have two disjunctions to decompose:
destruct H0 as [Even_n | Odd_n], H1 as [Even_m | Odd_m].
This gives four cases. I'll show you the first two, the last two are symmetric.
Fist case:
H : n + m = 2 * x + 1
Even_n : even n
Even_m : even m
______________________________________(1/1)
odd n /\ even m \/ even n /\ odd m
The assumptions are contradictory: If both n and m are even, then H cannot hold. We can prove this as follows:
- exfalso. destruct Even_n, Even_m. omega.
(Step through this to understand what happens!) The exfalso is not really necessary, but it's good documentation that we are doing a proof by showing that the assumptions contradict.
Second case:
H : n + m = 2 * x + 1
Even_n : even n
Odd_m : odd m
______________________________________(1/1)
odd n /\ even m \/ even n /\ odd m
Now, knowing assumptions that apply in this case, we can commit to the right disjunct. This is why your left kept you from making progress!
- right.
All that remains to be proved is:
Even_n : even n
Odd_m : odd m
______________________________________(1/1)
even n /\ odd m
And auto can handle this.

Related

Coq: help to formalize an informal proof

Theorem ev_ev__ev_full : forall n m,
even (n+m) <-> (even n <-> even m).
Proof.
intros n m. split.
- intros H. split.
+ intros H1. apply (ev_ev__ev n m H H1).
+ intros H1. rewrite plus_comm in H. apply (ev_ev__ev m n H H1).
- intros H.
Output:
n, m : nat
H : even n <-> even m
============================
even (n + m)
Now n can be either even or not even.
if n is even, m is also even. Then by ev_sum theorem (n+m) is also even.
if n is not even, it has the form (n' + 1), where n' is even. m is also not even, and has the form (m' + 1), where m' is even. So their sum is equal to:
n + m = n' + 1 + m' + 1 => n + m = (n' + m') + 2.
even ((n' + m') + 2). After apply ev_SS we get even (n' + m'). As we know that n' is even and m' is even, we apply ev_sum. And this proves the theorem.
How to write this informal proof in coq?
Start with these lemmas:
Theorem even_S (n : nat) : (~even n <-> even (S n)) /\ (even n <-> ~even (S n)). Admitted.
Theorem contra {A B : Prop} (prf : A -> B) : ~B -> ~A. Admitted.
even_S is proven with induction, and I think it's one of the examples of theorems where making the conclusion stronger than you might expect makes it easier to prove (dropping either side of the /\ makes the remaining side difficult). contra is a tautology.
Knowing even_S, the decidability of even n follows straightforwardly from induction on n.
Theorem even_dec (n : nat) : {even n} + {~even n}. Admitted.
This is a decision procedure: even_dec n tells you whether n is even or not, depending on whether it returns the left or right alternative. { _ } + { _ } is the notation for sumbool. It's basically like a bool (it's in Set and so can be destructed in computationally relevant contexts) except it also witnesses one of the two given Props depending on the alternative. In your proof, the first step is branching on this property:
destruct (even_dec n) as [prf_n | prf_n].
If even n, the proof is trivial.
+ admit.
Otherwise, the contrapositive of the backwards implication tells us ~even m. We can also eliminate the nots:
+ pose proof (contra (proj2 H) prf_n) as prf_m.
apply even_S in prf_n.
apply even_S in prf_m.
The rest of the proof (asserting that n = S n', m = S m', even n', even m' and thus even (n + m)) follows with some work (with inversion).
admit.
(I have filled in the admits myself and this path does successfully lead to the proof, but just spilling all the answers is no fun :).)

Coq theorem proving: Simple fraction law in peano arithmetic

I am learning coq and am trying to prove equalities in peano arithmetic.
I got stuck on a simple fraction law.
We know that (n + m) / 2 = n / 2 + m / 2 from primary school.
In peano arithmetic this does only hold if n and m are even (because then division produces correct results).
Compute (3 / 2) + (5 / 2). (*3*)
Compute (3 + 5) / 2. (*4*)
So we define:
Theorem fraction_addition: forall n m: nat ,
even n -> even m -> Nat.div2 n + Nat.div2 m = Nat.div2 (n + m).
From my understanding this is a correct and provable theorem.
I tried an inductive proof, e.g.
intros n m en em.
induction n.
- reflexivity.
- ???
Which gets me into the situation that
en = even (S n)
and IHn : even n -> Nat.div2 n + Nat.div2 m = Nat.div2 (n + m), so i don't find a way to apply the induction hypothesis.
After long research of the standard library and documentation, i don't find an answer.
You need to strengthen your induction hypothesis in cases like this.
One way of doing this is by proving an induction principle like this one:
From Coq Require Import Arith Even.
Lemma nat_ind2 (P : nat -> Prop) :
P 0 ->
P 1 ->
(forall n, P n -> P (S n) -> P (S (S n))) ->
forall n, P n.
Proof.
now intros P0 P1 IH n; enough (H : P n /\ P (S n)); [|induction n]; intuition.
Qed.
nat_ind2 can be used as follows:
Theorem fraction_addition n m :
even n -> even m ->
Nat.div2 n + Nat.div2 m = Nat.div2 (n + m).
Proof.
induction n using nat_ind2.
(* here goes the rest of the proof *)
Qed.
You can also prove your theorem without induction if you are ok with using the standard library.
If you use Even m in your hypothesis (which says exists n, m = 2*m) then you can use simple algebraic rewrites with lemmas from the standard library.
Require Import PeanoNat.
Import Nat.
Goal forall n m, Even n -> Even m -> n / 2 + m / 2 = (n+m)/2.
inversion 1; inversion 1.
subst.
rewrite <- mul_add_distr_l.
rewrite ?(mul_comm 2).
rewrite ?div_mul; auto.
Qed.
The question mark just means "rewrite as many (zero or more) times as possible".
inversion 1 does inversion on the first inductive hypothesis in the goal, in this case first Even n and then Even m. It gives us n = 2 * x and m = 2 * x0 in the context, which we then substitute.
Also note even_spec: forall n : nat, even n = true <-> Even n, so you can use even if you prefer that, just rewrite with even_spec first...

renaming part of hypothesis in Coq

After destructing n in my proof, I am stuck at the following:
1 subgoal
n : nat
X : Type
h : X
t : list X
n' : nat
E : n = S n'
H' : length t = n'
IHl : length t = n -> nth_error t n = None
______________________________________(1/1)
nth_error t n' = None
I want to rewrite using IHl, but that is not possible. How do I compose IHl and H' to make sense and prove this theorem?
I am just trying to elaborate on #Arthur answer.
I was able to reproduce your goal with the following script:
Require Import List.
Lemma toto (n : nat) (X : Type) (l : list nat) : length l = n -> nth_error l n = None.
Proof.
induction l as [ | h t IHl].
case_eq n.
simpl; auto.
simpl; discriminate.
case_eq n.
simpl; discriminate.
intros n' E.
simpl; intros E'; injection E'; clear E'; intros H'.
and I agree that this goal cannot be proved. Now, if you instead start your proof with the following text (the Proof and induction lines have to be replaced), it will be provable (I checked).
Proof.
revert n.
induction l as [ | h t IHl]; intros n.
The difference is that the induction hypothesis now has the following statement.
forall n : nat, length t = n -> nth_error t n = None
What happened? In the first (faulty) variant, you attempt to prove a statement for all lists whose length is equal to a precise n, because n is fixed before you start the proof by induction. In the second (correct) variant, you attempt to prove a statement for all lists l, and this statement accepts any n as long as length l = n.
In the first variant, n is fixed and the equality length l = n restricts l to be among those that have length precisely n. In the second case, l is chosen first, and n is not fixed, but the equality length l = n restricts n to follow the length of l.
This is called "loading the induction" because the statement forall n, length l = n -> nth_error l n = None is stronger (it is loaded) than the statement that you attempt to prove in the first variant (just for one specific n), but surprisingly it is easier to prove.
You cannot, because your induction hypothesis is not general enough. Here is a statement that should be easier to prove:
forall (X : Type) (t : list X), nth_error t (length t) = None

Inductive Predicate for Addition in Coq

I'm new to inductive predicates in Coq. I have learned how to define simple inductive predicates such as "even" (as in adam.chlipala.net/cpdt/html/Predicates.html) or "last" (as in http://www.cse.chalmers.se/research/group/logic/TypesSS05/resources/coq/CoqArt/inductive-prop-chap/SRC/last.v).
Now I wanted to try something slightly more complicated: to define addition as an inductive predicate, but I got stuck. I did the following:
Inductive N : Type :=
| z : N (* zero *)
| s : N -> N. (* successor *)
Inductive Add: N -> N -> N -> Prop :=
| add_z: forall n, (Add n z n)
| add_s: forall m n r, (Add m n r) -> (Add m (s n) (s r)).
Fixpoint plus (x y : N) :=
match y with
| z => x
| (s n) => (s (plus x n))
end.
And I would like to prove a simple theorem (analogously to what has been done for last and last_fun in www.cse.chalmers.se/research/group/logic/TypesSS05/resources/coq/CoqArt/inductive-prop-chap/SRC/last.v):
Theorem T1: forall x y r, (plus x y) = r -> (Add x y r).
Proof.
intros x y r. induction y.
simpl. intro H. rewrite H. apply add_z.
case r.
simpl. intro H. discriminate H.
???
But then I get stuck. The induction hypothesis seems strange. I don't know if I defined Add wrongly, or if I am just using wrong tactics. Could you please help me, by either correcting my inductive Add or telling me how to complete this proof?
You introduced r before using induction on y. In general you'll want to use induction before introducing anything so the induction hypothesis is as general as possible.
Conjecture injectivity : forall n m, s n = s m -> n = m.
Theorem T1: forall x y r, (plus x y) = r -> (Add x y r).
Proof.
intros x y. induction y.
simpl. intros r H. rewrite H. apply add_z.
intro r. case r.
simpl. intro H. discriminate H.
simpl. intros n H. apply add_s. apply IHy. apply injectivity. apply H.
Qed.

Proving commutativity of max in coq

I have a function max:
Fixpoint max (n : nat) (m : nat) : nat :=
match n, m with
| O, O => O
| O, S x => S x
| S x, O => S x
| S x, S y => S (max x y)
end.
and a proof of the commutativity of max as follows:
Theorem max_comm :
forall n m : nat, max n m = max m n.
Proof.
intros n m.
induction n as [|n'];
induction m as [|m'];
simpl; trivial.
(* Qed. *)
This leaves off at S (max n' m') = S (max m' n'), which seems correct, and given the base case has already been proven, seems like one should be able to tell coq "just use the recursion!". However, I cannot figure out how to do it. Any help?
The problem is you introduce variable m before doing induction on variable n, and that makes the induction hypothesis less general. Try this instead.
intro n; induction n as [| n' IHn'];
intro m; destruct m as [| m'];
simpl; try (rewrite IHn'); trivial.