Writing proofs of simple arithmetic in Coq - coq

I would like to prove simple things like for every natural number n, there exists a natural number k such that:
(2*n + 1)^2 = 8*k + 1
How does one go about such a proof? I thought of dividing it into cases when n is odd or even, but I do not know how to do so in Coq. Also, is there an inbuilt power (exponent) operator in Coq?

Yes, there are many built-in functions, you just need the right set of imports or open the right notation scope.
One easy way to do the proof is to use induction and some automation like ring, omega or lia tactics.
From Coq Require Import Arith Psatz.
Goal forall n, exists k, (2*n + 1)^2 = 8*k + 1.
Proof.
induction n as [| n [m IH]].
- now exists 0.
- exists (S n + m). rewrite Nat.pow_2_r in *. lia.
Qed.

Here is an alternative proof, using the same idea as found in the proof by #Yves:
From Coq Require Import Arith Psatz.
Fact exampleNat n : exists k, (2 * n + 1) ^2 = 8 * k + 1.
Proof.
exists (n * (S n) / 2).
assert (H : Nat.even (n * (S n)) = true) by
now rewrite Nat.even_mul, Nat.even_succ, Nat.orb_even_odd.
apply Nat.even_spec in H as [m H]; rewrite (Nat.mul_comm 2) in H.
rewrite H, Nat.div_mul, Nat.pow_2_r; lia.
Qed.
Observe that this proof schema works for the integer numbers too provided you change everything from namespace Nat to Z (S to Z.succ, etc.).

We can follow the initial plan suggested in the question of reasoning by cases on whether the input is odd or even, only representing parity by the value of n mod 2 and using a boolean equality test to express the alternative.
The proof can also be made with relative integers instead of natural numbers.
From Coq Require Import ZArith Psatz.
Open Scope Z_scope.
Lemma example n : exists k, (2 * n + 1) ^2 = 8 * k + 1.
Proof.
assert (vn : n = 2 * (n / 2) + n mod 2) by now apply Z_div_mod_eq.
destruct (n mod 2 =? 0) eqn: q.
- rewrite Z.eqb_eq in q; rewrite vn, q.
exists ((2 * (n / 2) + 1) * (n / 2)); ring.
- enough (vm : n mod 2 = 1)
by now rewrite vn, vm; exists (2 * (n / 2) ^ 2 + 3 * (n / 2) + 1); ring.
rewrite Z.eqb_neq in q.
assert (0 <= n mod 2 < 2) by now apply Z_mod_lt.
lia.
Qed.
This proof is not as nice and elementary as the one by #Anton on Jan 24th, though.

Related

How to show injectivity of a function?

Here's what I'm trying to prove: Theorem add_n_injective : forall n m p, n + m = n + p -> m = p.
The + is notation for plus, defined as in https://softwarefoundations.cis.upenn.edu/lf-current/Basics.html:
Fixpoint plus (n : nat) (m : nat) : nat :=
match n with
| O ⇒ m
| S n' ⇒ S (plus n' m)
end.
In Agda, one can do cong (n + _) to use the fact that n + m = n + p for any n m p.
Coq's built-in tactices injection and congruence both seemed promising, but they only work for constructors.
I tried the following strategy and kept hitting weird errors or getting stuck:
make an inductive type for bundling up a proof of (n + m = s): Sum (n m s)
use the congruence tactic in a lemma that shows Sum (n m s) = Sum (n p s)
use constructing Sums, destruct, and the lemma to show that n + m = n + p
Is there an easier way to prove this? I feel like there must be some built-in tactic I'm missing or some trickery with unfold.
UPDATE
Got it:
Theorem add_n_injective : forall n m p, n + m = n + p -> m = p.
Proof.
intros. induction n.
- exact H.
- apply IHn. (* goal: n + m = n + p *)
simpl in H. (* H: S (n + m) = S (n + p) *)
congruence.
Qed.
Thanks #ejgallego
Injectivity of plus is not an "elementary" statement, given that the plus function could be arbitrary (and non-injective)
I'd say the standard proof does require induction on the left argument, indeed using this method the proof quickly follows.
You will need injection when you arrive to a goal of the form S (n + m) = S (n + p) to derive the inner equality.

How to prove mathematical induction formulae in LEAN theorem prover?

Can anyone help me understand how to write the proof of a simple result that can be easily obtained by induction, for example the formula for the sum of the first n natural numbers: 1+2+...+n = n(n+1)/2, using the LEAN theorem prover?
Here is my proof. You'll need mathlib for it to work.
import algebra.big_operators tactic.ring
open finset
example (n : ℕ) : 2 * (range (n + 1)).sum id = n * (n + 1) :=
begin
induction n with n ih,
{ refl },
{ rw [sum_range_succ, mul_add, ih, id.def, nat.succ_eq_add_one],
ring }
end
range (n + 1) is the set of natural numbers less than n + 1, i.e. 0 to n.
I used the finset.sum function. If s is a finset and f is a function, then
s.sum f is $\sum_{x \in s} f(x)$.
The induction tactic does induction. There are then two cases. The case n = 0 can be done with refl since this is nothing more than a computation.
The inductive step can be done with rw. Using a VSCode you can click after each comma in my proof to see what each rw does. This gets it into a form that the ring tactic will solve.

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

how to rearrange terms in Coq using plus communtativity and associativity?

