Tactic for existential hypothesis - coq

Say we have a proposition P1 n, and there exists n for which it holds. Furthermore we have a proposition P2, where P1 n implies P2 for any n. How do we prove P2?
Parameter P1 : nat -> Prop.
Axiom some_p1 : exists n, P1 n.
Parameter P2 : Prop.
Axiom p1_implies_p2 : forall n, P1 n -> P2.
Theorem p2 : P2.
I tried
Proof.
eapply p1_implies_p2.
which gives me the goal P1 ?n, but I'm not sure how to proceed from there.

You may eliminate some_p1to get a witness nand a hypothesis Hn.
Theorem p2 : P2.
case some_p1 ; intros n Hn. apply (p1_implies_p2 _ Hn).
Qed.

Just for completeness, if you use the SSReflect proof language, Pierre's proof idea would look like this:
Theorem p2 : P2.
Proof. move: some_p1 => [n p1n]. exact: (p1_implies_p2 p1n). Qed.
Note that providing the second argument p1n to p1_implies_p2 is enough, since the omitted first one, n, can be inferred by Coq.

Related

apply dependently typed constructor in hypothesis

Consider the following inductive definition:
Inductive T (n : nat) : nat -> Prop :=
| c1 : T n n.
This works:
Theorem a : T 1 1.
Proof.
apply c1.
Qed.
But this doesn't:
Theorem b : T 1 1 -> True.
Proof.
intros H.
apply c1 in H.
Both calls to apply seem equivalent to me, but the latter fails with Error: Statement without assumptions. Why? And how can I make it work?
This question arose from my poor understanding of the apply tactic. #gallais's comment made me realize why apply c1 in H doesn't really make sense. The tactic essentially works as a function application on H and c1 H doesn't really make sense. For future reference, this is an example in which apply in would make sense. If we had another constructor c2 like this:
Inductive T (n : nat) : nat -> Prop :=
| c1 : T n n
| c2 : forall x, T n x -> T n (S x).
Then apply c2 in H would transform something of type T n x into something of type T n (S x), for example:
Theorem b : T 1 1 -> True.
Proof.
intros H.
apply c2 in H.
transforms the hypothesis H : T 1 1 into H : T 1 2.
There is a difference between proving H or proving H -> True. The Coq standard library already defined a proof of True, called I.
Hence:
Theorem b : T 1 1 -> True.
Proof.
intros; apply I.
Qed.
But please also note that:
Theorem prove_I : forall p : Prop, p -> True.
Proof.
intros; apply I.
Qed.
And as a consequence H -> True does not prove H, there's no correlation between the inhabitants of the two type.
The apply tactic works differently when it is applied to a goal or a hypothesis. Applying H : A -> B has the following semantics:
if the goal was B, then it will be transformed to A after apply H.
if the hypothesis H1 : A, then it will be transformed to H1 : B after apply H in H1
This makes the reasoning correct; so it does not introduce inconsistencies.

Induction on predicates with product type arguments

