I've been learning about Coq's tactics and familiarizing myself with the system by reproving basic facts about natural numbers.
I've been trying to avoid using the theorems that are already proven in the library, and reproving things like the associativity of multiplication, etc.
However, I've been stymied in a couple of cases, where I have a property for n m:nat that I want to prove, but when I try to do induction on both n and m, the structure of the inductive hypothesises is useless for trying to prove the property.
I proved n = m -> o * n = o * m very easily:
Theorem times_alg_left : forall n m o:nat, n = m -> o * n = o * m.
intros n m o H.
rewrite H; reflexivity.
Defined.
But trying to prove S o * n = S o * m -> n = m completely flumoxed me. I decided, after considerable struggles, to try to prove 2 * n = 2 * m -> n = m, but that was no easier.
I end up with situations like this:
Theorem m2_eq : forall n m:nat, 2 * n = 2 * m -> n = m.
intros n m H.
induction n.
destruct m.
reflexivity.
discriminate.
induction m.
discriminate.
1 subgoal
n, m : nat
H : 2 * S n = 2 * S m
IHn : 2 * n = 2 * S m -> n = S m
IHm : 2 * S n = 2 * m -> (2 * n = 2 * m -> n = m) -> S n = m
______________________________________(1/1)
S n = S m
I've got 2 * S n = 2 * S m, but my inductive premises are talking about 2 * n = 2 * S m and 2 * S n = 2 * m.
I can't make anything happen from this situation.
Similarly, I started trying to proof things about Nat.sub and less than or equal to get around this limitation, but I ran into the same situation.
Theorem sub0_imp_le : forall n m:nat, n - m = 0 -> n <= m.
intros n m H.
induction n; induction m.
apply le_n.
apply le_0.
rewrite sub0 in H.
discriminate.
1 subgoal
n, m : nat
H : S n - S m = 0
IHn : n - S m = 0 -> n <= S m
IHm : S n - m = 0 -> (n - m = 0 -> n <= m) -> S n <= m
______________________________________(1/1)
S n <= S m
But I'm in the same pickle where my inductive premises are worthless.
How do I structure my tactics to solve these type of theorems, with 2 nat variables, and some kind of equality or subtraction situation going on?
You need to do induct on one number while generalizing the other, using the generalize dependent tactic, for instance. This is explained in detail in the Software Foundations book.
Using the Software Foundations book Arthur mentioned, I found the exmaple in question. I need to not introduce m before doing induction on n. I needed to do induction on n first instead, then introduce m.
https://softwarefoundations.cis.upenn.edu/lf-current/Tactics.html#lab143
Theorem times_alg_rem_left : forall n o m:nat, (S o) * n = (S o) * m -> n = m.
intros n o.
induction n.
simpl.
intros m eq.
destruct m.
reflexivity.
rewrite (timesz o) in eq.
simpl in eq.
discriminate.
intros m eq.
destruct m.
rewrite (timesz (S o)) in eq.
inversion eq.
apply f_equal.
apply IHn.
rewrite (times_nSm (S o) n) in eq.
rewrite (times_nSm (S o) m) in eq.
apply plus_alg_rem_right in eq.
assumption.
Defined.
Related
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.
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.
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 can I prove this lemma:
Lemma even_plus_split n m :
even (n + m) -> even n /\ even m \/ odd n /\ odd m.
These are the only libraries and definition that can be used:
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.
I am new to Coq and confused about it. Can you give me a solution? Thanks in advance!
the code so far:
Lemma even_plus_split n m :
even (n + m) -> even n /\ even m \/ odd n /\ odd m.
Proof.
intros.
unfold even.
unfold even in H.
destruct H as [k H].
unfold odd.
exists (1/2*k).
result so far:
1 subgoal
n, m, k : nat
H : n + m = 2 * k
______________________________________(1/1)
(exists k0 : nat, n = 2 * k0) /\ (exists k0 : nat, m = 2 * k0) \/
(exists k0 : nat, n = 2 * k0 + 1) /\ (exists k0 : nat, m = 2 * k0 + 1)
I just want to make k0 equals to 1/2*k, and therefore I suppose it would make sense, but I can't do that.
I just want to make k0 equals to 1/2*k, and therefore I suppose it would make sense, but I can't do that.
There is a function called Nat.div2, which divides a natural number by 2. Running Search Nat.div2.
Nat.le_div2: forall n : nat, Nat.div2 (S n) <= n
Nat.lt_div2: forall n : nat, 0 < n -> Nat.div2 n < n
Nat.div2_decr: forall a n : nat, a <= S n -> Nat.div2 a <= n
Nat.div2_wd: Morphisms.Proper (Morphisms.respectful eq eq) Nat.div2
Nat.div2_spec: forall a : nat, Nat.div2 a = Nat.shiftr a 1
Nnat.N2Nat.inj_div2: forall a : N, N.to_nat (N.div2 a) = Nat.div2 (N.to_nat a)
Nnat.Nat2N.inj_div2: forall n : nat, N.of_nat (Nat.div2 n) = N.div2 (N.of_nat n)
Nat.div2_double: forall n : nat, Nat.div2 (2 * n) = n
Nat.div2_div: forall a : nat, Nat.div2 a = a / 2
Nat.div2_succ_double: forall n : nat, Nat.div2 (S (2 * n)) = n
Nat.div2_odd: forall a : nat, a = 2 * Nat.div2 a + Nat.b2n (Nat.odd a)
Nat.div2_bitwise:
forall (op : bool -> bool -> bool) (n a b : nat),
Nat.div2 (Nat.bitwise op (S n) a b) = Nat.bitwise op n (Nat.div2 a) (Nat.div2 b)
Of these, the most promising seems to be Nat.div2_odd: forall a : nat, a = 2 * Nat.div2 a + Nat.b2n (Nat.odd a). If you pose proof this lemma, you can destruct (Nat.odd a) and use simpl to get that either a = 2 * Nat.div2 a or a = 2 * Nat.div2 a + 1, for whichever a you choose.
This may not give you a solution directly (I am not convinced that setting k0 to k / 2 is the right decision), but if it does not, you should make sure that you can figure out how to prove this fact on paper before you try it in Coq. Coq is very good at making sure that you don't make any jumps of logic that you're not allowed to make; it's extremely bad at helping you figure out how to prove a fact that you don't yet know how to prove.
Everybody who tries to answer seems to be dancing around the fact that you actually chose a wrong direction for this proof. Here is a example:
if n = 601 and m = 399, then n + m = 2 * 500,
n = 2 * 300 + 1, and m = 2 * 199 + 1.
Between 500, 300, and 199, the 1/2 ratio does not appear anywhere.
Still the statement (even n /\ even m) / (odd n /\ odd m) is definitely true.
So for now, you have more a math problem than a Coq problem.
You have to make a proof for universally quantified numbers n and m, but somehow this proof should also work for specific choices of these numbers. So in a sense you can make the mental exercise of testing your proof on examples.
I had a problem finishing the proof of this Lemma :
Lemma l1 : forall m n : nat, m * m = n * n -> m = n.
any hint would be very helpful.
I started the proof like this:
Require Import Arith Omega Nat.
Lemma l1 : forall m n : nat, m * m = n * n -> m = n.
Proof.
intros.
destruct (Nat.eq_dec m n ).
trivial.
induction n.
induction m.
auto.
simpl in H;congruence.
A hint: take the square root of the both sides of your hypothesis, then it leads immediately to the conclusion. For the square root function use Nat.sqrt from the Arith module.
First solution:
Require Import Coq.Arith.Arith.
Lemma l1 : forall m n : nat, m * m = n * n -> m = n.
Proof.
intros m n H. apply (f_equal Nat.sqrt) in H.
now repeat rewrite Nat.sqrt_square in H.
Qed.
Second solution:
The lemma can also be proved using the nia tactic, an incomplete proof procedure for integer non-linear arithmetic:
Require Import Psatz.
Lemma l1 m n : m * m = n * n -> m = n.
Proof. nia. Qed.
Third solution:
Let's use a couple times the standard Nat.square_le_simpl_nonneg lemma:
forall n m : nat, 0 <= m -> n * n <= m * m -> n <= m
Here we go:
Require Import Coq.Arith.Arith.
Lemma l1 (m n : nat) :
m * m = n * n -> m = n.
Proof with (auto with arith).
intros H.
pose proof (Nat.eq_le_incl _ _ H) as Hle.
pose proof (Nat.eq_le_incl _ _ (eq_sym H)) as Hge.
apply Nat.square_le_simpl_nonneg in Hle...
apply Nat.square_le_simpl_nonneg in Hge...
Qed.
Fourth solution:
Here is a classical proof, based on the following equality
m * m - n * n = (m + n) * (m - n)
Firstly, we'll need a helper lemma, proving the above equality (Surprisingly, it seems that the standard library is lacking this lemma):
Require Import Coq.Arith.Arith.
(* can be proved using `nia` tactic *)
Lemma sqr_diff (m n : nat) :
m * m - n * n = (m + n) * (m - n).
Proof with (auto with arith).
destruct (Nat.lt_trichotomy m n) as [H | [H | H]].
- pose proof H as H'. (* copy hypothesis *)
apply Nat.square_lt_mono_nonneg in H...
repeat match goal with
h : _ < _ |- _ => apply Nat.lt_le_incl, Nat.sub_0_le in h
end.
rewrite H, H'...
- now rewrite H, !Nat.sub_diag.
- rewrite Nat.mul_add_distr_r, !Nat.mul_sub_distr_l.
rewrite Nat.add_sub_assoc...
replace (n * m) with (m * n) by apply Nat.mul_comm.
rewrite Nat.sub_add...
Qed.
And now we can prove the main lemma:
Lemma l1 (m n : nat) :
m * m = n * n -> m = n.
Proof.
intros H.
pose proof (Nat.eq_le_incl _ _ H) as Hle;
pose proof (Nat.eq_le_incl _ _ (eq_sym H)) as Hge; clear H.
rewrite <- Nat.sub_0_le in *.
rewrite sqr_diff in *.
destruct (mult_is_O _ _ Hle) as [H | H].
now destruct (plus_is_O _ _ H); subst.
destruct (mult_is_O _ _ Hge) as [H' | H'].
now destruct (plus_is_O _ _ H'); subst.
rewrite Nat.sub_0_le in *.
apply Nat.le_antisymm; assumption.
Qed.