I have a general question about how to rearrange terms in Coq. For example, if we have a term m + p + n + p, humans can quickly re-arrange the terms to something like m + n + p + p (implicitly using plus_comm and plus_assoc). How do we do this efficiently in Coq?
For a (silly) example,
Require Import Coq.Arith.Plus.
Require Import Coq.Setoids.Setoid.
Theorem plus_comm_test: forall n m p: nat,
m + p + (n + p) = m + n + 2 * p.
Proof. intros. rewrite plus_assoc. simpl. rewrite <- plus_n_O.
Now, we have
1 subgoals
...
______________________________________(1/1)
m + p + n + p = m + n + (p + p)
My question is:
How do I rewrite the LHS to m + n + p + p effectively?
I tried to use rewrite plus_comm at 2, but it gives an error Nothing to rewrite. Simply using rewrite plus_comm changes the LHS to p + m + n + p.
Any suggestions on effective rewrites are also welcome.
Thanks.
In this particular case (linear arithmetic over the integers), you can just use the omega tactic:
Require Import Omega.
Theorem plus_comm_test: forall n m p: nat,
m + p + (n + p) = m + n + 2 * p.
Proof. intros; omega. Qed.
However, there are situations where omega is not enough. In those cases, the standard rewrite tactic is not very convenient. The Ssreflect library comes with its own version of the rewrite tactic, that works much better for tasks such as rewriting on sub-terms of your goal. For instance:
Require Import Ssreflect.ssreflect Ssreflect.ssrfun Ssreflect.ssrbool.
Require Import Ssreflect.ssrnat.
Theorem plus_comm_test: forall n m p: nat,
m + p + (n + p) = m + n + 2 * p.
Proof.
move=> n m p.
by rewrite -addnA [p + _]addnC -[_ + p]addnA addnn -mul2n addnA.
Qed.
The annotations in square brackets, such as [p + _], provide patterns that help the rewrite tactic figure out where to act. The addn* lemmas and friends are Ssreflect's own version of the standard arithmetic results over the natural numbers.
As Arthur says sometimes omega is not enough, but I sometimes use it for simple steps like this.
Require Import Omega.
Theorem test: forall a b c:nat, a + b + 2 * c = c + b + a + c.
intros.
replace (c + b + a) with (a + b + c) by omega.
replace (a + b + c + c) with (a + b + (c + c)) by omega.
replace (c + c) with (2 * c) by omega.
reflexivity.
Qed.
This is a silly example, because omega would have solved it all in one go, but sometimes you want to rewrite things inside functions that omega can't reach into without a little help...
The ring tactic is able to prove equality of these rearrangements.
Using your example:
Require Import ZArith.
Open Scope Z_scope.
(* Both "ring" and "omega" can prove this. *)
Theorem plus_comm_test : forall n m p : Z,
m + p + (n + p) = m + n + 2 * p.
Proof.
intros.
ring.
Qed.
ring works on the integers, but I don't think it works on the natural numbers.
However, ring is able to prove some identities that omega cannot prove. (The docs say, "Multiplication is handled by omega but only goals where at least one of the two multiplicands of products is a constant are solvable. This is the restriction meant by "Presburger arithmetic".")
For example:
(* "ring" can prove this but "omega" cannot. *)
Theorem rearrange_test : forall a b c : Z,
a * (b + c) = c*a + b*a.
Proof.
intros.
ring.
Qed.

Proving st X + st Y = st Y + (st X - 1) + 1 using Coq

Just like the title says, I'm looking for a way to prove st X + st Y = st Y + (st X - 1) + 1 in Coq. I've been trying applying various combinations of plus_comm, plus_assoc and plus_permute but I haven't been able to make it go through. Any suggestions?
Here is the goal window:
3 subgoal
n : nat
m : nat
st : state
H : st Y + st X = n + m /\ beval st (BNot (BEq (AId X) (ANum 0))) = true
______________________________________(1/3)
st Y + 1 + (st X - 1) = n + m
For integers, either ring or omega should be able to solve such a goal. It can also be done manually. It helps to disable notations so that function names appear (in order use SearchAbout to find useful lemmas). The following is probably not the shortest possible proof, just the first I found:
Require Import ZArith.
Lemma simple: forall x y, (x + y)%Z = (y + (x - 1) + 1)%Z.
intros.
rewrite Z.add_sub_assoc.
replace ((y + x)%Z) with ((x + y)%Z).
Focus 2.
rewrite Z.add_comm.
reflexivity.
set (t := ((x + y)%Z)).
replace (1%Z) with (Z.succ 0).
Focus 2.
symmetry.
apply Z.one_succ.
rewrite Zminus_succ_r.
rewrite Z.add_succ_r.
rewrite <- Zminus_0_l_reverse.
rewrite <- Zplus_0_r_reverse.
rewrite Z.succ_pred.
reflexivity.
Qed.
For those looking to use omega as a quick-fix, here's one way to get the goal into a form where it can be applied:
inversion H.
inversion H1.
rewrite negb_true_iff in H3.
apply beq_nat_false in H3.
omega.
For why omega works after we do this and not when the goal was in the original state, here is a great answer by Github user jaewooklee93:
"You don't need to think about plus_comm or similar lemmas here, because omega can solve those easy problems. Your goals are almost trivial, but the reason why omega hesistates to clear the goals is just because the minus between nat is not the same as the one we already know; 2-5=0, since there is no notion of negative in nat. So if you don't provide the fact that st X is greater than zero, omega cannot clear the goal for you. But you already have that condition in H1. Therefore, the only thing you should do is to simplify H1 and apply lemmas to H1 to make it st X<>0 .Then omega can properly work."