Coq: help to formalize an informal proof - coq

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 :).)

Related

Proving S (n + m) = n + (S m), how to rewrite n+1 = S(n)?

Theorem add_0_r : forall n:nat, n + 0 = n.
Proof.
intros n. induction n as [| n' IHn'].
- (* n = 0 *) reflexivity.
- (* n = S n' *) simpl. rewrite -> IHn'. reflexivity. Qed.
Theorem plus_n_Sm : forall n m : nat,
S (n + m) = n + (S m).
Proof.
intros n m. induction m as [| m' IHn']. rewrite -> add_0_r. rewrite <- sum.
The last tactic rewirte <- sum does not work. This is the goal:
n: ℕ
-------------
S(n) = n + 1
I don't know how to rewrite n+1 as S(n). I think that n+1 is just a notation for S(n), right?
If you look at the definition of + as follows, you can see that it is defined by induction on its first argument:
Locate "+". (* to obtain the name Nat.add *)
Print Nat.add.
(*
Nat.add =
fix add (n m : nat) {struct n} : nat :=
match n with
| 0 => m
| S p => S (add p m)
end
: nat -> nat -> nat
*)
As a result 1 + n is indeed convertible to S n (you can see that using Eval cbn in 1 + ?[n].) but not n + 1 (if you unfold Nat.add. you will obtain a pattern match stuck on the variable n).
For your proof, that specific definition of + means that you might reconsider your approach and try to do your proof by induction on n rather than m (paying attention to have the right induction hypothesis).
If you are using the nat type from the standard library, then n+1 is not a notation for S n, but a notation for the function Nat.add. In that case n+1 is not apparently equal to S n. You need to prove it by an induction on n.
By the way, if you are using Nat.nat, you need to use induction on n rather than m. Because Nat.add is defined by a match on the first argument. In this case, your first subgoal of the induction can be proved simply by reflexivity. (Coq is able to simplify S (0 + m) and 0 + S m, but not S (n + 0) and n + 1).
Was able to prove with the following:
Theorem plus_n_Sm : forall n m : nat,
S (n + m) = n + (S m).
Proof.
intros n m. induction n as [| n' IHn'].
- simpl. reflexivity.
- simpl. rewrite -> IHn'. reflexivity.
Qed.

Using a theorem on integer numbers for proving a theorem on natural numbers

I'm not a mathematician, but I take interest in the topic and the use of proof assistants like Coq. I still need to learn a lot on how Coq works. As an exercise, I would like to proof that:
forall n : nat, n > 0 -> Nat.Odd n <-> Nat.Odd (5 * n + 6).
I failed to proof this directly and therefore thought of taking a roundtrip via the integers:
Require Import ZArith.
Require Import Lia.
Theorem T1 : forall n : Z,
Z.Odd n <-> Z.Odd (5 * n + 6).
Proof.
unfold Z.Odd.
intros. split.
- intros. destruct H as [x G]. rewrite G. exists ((5 * x + 5)%Z). lia.
- intros. destruct H as [x G]. exists ((-2 * n - 3 + x)%Z). lia.
Qed.
I would now like to use this result to proof the initial theorem. Unfortunately, I get stuck in relating Nat.Odd to Z.Odd and the eventual application of T1:
Lemma L1 : forall n : nat,
Z.Odd (Z.of_nat n) <-> Nat.Odd n.
Proof.
intros.
Admitted.
Theorem T2 : forall n : nat,
n > 0 -> Nat.Odd n <-> Nat.Odd (5 * n + 6).
Proof.
intros.
pose proof T1 as G.
rewrite <- L1.
rewrite <- L1.
Admitted.
I would like to know if I'm on the right track here. I'm also seeking for some hints on how to eventually proof T2 using the result T1 (assuming that this is actually a sensible approach to proving the initial goal using Coq).
Any help is appreciated.
There is probably a way to prove this goal staying in Nat (by using a divisibility argument) but this approach is also feasible.
The lemma L1 on which you got stuck can actually be solved in a similar fashion as the theorem T1, leveraging lia for finding the right lemmas. Then, the only thing in your way to apply T1 in the course of proving T2 is to show that Z.of_nat respects addition and multiplication: you can rely another time on lia. All together you obtain the following proof:
From Coq Require Import ZArith Arith.PeanoNat Psatz.
Theorem T1 : forall n : Z, Z.Odd n <-> Z.Odd (5 * n + 6).
Admitted.
Lemma L1 (n : nat) : Z.Odd (Z.of_nat n) <-> Nat.Odd n.
Proof.
split.
- intros [x?]. exists (Z.to_nat x). lia.
- intros [x?]. exists (Z.of_nat x). lia.
Qed.
Theorem T2 (n : nat) : Nat.Odd n <-> Nat.Odd (5 * n + 6).
Proof.
do 2 rewrite <- L1.
(* We need to massage slightly the goal to apply T1 *)
assert (Z.of_nat (5*n + 6) = (5*(Z.of_nat n)+6)%Z) as -> by lia.
apply T1.
Qed.

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...

IndProp: ev_plus_plus

(** **** Exercise: 3 stars, standard, optional (ev_plus_plus)
This exercise just requires applying existing lemmas. No
induction or even case analysis is needed, though some of the
rewriting may be tedious. *)
Theorem ev_plus_plus : forall n m p,
even (n+m) -> even (n+p) -> even (m+p).
Proof.
intros n m p H1 H2.
Here is what I got:
1 subgoal (ID 89)
n, m, p : nat
H1 : even (n + m)
H2 : even (n + p)
============================
even (m + p)
I have proven the previous theorem:
Theorem ev_ev__ev : forall n m,
even (n+m) -> even n -> even m.
And wanted to apply it to H1, but
apply ev_ev__ev in H1.
gives an error:
Error: Unable to find an instance for the variable m.
Why can't it find "m" in the expression even (n + m)? How to fix?
Update
apply ev_ev__ev with (m:=m) in H1.
gives a very strange result:
2 subgoals (ID 90)
n, m, p : nat
H1 : even m
H2 : even (n + p)
============================
even (m + p)
subgoal 2 (ID 92) is:
even (n + m + m)
I thought that it will transform H1 to 2 hypothesis:
H11 : even n
H12 : even m
But instead it gave 2 subgoals, the second that we need to prove is more complicated than the initial one:
even (n + m + m)
What's happening here?
The statement forall n m, even (n+m) -> even n -> even m. does not mean "if we have that (n + m) is even then we have both that n is even and that m is even" (this is false, consider n = m = 1). Instead it means "if we have that (n+m) is even, and we have that n is even, then we have that m is even".
There is no way to get H11 : even n and H12 : even m just from H1 : even (n + m) without assuming a contradiction. I would suggest figuring out how to prove your theorem with pen and paper before trying to prove it in Coq.
Because Coq can't figure out what value it should give for m. You can apply the tactic eapply ev_ev__ev in H1. and see the goals
n, m, p : nat
H2 : even (n + p)
H1 : even ?m
============================
even (m + p)
subgoal 2 (ID 17) is:
even (n + m + ?m)
Coq has instantiated the m with a meta variable ?m, and you need to give a witness for this meta variable in the end to finish the proof.
Second approach is just apply the tactic with instantiating the value of m apply ev_ev__ev with (m := m) in H1.
You can see more on apply with tactics in software-foundations https://softwarefoundations.cis.upenn.edu/lf-current/Tactics.html
The thing that is happening is that Coq unifies H1 with the even n argument of ev_ev__ev instead of the even (n+m).
You can tell Coq exactly where you want H1 to go, and use _ wildcards for the places where you let Coq work out the details.
You probably wanted this the term ev_ev__ev n m H1 with type even n -> even m but your apply produced the term ev_ev__ev (n+m) m _ H1 which also left you with some more stuff to prove. To take a look at the proof context, do
Check ev_ev__ev (n+m) m _ H1.

Coq - proving something which has already been defined?

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.