How to show injectivity of a function? - coq

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.

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.

How to prove `plus_le_compat_l : forall n m p, n <= m -> p + n <= p + m.`

another problem from SFv1 which got me stuck.
The theorem is as follows:
Theorem plus_le_compat_l : forall n m p,
n <= m ->
p + n <= p + m.
I have tried several avenues so far, the one that got me the furthest was to introduce n and start induction on it. The base case is rather trivial (intros m p H. rewrite add_0_r. apply le_plus_l.).
As for the inductive step, I have tried to destruct p, which gives me two subcases. For the first where p = O, it's super easy to prove by applying H. When p = S n I get stuck. Here's the full proof so far:
Theorem plus_le_compat_l : forall n m p,
n <= m ->
p + n <= p + m.
Proof.
intros n.
induction n as [| n' IHn'].
- intros m p H. rewrite add_0_r. apply le_plus_l.
- destruct p eqn:E.
+ intros H. simpl. apply H.
+ intros H. simpl. apply n_le_m__Sn_le_Sm.
And my current goal:
n' : nat
IHn' : forall m p : nat, n' <= m -> p + n' <= p + m
m, p, n : nat
E : p = S n
H : S n' <= m
============================
n + S n' <= n + m
I tried a trivial manipulation to turn the LHS of the inequality into n' + S n which lets me rewrite the S n as p, but that also doesn't take me anywhere.
Any hints here are highly appreciated :-)
Thanks
PS: I have tried to apply a previously proved theorem without success:
Theorem add_le_cases : forall n m p q,
n + m <= p + q -> n <= p \/ m <= q.
I think in this case using induction on p is the way to go, and both goals should be quite ok to prove – the induction one by a use of le_n_S.

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

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.