If I have a predicate like this:
Inductive foo : nat -> nat -> Prop :=
| Foo : forall n, foo n n.
then I can trivially use induction to prove some dummy lemmas:
Lemma foo_refl : forall n n',
foo n n' -> n = n'.
Proof.
intros.
induction H.
reflexivity.
Qed.
However, for a predicate with product type arguments:
Inductive bar : (nat * nat) -> (nat * nat) -> Prop :=
| Bar : forall n m, bar (n, m) (n, m).
a similar proof for nearly identical lemma gets stuck because all assumptions about variables disappear:
Lemma bar_refl : forall n n' m m',
bar (n, m) (n', m') -> n = n'.
Proof.
intros.
induction H.
(* :( *)
Why is this happening? If I replace induction with inversion, then it behaves as expected.
The lemma is still provable with induction but requires some workarounds:
Lemma bar_refl : forall n n' m m',
bar (n, m) (n', m') -> n = n'.
Proof.
intros.
remember (n, m) as nm.
remember (n', m') as n'm'.
induction H.
inversion Heqnm. inversion Heqn'm'. repeat subst.
reflexivity.
Qed.
Unfortunately, this way proofs gets completely cluttered and are impossible to follow for more complicated predicates.
One obvious solution would be to declare bar like this:
Inductive bar' : nat -> nat -> nat -> nat -> Prop :=
| Bar' : forall n m, bar' n m n m.
This solves all the problems. Yet, for my purposes, I find the previous ("tupled") approach somewhat more elegant. Is there a way to keep the predicate as it is and still be able to do manageable inductive proofs? Where does the problem even come from?
The issue is that induction can only works with variables, not constructed terms. This is why you should first prove something like
Lemma bar_refl : forall p q, bar p q -> fst p = fst q.
which is trivially proved by now induction 1. to prove your lemma.
If you don't want the intermediate lemma to have a name, your solution is the correct one: you need to help Coq with remember to generalize your goal, and then you'll be able to prove it.
I don't remember exactly where this restriction comes from, but I recall something about making some unification problem undecidable.
Often in these situation one can do induction on one of the sub-terms.
In your case your lemma can be proved by induction on n, with
Lemma bar_refl : forall n n' m m', bar (n, m) (n', m') -> n = n'.
Proof. induction n; intros; inversion H; auto. Qed.
... all assumptions about variables disappear... Why is this happening? If I replace induction with inversion, then it behaves as expected.
The reason that happens is described perfectly in this blog post:
Dependent Case Analysis in Coq without Axioms
by James Wilcox. Let me quote the most relevant part for this case:
When Coq performs a case analysis, it first abstracts over all indices. You may have seen this manifest as a loss of information when using destruct on predicates (try destructing even 3 for example: it just deletes the hypothesis!), or when doing induction on a predicate with concrete indices (try proving forall n, even (2*n+1) -> False by induction on the hypothesis (not the nat) -- you'll be stuck!). Coq essentially forgets the concrete values of the indices. When trying to induct on such a hypothesis, one solution is to replace each concrete index with a new variable together with a constraint that forces the variable to be equal to the correct concrete value. destruct does something similar: when given a term of some inductive type with concrete index values, it first replaces the concrete values with new variables. It doesn't add the equality constraints (but inversion does). The error here is about abstracting out the indices. You can't just go replacing concrete values with arbitrary variables and hope that things still type check. It's just a heuristic.
To give a concrete example, when using destruct H. one basically does pattern-matching like so:
Lemma bar_refl : forall n n' m m',
bar (n, m) (n', m') -> n = n'.
Proof.
intros n n' m m' H.
refine (match H with
| Bar a b => _
end).
with the following proof state:
n, n', m, m' : nat
H : bar (n, m) (n', m')
a, b : nat
============================
n = n'
To get almost the exact proof state we should've erased H from the context, using the clear H. command: refine (...); clear H.. This rather primitive pattern-matching doesn't allow us to prove our goal.
Coq abstracted away (n, m) and (n',m') replacing them with some pairs p and p', such that p = (a, b) and p' = (a, b). Unfortunately, our goal has the form n = n' and there is neither (n,m) nor (n',m') in it -- that's why Coq didn't change the goal with a = a.
But there is a way to tell Coq to do that. I don't know how to do exactly that using tactics, so I'll show a proof term. It's is going to look somewhat similar to #Vinz's solution, but notice that I didn't change the statement of the lemma:
Undo. (* to undo the previous pattern-matching *)
refine (match H in (bar p p') return fst p = fst p' with
| Bar a b => _
end).
This time we added more annotations for Coq to understand the connections between the components of H's type and the goal -- we explicitly named the p and p' pairs and because we told Coq to treat our goal as fst p = fst p' it will replace p and p' in the goal with (a,b). Our proof state looks like this now:
n, n', m, m' : nat
H : bar (n, m) (n', m')
a, b : nat
============================
fst (a, b) = fst (a, b)
and simple reflexivity is able to finish the proof.
I think now it should be clear why destruct works fine in the following lemma (don't look at the answer below, try to figure it out first):
Lemma bar_refl_all : forall n n' m m',
bar (n, m) (n', m') -> (n, m) = (n', m').
Proof.
intros. destruct H. reflexivity.
Qed.
Answer: because the goal contains the same pairs that are present in the hypothesis's type, so Coq replaces them all with appropriate variables and that will prevent the information loss.
Another way ...
Lemma bar_refl n n' m m' : bar (n, m) (n', m') -> n = n'.
Proof.
change (n = n') with (fst (n,m) = fst (n',m')).
generalize (n,m) (n',m').
intros ? ? [ ]; reflexivity.
Qed.

How to prove False from obviously contradictory assumptions

Suppose I want to prove following Theorem:
Theorem succ_neq_zero : forall n m: nat, S n = m -> 0 = m -> False.
This one is trivial since m cannot be both successor and zero, as assumed. However I found it quite tricky to prove it, and I don't know how to make it without an auxiliary lemma:
Lemma succ_neq_zero_lemma : forall n : nat, O = S n -> False.
Proof.
intros.
inversion H.
Qed.
Theorem succ_neq_zero : forall n m: nat, S n = m -> 0 = m -> False.
Proof.
intros.
symmetry in H.
apply (succ_neq_zero_lemma n).
transitivity m.
assumption.
assumption.
Qed.
I am pretty sure there is a better way to prove this. What is the best way to do it?
You just need to substitute for m in the first equation:
Theorem succ_neq_zero : forall n m: nat, S n = m -> 0 = m -> False.
Proof.
intros n m H1 H2; rewrite <- H2 in H1; inversion H1.
Qed.
There's a very easy way to prove it:
Theorem succ_neq_zero : forall n m: nat, S n = m -> 0 = m -> False.
Proof.
congruence.
Qed.
The congruence tactic is a decision procedure for ground equalities on uninterpreted symbols. It's complete for uninterpreted symbols and for constructors, so in cases like this one, it can prove that the equality 0 = m is impossible.
It might be useful to know how congruence works.
To prove that two terms constructed by different constructors are in fact different, just create a function that returns True in one case and False in the other cases, and then use it to prove True = False. I think this is explained in Coq'Art
Example not_congruent: 0 <> 1.
intros C. (* now our goal is 'False' *)
pose (fun m=>match m with 0=>True |S _=>False end) as f.
assert (Contra: f 1 = f 0) by (rewrite C; reflexivity).
now replace False with True by Contra.
Qed.

Coq induction start at specific nat

I'm trying to learn coq so please assume I know nothing about it.
If I have a lemma in coq that starts
forall n m:nat, n>=1 -> m>=1 ...
And I want to proceed by induction on n. How do I start the induction at 1? Currently when I use the "induction n." tactic it starts at zero and this makes the base statement false which makes it hard to proceed.
Any hints?
The following is a proof that every proposition P is true forall n>=1, if P is true for 1 and if P is inductively true.
Require Import Omega.
Parameter P : nat -> Prop.
Parameter p1 : P 1.
Parameter pS : forall n, P n -> P (S n).
Goal forall n, n>=1 -> P n.
We begin the proof by induction.
induction n; intro.
A false base case is no problem, if you have a false hypothesis laying around. In this case 0>=1.
- exfalso. omega.
The inductive case is tricky, because to access a proof of P n, we first have to proof that n>=1. The trick is to do a case analysis on n. If n=0, then we can trivially proof the goal P 1. If n>=1, we can access P n, and then proof the rest.
- destruct n.
+ apply p1.
+ assert (S n >= 1) by omega.
intuition.
apply pS.
trivial.
Qed.

Using an existential theorem in Coq

I have the following theorem in Coq: Theorem T : exists x:A, P x. I want to be able to use this value in a subsequent proof. I.E. I want to say something like: "let o represent a value such that P o. I know that o exists by theorem T..."
How would I do this?
Thanks in advance!
Mathematically speaking, you need to apply an elimination rule for the ∃ constructor. The generic elimination tactic elim works.
elim T; intro o.
Silly example:
Parameter A : Prop.
Parameter P : A -> Prop.
Axiom T : exists x:A, P x.
Parameter G : Prop.
Axiom U : forall x:A, P x -> G.
Goal G.
Proof.
elim T; intro o.
apply U.
Qed.