What does IH cannot be used as a hint. in Coq mean when using eauto giving it the induction hypothesis directly? - coq

Saw related question Lemma cannot be used as a hint but didn't seem super useful + seemed better to ask new that ask unrelated questions to posters there. I tried doing the trivial lemma:
From mathcomp Require Import all_ssreflect.
Require Import ZArith.
From Hammer Require Import Tactics.
From Hammer Require Import Hammer.
Theorem n_plus_0_eq_n_sketch1:
forall n:nat,
n + 0 = n.
Proof.
have IH: forall P : nat -> Prop, P 0 -> (forall n : nat, P n -> P n.+1) -> forall n : nat, P n. by apply nat_ind. (* succeeds *)
(* close target with guessed lemmas **)
(* by sauto use: IH. *) (* fails *)
by eauto using IH. (* Gives error, IH cannot be used as a hint. *)
but the eauto tactic gives the error:
IH cannot be used as a hint.
Why is that? What's wrong with the lemma I am giving it?
I've had it work in other cases so I'm puzzled:
Theorem add_comm_eauto_using:
forall n m: nat,
n + m = m + n.
Proof.
intros.
assert (H: forall n, n + 0 = n) by eauto using n_plus_zero_eq_n.
assert (H': forall n m, S (n + m) = n + S m) by eauto using Sn_plus_m_eq_n_plus_Sm.
induction n.
- eauto using H, H'.
-
(* auto using IHn, H, H'. *)
simpl.
(* auto using IHn, H, H'. *)
rewrite IHn.
auto using H, H'.
Qed.
Is it some detail of how eauto like it can't unify the goal and my lemma or something?
ref:
Lemma cannot be used as a hint

eauto works by matching head-symbols. Unfortunately the
head symbol of IH is a variable P so this is why you are getting an error (see here)
This is accepted but does not solve the goal
have IH1 := IH (fun n => n + 0 = n).
eauto using IH1.

Related

Using a theorem on integer numbers for proving a theorem on natural numbers

I'm not a mathematician, but I take interest in the topic and the use of proof assistants like Coq. I still need to learn a lot on how Coq works. As an exercise, I would like to proof that:
forall n : nat, n > 0 -> Nat.Odd n <-> Nat.Odd (5 * n + 6).
I failed to proof this directly and therefore thought of taking a roundtrip via the integers:
Require Import ZArith.
Require Import Lia.
Theorem T1 : forall n : Z,
Z.Odd n <-> Z.Odd (5 * n + 6).
Proof.
unfold Z.Odd.
intros. split.
- intros. destruct H as [x G]. rewrite G. exists ((5 * x + 5)%Z). lia.
- intros. destruct H as [x G]. exists ((-2 * n - 3 + x)%Z). lia.
Qed.
I would now like to use this result to proof the initial theorem. Unfortunately, I get stuck in relating Nat.Odd to Z.Odd and the eventual application of T1:
Lemma L1 : forall n : nat,
Z.Odd (Z.of_nat n) <-> Nat.Odd n.
Proof.
intros.
Admitted.
Theorem T2 : forall n : nat,
n > 0 -> Nat.Odd n <-> Nat.Odd (5 * n + 6).
Proof.
intros.
pose proof T1 as G.
rewrite <- L1.
rewrite <- L1.
Admitted.
I would like to know if I'm on the right track here. I'm also seeking for some hints on how to eventually proof T2 using the result T1 (assuming that this is actually a sensible approach to proving the initial goal using Coq).
Any help is appreciated.
There is probably a way to prove this goal staying in Nat (by using a divisibility argument) but this approach is also feasible.
The lemma L1 on which you got stuck can actually be solved in a similar fashion as the theorem T1, leveraging lia for finding the right lemmas. Then, the only thing in your way to apply T1 in the course of proving T2 is to show that Z.of_nat respects addition and multiplication: you can rely another time on lia. All together you obtain the following proof:
From Coq Require Import ZArith Arith.PeanoNat Psatz.
Theorem T1 : forall n : Z, Z.Odd n <-> Z.Odd (5 * n + 6).
Admitted.
Lemma L1 (n : nat) : Z.Odd (Z.of_nat n) <-> Nat.Odd n.
Proof.
split.
- intros [x?]. exists (Z.to_nat x). lia.
- intros [x?]. exists (Z.of_nat x). lia.
Qed.
Theorem T2 (n : nat) : Nat.Odd n <-> Nat.Odd (5 * n + 6).
Proof.
do 2 rewrite <- L1.
(* We need to massage slightly the goal to apply T1 *)
assert (Z.of_nat (5*n + 6) = (5*(Z.of_nat n)+6)%Z) as -> by lia.
apply T1.
Qed.

Induction on evidence for the "less than" relation in coq

I am working on the proof of the following theorem Sn_le_Sm__n_le_m in IndProp.v of Software Foundations (Vol 1: Logical Foundations).
Theorem Sn_le_Sm__n_le_m : ∀n m,
S n ≤ S m → n ≤ m.
Proof.
intros n m HS.
induction HS as [ | m' Hm' IHm'].
- (* le_n *) (* Failed Here *)
- (* le_S *) apply IHSm'.
Admitted.
where, the definition of le (i.e., ≤) is:
Inductive le : nat → nat → Prop :=
| le_n n : le n n
| le_S n m (H : le n m) : le n (S m).
Notation "m ≤ n" := (le m n).
Before induction HS, the context as well as the goal is as follows:
n, m : nat
HS : S n <= S m
______________________________________(1/1)
n <= m
At the point of the first bullet -, the context as well as the goal is:
n, m : nat
______________________________________(1/1)
n <= m
where we have to prove n <= m without any context, which is obviously impossible.
Why does it not generate S n = S m (and then n = m) for the le_n case in induction HS?
The main problem here -I think- is it is impossible to prove the Theorem using induction on HS as there is no way to say something about n with only hypothesis about S n because non of the constructors of le do not change the value of n. But anyway the reason that after first bullet - there is no assumption is because calling induction has the effect of replacing all occurrences of the property argument by the values that correspond to each constructor and it doesn't help in this case since the term that gets replaced S n is not mentioned anywhere. There are some tricks to avoid this. for example you can replace n with pred(S n) as follows.
Theorem Sn_le_Sm__n_le_m : forall n m,
S n <= S m -> n <= m.
Proof.
intros n m HS.
assert(Hn: n=pred (S n)). reflexivity. rewrite Hn.
assert(Hm: m=pred (S m)). reflexivity. rewrite Hm.
induction HS.
- (* le_n *) apply le_n.
- (* le_S *) (* Stucks! *) Abort.
But as I mentioned above it is impossible to go further. Another way is to use inversion which is smarter but in some cases it may not help since induction hypothesis would be necessary. But it worth to know about it.
Theorem Sn_le_Sm__n_le_m : forall n m,
S n <= S m -> n <= m.
Proof.
intros n m HS.
inversion HS.
- (* le_n *) apply le_n.
- (* le_S *) (* Stucks! *) Abort.
Best way to solve the problem is use of remember tactic as follows.
Theorem Sn_le_Sm__n_le_m : forall n m,
S n <= S m -> n <= m.
Proof.
intros n m HS.
remember (S n) as Sn.
remember (S m) as Sm.
induction HS as [ n' | n' m' H IH].
- (* le_n *)
rewrite HeqSn in HeqSm. injection HeqSm as Heq.
rewrite <- Heq. apply le_n.
- (* le_S *) (* Stucks! *) Abort.
According to Software Foundations (Vol 1: Logical Foundations)
The tactic remember e as x causes Coq to (1) replace all occurrences
of the expression e by the variable x, and (2) add an equation x = e
to the context.
Anyway, although it is impossible to prove the fact using induction on HS -imo-, performing an induction on m will solve the case. (Note the use of inversion.)
Theorem Sn_le_Sm__n_le_m : forall n m,
S n <= S m -> n <= m.
Proof.
intros n.
induction m as [|m' IHm'].
- intros H. inversion H as [Hn | n' contra Hn'].
+ apply le_n.
+ inversion contra.
- intros H. inversion H as [HnSm' | n' HSnSm' Heq].
+ apply le_n.
+ apply le_S. apply IHm'. apply HSnSm'.
Qed.
Just more examples of Kamyar's answer.
Well, let's take a look of le induction scheme :
Compute le_ind.
forall (n : nat) (P : nat -> Prop),
P n ->
(forall m : nat, n <= m -> P m -> P (S m)) ->
forall n0 : nat, n <= n0 -> P n0
P is some proposition that holds one natural number, which means in the case of le_n, our preposition n <= m will be reduced to forall n, n <= m. Indeed, it's the same lemma that we want to prove, however unprovable because there is no premise.
An easy to solve this is doing induction where le_ind doesn't do.
For example :
Theorem Sn_le_Sm__n_le_m' : forall m n,
S n <= S m -> n <= m.
elim.
by intros; apply : Gt.gt_S_le .
intros; inversion H0.
by subst.
by subst; apply : le_Sn_le.
Qed.
Notice that we doing induction by m, and using inversion to generates the two possible construction of le ({x = y} + {x < y}). Optionally, you can use le decidability.
Theorem Sn_le_Sm__n_le_m : forall n m,
S n <= S m -> n <= m.
intros.
generalize dependent n.
elim.
auto with arith.
intros.
have : n <= m.
by apply : H; apply : le_Sn_le.
move => H'.
destruct m.
auto with arith.
destruct (le_lt_eq_dec _ _ H').
assumption.
subst.
(* just prove that there is no S m <= m *)
Qed.
For the sake of your time, coq has the tactic dependent induction that easily solves your goal :
Theorem Sn_le_Sm__n_le_m'' : forall n m,
S n <= S m -> n <= m.
intros.
dependent induction H.
auto.
by apply : (le_Sn_le _ _ H).
Qed.

Stuck proving lemma with unprovable subgoals

I'm trying to prove a lemma that's based on the following definitions.
Section lemma.
Variable A : Type.
Variable P : A -> Prop.
Variable P_dec : forall x, {P x}+{~P x}.
Inductive vector : nat -> Type :=
| Vnil : vector O
| Vcons : forall {n}, A -> vector n -> vector (S n).
Arguments Vcons {_} _ _.
Fixpoint countPV {n: nat} (v : vector n): nat :=
match v with
| Vnil => O
| Vcons x v' => if P_dec x then S (countPV v') else countPV v'
end.
The lemma I'm trying to prove is as follows
Lemma lem: forall (n:nat) (a:A) (v:vector n),
S n = countPV (Vcons a v) -> (P a /\ n = countPV v).
I've tried a lot of things and currently I'm at this point.
Proof.
intros n a v.
unfold not in P_dec.
simpl.
destruct P_dec.
- intros.
split.
* exact p.
* apply eq_add_S.
exact H.
- intros.
split.
The context at this point:
2 subgoals
A : Type
P : A -> Prop
P_dec : forall x : A, {P x} + {P x -> False}
n : nat
a : A
v : vector n
f : P a -> False
H : S n = countPV v
______________________________________(1/2)
P a
______________________________________(2/2)
n = countPV v
My issue is that I seem to be stuck with two subgoals that I can not prove and the available context does not seem to be helpful. Can anyone provide me with some pointers to move on?
EDIT:
I've proven the lemma by contradicting H:
assert (countPV v <= n).
* apply countNotBiggerThanConstructor.
* omega.
Qed.
where countNotBiggerThanConstructor is:
Lemma countNotBiggerThanConstructor: forall {n : nat} (v: vector n), countPV v <= n.
Proof.
intros n v.
induction v.
- reflexivity.
- simpl.
destruct P_dec.
+ apply le_n_S in IHv.
assumption.
+ apply le_S.
assumption.
Qed.
Notice that H can't possibly be true. That is a good thing, if you can prove False, you can prove anything. So I would do contradict H next (and you don't need that last split).
Overall your proof seems a little messy to me. I suggest thinking about how you would prove this lemma on paper and trying to do that in Coq. I am not an expert in Coq, but I think it would also help you realize, that you need to use contradiction in this case.
(Edit: BTW other answers suggesting that this lemma does not hold are wrong, but I can't comment with my 1 reputation)

Proving increasing iota in Coq

I am stuck on a goal.
Assume we have the following definition:
Fixpoint iota (n : nat) : list nat :=
match n with
| 0 => []
| S k => iota k ++ [k]
end.
And we want to prove:
Theorem t1 : forall n, In n (iota n) -> False.
So far, I have managed to the following:
Theorem t1 : forall n, In n (iota n) -> False.
Proof.
intros.
induction n.
- cbn in H. contradiction.
- cbn in H. apply app_split in H.
Focus 2. unfold not. intros.
unfold In in H0. destruct H0. assert (~(n = S n)) by now apply s_inj.
contradiction.
apply H0.
apply IHn.
I used these two lemmas, proofs omitted:
Axiom app_split : forall A x (l l2 : list A), In x (l ++ l2) -> not (In x l2) -> In x l.
Axiom s_inj : forall n, ~(n = S n).
However, I am completely stuck, I need to somehow show that: In n (iota n) assuming In (S n) (iota n).
As you've observed the fact that the n in In n and the one in iota n are in lockstep in your statement makes the induction hypothesis hard to invoke (if not completely useless).
The trick here is to prove a more general statement than the one you are actually interested in which breaks this dependency between the two ns. I would suggest:
Theorem t : forall n k, n <= k -> In k (iota n) -> False.
from which you can derive t1 as a corollary:
Corollary t1 : forall n, In n (iota n) -> False.
intro n; apply (t n n); reflexivity.
Qed.
If you want to peek at the proof of t, you can have a look at this self-contained gist

How to simplify A + 0 > 0 into A > 0?

I'm just a beginner with Coq, and I've been trying to prove a few elementary theorems about natural numbers. I've done a few already, not very elegantly, but completed nether the less. However I'm totally stuck on completing this theorem:
Theorem add_increase: (forall a b: nat, a > 0 -> a + b > b).
Proof.
intros A.
intros B.
intros H.
case B.
Entering this in, I get this output:
2 subgoals
A, B : nat
H : A > 0
______________________________________(1/2)
A + 0 > 0
______________________________________(2/2)
forall n : nat, A + S n > S n
Obviously, the first goal is pretty trivial to simplify to hypothesis H. However, I just can't figure out how to make this straightforward simplification.
One way to simplify this is to use a rather boring lemma
Lemma add_zero_r : forall n, n + 0 = n.
Proof.
intros n. induction n. reflexivity.
simpl. rewrite IHn. reflexivity.
Qed.
and next use this to rewrite your goal:
Theorem add_increase: (forall a b: nat, a > 0 -> a + b > b).
Proof.
intros A.
intros B.
intros H.
case B.
rewrite (add_zero_r A).
assumption.
To finish the other proof case I've used a little lemma and a tactic that eases the task of proving stuff with inequalities over naturals.
First, I've imported Omega library.
Require Import Omega.
Prove another boring fact.
Lemma add_succ_r : forall n m, n + (S m) = S (n + m).
Proof.
intros n m. induction n. reflexivity.
simpl. rewrite IHn. reflexivity.
Qed.
and going back to add_increase prove we have the following goal:
A, B : nat
H : A > 0
============================
forall n : nat, A + S n > S n
That can be solved by:
intros C.
rewrite (add_succ_r A C).
omega.
Again, I've used the previous proved lemma to rewrite the goal. The omega tactic is a very useful one since it is a complete decision procedure for the so called quantifier free Presburger arithmetic, and based on your context, it can solve the goal automagically.
Here's the complete solution to your proof:
Require Import Omega.
Lemma add_zero_r : forall n, n + 0 = n.
Proof.
intros n. induction n. reflexivity.
simpl. rewrite IHn. reflexivity.
Qed.
Lemma add_succ_r : forall n m, n + (S m) = S (n + m).
Proof.
intros n m. induction n. reflexivity.
simpl. rewrite IHn. reflexivity.
Qed.
Theorem add_increase: (forall a b: nat, a > 0 -> a + b > b).
Proof.
intros A.
intros B.
intros H.
case B.
rewrite (add_zero_r A).
assumption.
intros C.
rewrite (add_succ_r A C).
omega.
Qed.
Several common lemmas such as a + 0 = a etc. are put in the hint database arith. With them, auto can usually solve many simple goals of this kind, so use auto with arith.
Require Import Arith.
Theorem add_increase: (forall a b: nat, a > 0 -> a + b > b).
destruct a; intros b H.
- inversion H. (* base case, H: 0 > 0 *)
- simpl. auto with arith.
Qed.
To see which lemmas auto used, you can Print add_increase. In this case, auto used three lemmas, and they can alternatively be given explicitly to auto by auto using gt_le_S, le_lt_n_Sm, le_plus_r.
In general, when you need a lemma that you think ought to have already been proven, you can search for it with SearchAbout. Use _ as a wild card, or ?a as a named wild-card. In your case above you wanted something about adding a zero on the right, so
SearchAbout ( _ + 0 = _ ).
returns
plus_0_r: forall n : nat, n + 0 = n
NPeano.Nat.add_0_r: forall n : nat, n + 0 = n
You can even find a lemma in the library that is close to what you want to prove.
SearchAbout ( _ > _ -> _ + _ > _ ).
finds
plus_gt_compat_l: forall n m p : nat, n > m -> p + n > p + m
which is pretty close to add_increase.
Theorem add_increase: (forall a b: nat, a > 0 -> a + b > b).
intros.
pose (plus_gt_compat_l a 0 b H) as A.
repeat rewrite (plus_comm b) in A.
apply A.
Qed.
Another solution using a different natural numbers library ssrnat and the ssreflect proof language (which is needed by the library):
From mathcomp Require Import ssreflect ssrfun ssrbool eqtype ssrnat seq.
Theorem add_increase a b : 0 < a -> b < a + b.
Proof. by rewrite -{1}[b]add0n ltn_add2r. Qed.
The ltn_add2r : (m + p < n + p) = (m < n) lemma is proved by induction on p, directly by induction on p plus commutativity and other easy properties of addition.
Note that if we're invoking the omega tactic, we could've just done:
Theorem add_increase : forall a b: nat, a > 0 -> a + b > b.
Proof. intros a b. omega. Qed.