Unfolding a sum and making it match hypotheses - coq

I've unfolded everything except the times 6, but I'm having trouble getting rid of the extra "+1" which is preventing me from rewriting
1 subgoal
n : nat
IHn : 6 * sum_n2 n = n * (n + 1) * (2 * n + 1)
Sn : S n = n + 1
______________________________________(1/1)
6 * S (n + n * (n + 1) + sum_n2 n) = (n + 1) * (n + 1 + 1) * (2 * (n + 1) + 1)

This looks like a tutorial exercise, so this depends a bit on which lemmas you have. Coq has a search function to help you find lemmas.
Below is an example on how you would solve this using standard library lemmas - which might not work for you, e.g. early SF chapters have their own nat definitions and lemmas. But the Search function should show you equivalent lemmas you have.
Require Import PeanoNat.
Axiom sum_n2: nat->nat.
Example E1 : forall (n : nat) (IHn : 6 * sum_n2 n = n * (n + 1) * (2 * n + 1)),
6 * S (n + n * (n + 1) + sum_n2 n) = (n + 1) * (n + 1 + 1) * (2 * (n + 1) + 1).
Proof.
intros.
Search (S _) (_ + 1).
rewrite <- (Nat.add_1_r (n + n * (n + 1) + sum_n2 n)).
Search (_ * (_ + _)).
rewrite (Nat.mul_add_distr_l 6).
rewrite (Nat.mul_add_distr_l 6).
rewrite IHn.
(* You should do this manually as well - just a preview on how one does this after going through the exercises *)
Require Import Lia.
lia.
This also shows that you can give arguments to lemmas to better control where they are applied.
If you use Coq later, you will just use the lia tactic (for Linear Integer Arithmetic) which can also discharge your goal right away (without the above rewrites). But you should practice and do it manual.
You might want to have a look at the Search function in the manual (https://coq.inria.fr/refman/proof-engine/vernacular-commands.html#coq:cmd.Search).

Related

Cannot rewrite goal with assertion?

I am not sure I understand why in some cases rewriting H works, and in some it doesnt.
Here for example:
Theorem add_assoc2 : forall n m: nat, n + m = m + n.
Proof. intros. rewrite add_comm. reflexivity. Qed.
Theorem plus_4: forall n m p q: nat,
n + (n * p) + m + (m * p) = n + m + (n * p) + (m * p).
Proof.
intros.
assert (H: n * p + m = m + n * p).
{ rewrite <- add_assoc2. reflexivity. }
rewrite H.
Gives:
1 goal
n, m, p, q : nat
H : n * p + m = m + n * p
______________________________________(1/1)
n + n * p + m + m * p = n + m + n * p + m * p
But Coq complains: Found no subterm matching "n * p + m" in the current goal.
Why?
I clearly see one, on the left side. When using induction, rewriting with IHn doesn't pose any problem, even if there are some other terms in front of rewriteable expression.
You can "see" a subterm n * p + m, but this is misleading: Coq doesn't show you the implicit parentheses around all the + expressions.
Use
Set Printing Parentheses.
to make them visible. Your proof state is really:
n, m, p, q : nat
H : ((n * p) + m) = (m + (n * p))
============================
(((n + (n * p)) + m) + (m * p)) = (((n + m) + (n * p)) + (m * p))
Coq was right that there is no subterm that matches H's left hand side expression ((n * p) + m). You need to rewrite using some associativity lemmas to shift the parentheses around.
Also, add_assoc2 is not a good name for a lemma forall n m: nat, n + m = m + n. This is a commutativity property, not associativity.

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.

Writing proofs of simple arithmetic in 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.

Why is following Coq rewrite not applying on right hand side of assumption?

I have following Coq env.
1 subgoals
m : nat
IHm : forall n : nat, n + n = m + m -> n = m
n : nat
H : S (n + S n) = S (m + S m)
ll := ll : forall k : nat, k + S k = S k + k
Doing rewrite ll in H, only changes the LHS S (n + S n) to S (S n + n) but not the RHS S (m + S m). ll should be applicable on all variables of type nat. What is wrong here?
Expanding on Emilio's comment, rewrite H and rewrite H in H' will first find an instantiation for all (dependently) quantified variables of H, and then replace all occurrences* of that instantiated LHS with the RHS. I believe it finds the topmost/leftmost instantiation in the syntax tree. So, for example, if you do this:
Goal forall a b, (forall x, x + 0 = x) -> (a + 0) * (a + 0) * (b + 0) = a * a * b.
intros a b H.
rewrite H.
the rewrite H will choose to instantiate x with a, and the resulting goal will be a * a * (b + 0) = a * a * b. You can prefix the lemma with ! (as in rewrite !H) to mean "rewrite everywhere, picking as many instantiations as you can", or with ? (as in rewrite ?H) to mean try rewrite !H, i.e., you can pick multiple instantiations, and also don't fail if you can't find any.
*There's actually a bit more nuance, which is that the replacement is done in a single pass with rewrite H and in multiple passes with rewrite ?H and rewrite !H. This only shows up when the first replacement(s) expose other replacement locations that weren't previously available. This shows up, for example, if you rewrite with a + 0 = a in the goal (a + 0) + 0 = a; rewrite H leaves the goal a + 0 = 0.

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.