Coq: Proving that the product of n and (S n) is even
Question
Given the procedure even, I want to prove that even (n * (S n)) = true for all natural numbers n.
Using induction, this is easily seen to be true for the case n = 0. However, the case (S n) * (S (S n)) is hard to simplify.
I've considered proving the lemma that even (m * n) = even m /\ even n, but this doesn't seem to be easier.
Also, it is easy to see that if even n = true iff. even (S n) = false.
Fixpoint even (n : nat) : bool :=
match n with
| O => true
| 1 => false
| S (S n') => even n'
end.
Can someone give a hint on how to prove this using a "beginner's" subset of Coq?
Answer (Anton Trunov)
This is a case where a more advanced induction principle can be useful. It is briefly described in this answer.
Require Import Coq.Arith.Arith. Require Import Coq.Bool.Bool.P: nat -> PropP 0 -> P 1 -> (forall n : nat, P n -> P (S n) -> P (S (S n))) -> forall n : nat, P nP: nat -> PropP 0 -> P 1 -> (forall n : nat, P n -> P (S n) -> P (S (S n))) -> forall n : nat, P nP: nat -> Prop
H: P 0
H0: P 1
H1: forall n : nat, P n -> P (S n) -> P (S (S n))
n: natP ninduction n; intuition. Qed.P: nat -> Prop
H: P 0
H0: P 1
H1: forall n : nat, P n -> P (S n) -> P (S (S n))
n: natP n /\ P (S n)
Now, let's define several helper lemmas. They are obvious and can be easily proved using the pair_induction principle and some proof automation.
forall n : nat, Nat.even (2 * n) = trueforall n : nat, Nat.even (2 * n) = truenow replace (2 * S n) with (2 + 2 * n) by ring. Qed.n: nat
IHn: Nat.even (2 * n) = trueNat.even (2 * S n) = trueforall m n : nat, Nat.even m = true -> Nat.even (m + n) = Nat.even nnow induction m using pair_induction; auto. Qed.forall m n : nat, Nat.even m = true -> Nat.even (m + n) = Nat.even nforall m n : nat, Nat.even (2 * m + n) = Nat.even nintros; apply even_add_even, even_mul2. Qed.forall m n : nat, Nat.even (2 * m + n) = Nat.even nforall n : nat, Nat.even (S n) = negb (Nat.even n)forall n : nat, Nat.even (S n) = negb (Nat.even n)n: nat
IHn: Nat.even (S n) = negb (Nat.even n)Nat.even (S (S n)) = negb (Nat.even (S n))n: nat
IHn: Nat.even (S n) = negb (Nat.even n)Nat.even n = negb (Nat.even (S n))assumption. Qed.n: nat
IHn: Nat.even (S n) = negb (Nat.even n)Nat.even (S n) = negb (Nat.even n)
The following lemma shows how to "distribute" even over multiplication. It plays an important role in the proof of our main goal. As almost always generalization helps a lot.
forall m n : nat, Nat.even (m * n) = Nat.even m || Nat.even nforall m n : nat, Nat.even (m * n) = Nat.even m || Nat.even nm: nat
IHm: forall n : nat, Nat.even (m * n) = Nat.even m || Nat.even n
IHm0: forall n : nat, Nat.even (S m * n) = Nat.even (S m) || Nat.even nforall n : nat, Nat.even (n + (n + m * n)) = Nat.even m || Nat.even nm: nat
IHm: forall n : nat, Nat.even (m * n) = Nat.even m || Nat.even n
IHm0: forall n : nat, Nat.even (S m * n) = Nat.even (S m) || Nat.even n
n: natNat.even (n + (n + m * n)) = Nat.even m || Nat.even nnow rewrite even_add_mul2. Qed.m: nat
IHm: forall n : nat, Nat.even (m * n) = Nat.even m || Nat.even n
IHm0: forall n : nat, Nat.even (S m * n) = Nat.even (S m) || Nat.even n
n: natNat.even (2 * n + m * n) = Nat.even m || Nat.even n
Now, the proof of the goal is trivial
forall n : nat, Nat.even (n * S n) = truenow rewrite even_mult, even_S, orb_negb_r. Qed.n: natNat.even (n * S n) = true
Can someone give a hint on how to prove this using a "beginner's" subset of Coq?
You can consider this a hint, since it reveals the general structure of a possible proof. The automatic tactics may be replaced by the "manual" tactics like with rewrite, apply, destruct and so on.
Answer (ejgallego)
I'd like to contribute a shorter proof using the mathcomp lib:
n: nat~~ odd (n * n.+1)by rewrite oddM andbN. Qed.n: nat~~ odd (n * n.+1)
oddM is proved by simple induction, as well as oddD.
A: The definition of odd here has different structure comparing to even in the question, that's why simple induction works well in this case.
Answer (Anton Trunov)
Another version, in the spirit of @ejgallego's answer. Let's give another definition for the even predicate. The purpose of this is to make proofs by simple induction easy, so there is no need of using pair_induction. The main idea is that we are going to prove some properties of even2 and then we'll use the fact that Nat.even and even2 are extensionally equal to transfer the properties of even2 onto Nat.even.
Require Import Coq.Bool.Bool. Fixpoint even2 (n : nat) : bool := match n with | O => true | S n' => negb (even2 n') end.
Let's show that Nat.even and even2 are extensionally equal.
n: natNat.even (S n) = negb (Nat.even n)n: natNat.even (S n) = negb (Nat.even n)apply negb_sym; assumption. Qed.n: nat
IHn: Nat.even (S n) = negb (Nat.even n)Nat.even (S (S n)) = negb (Nat.even (S n))n: natNat.even n = even2 nn: natNat.even n = even2 nnow rewrite even_S, IHn. Qed.n: nat
IHn: Nat.even n = even2 nNat.even (S n) = even2 (S n)
Some distribution lemmas for even2:
m, n: nateven2 (m + n) = negb (xorb (even2 m) (even2 n))m, n: nateven2 (m + n) = negb (xorb (even2 m) (even2 n))n: nateven2 n = negb (if even2 n then false else true)m, n: nat
IHm: even2 (m + n) = negb (xorb (even2 m) (even2 n))negb (even2 (m + n)) = negb (xorb (negb (even2 m)) (even2 n))now destruct (even2 n).n: nateven2 n = negb (if even2 n then false else true)m, n: nat
IHm: even2 (m + n) = negb (xorb (even2 m) (even2 n))negb (even2 (m + n)) = negb (xorb (negb (even2 m)) (even2 n))now destruct (even2 m); destruct (even2 n). Qed.m, n: nat
IHm: even2 (m + n) = negb (xorb (even2 m) (even2 n))negb (negb (xorb (even2 m) (even2 n))) = negb (xorb (negb (even2 m)) (even2 n))m, n: nateven2 (m * n) = even2 m || even2 nm, n: nateven2 (m * n) = even2 m || even2 nm, n: nat
IHm: even2 (m * n) = even2 m || even2 neven2 (n + m * n) = negb (even2 m) || even2 nnow destruct (even2 m); destruct (even2 n). Qed.m, n: nat
IHm: even2 (m * n) = even2 m || even2 nnegb (xorb (even2 n) (even2 m || even2 n)) = negb (even2 m) || even2 n
Finally, we are able to prove our goal, using the equality between Nat.even and even2.
forall n : nat, Nat.even (n * S n) = truenow rewrite even_equiv_even2, even2_distr_mult, orb_negb_r. Qed.n: natNat.even (n * S n) = true
Answer (Anton Trunov)
A short version that makes use of the standard library:
Require Import Coq.Arith.Arith.forall n : nat, Nat.even (n * S n) = truenow rewrite Nat.even_mul, Nat.even_succ, Nat.orb_even_odd. Qed.n: natNat.even (n * S n) = true
Answer (Olivier Verdier)
For what it's worth, here is my take on the solution. The essential idea is, instead of proving a predicate P n, prove instead P n /\ P (S n), which is equivalent, but the second formulation allows to use simple induction.
Here is the complete proof:
Require Import Nat. Require Import Lia. Definition claim n := even (n * (S n)) = true. (* A technical Lemma, needed in the proof *)forall n m : nat, even n = true -> even (n + 2 * m) = trueforall n m : nat, even n = true -> even (n + 2 * m) = truen, m: nat
H: even n = trueeven (n + 2 * m) = truen: nat
H: even n = trueeven (n + 2 * 0) = truen, m: nat
H: even n = true
IHm: even (n + 2 * m) = trueeven (n + 2 * S m) = truen: nat
H: even n = trueeven (n + 2 * 0) = truereplace (n + 0) with n; intuition.n: nat
H: even n = trueeven (n + 0) = truereplace (n + 2 * S m) with (S (S (n + 2 * m))); [intuition | lia]. Qed. (* A simple identity, that Coq needs help to prove *)n, m: nat
H: even n = true
IHm: even (n + 2 * m) = trueeven (n + 2 * S m) = true(* (n+2)*(n+3) = (n+1)*(n+2) + 2*(n+2) *)forall n : nat, S (S n) * S (S (S n)) = S n * S (S n) + 2 * S (S n)forall n : nat, S (S n) * S (S (S n)) = S n * S (S n) + 2 * S (S n)n: natS (S n) * S (S (S n)) = S n * S (S n) + 2 * S (S n)n: natS (S n) * (S n + 2) = S n * S (S n) + 2 * S (S n)n, m: nat
Heqm: m = S (S n)m * (S n + 2) = S n * m + 2 * mintuition. Qed. (* The claim to be proved by simple induction *)n, m: nat
Heqm: m = S (S n)(S n + 2) * m = S n * m + 2 * mforall n : nat, claim n /\ claim (S n)forall n : nat, claim n /\ claim (S n)n: natclaim n /\ claim (S n)n: nateven (n * S n) = true /\ even (S n * S (S n)) = trueeven (0 * 1) = true /\ even (1 * 2) = truen: nat
IHn: even (n * S n) = true /\ even (S n * S (S n)) = trueeven (S n * S (S n)) = true /\ even (S (S n) * S (S (S n))) = trueintuition.even (0 * 1) = true /\ even (1 * 2) = truen: nat
IHn: even (n * S n) = true /\ even (S n * S (S n)) = trueeven (S n * S (S n)) = true /\ even (S (S n) * S (S (S n))) = truen: nat
H: even (n * S n) = true
H0: even (S n * S (S n)) = trueeven (S (S n) * S (S (S n))) = trueapply tech; auto. Qed.n: nat
H: even (n * S n) = true
H0: even (S n * S (S n)) = trueeven (S n * S (S n) + 2 * S (S n)) = true