Destruct hypothesis: general case - coq

That's pretty clear what destruct H does if H contains conjunction or disjunction. But I can't figure out what it does in general case. It does something bizarre, especially if H: a -> b.
Some examples:
Lemma demo : forall (x y: nat), x=4 -> x=4.
Proof.
intros. destruct H.
The hypothesis is just destroyed:
1 subgoal
x, y : nat
______________________________________(1/1)
x = x
Another one:
Lemma demo : forall (x y: nat), (x = 4 -> x=4) -> True.
Proof.
intros. destruct H.
Now I have two branches:
1 subgoal
x, y : nat
______________________________________(1/1)
x = 4
1 subgoal
x, y : nat
______________________________________(1/1)
True
Third example. It's not provable but it still doesn't make sense to me:
Lemma demo : forall (x y: nat), (x = 4 -> x = 4) -> x = 4.
Proof.
intros. destruct H.
Now I have to prove x = x in the second branch!
2 subgoals
x, y : nat
______________________________________(1/2)
x = 4
______________________________________(2/2)
x = x
So, I clearly don't understand what destruct H does.

The cases you are referring to fall in two categories. If H : A and A is inductively or coinductively defined (e.g., conjunction and disjunction), then destruct H generates one subgoal for each constructor in that type, with additional hypotheses determined by the arguments of that constructor. On the other hand, if H : A -> B, then destruct H generates one subgoal where you have to prove A, and then continues recursively as if H : B. This is roughly equivalent to the following calls:
assert (H' : A); [ |specialize (H H'); destruct H].
The missing piece of the puzzle is that equality itself is defined as an inductive type:
Inductive eq (A : Type) (a : A) : A -> Prop :=
| eq_refl : eq A a a
When you destruct something of type x = 4, Coq generates one case for each constructor of that type. But there is only one constructor in that type: eq_refl. When considering that case, Coq also automatically replaces occurrences of the RHS of destructed equality by the LHS (since both sides are equal for that constructor). In your first and third examples, this leads to replacing 4 in the goal with x.
Most of the time, you do not want to destruct an equality hypothesis, since this replacement behavior is not very useful. It is usually better to use the rewrite tactic, since it allows you to rewrite from rightto-left or left-to-right.

Related

Rewriting with John Major's equality

John Major's equality comes with the following lemma for rewriting:
Check JMeq_ind_r.
(*
JMeq_ind_r
: forall (A : Type) (x : A) (P : A -> Prop),
P x -> forall y : A, JMeq y x -> P y
*)
It is easy to generalize it like that:
Lemma JMeq_ind2_r
: forall (A:Type)(x:A)(P:forall C,C->Prop),
P A x -> forall (B:Type)(y:B), #JMeq B y A x -> P B y.
Proof.
intros.
destruct H0.
assumption.
Qed.
However I need something a bit different:
Lemma JMeq_ind3_r
: forall (A:Type)(x:A*A) (P:forall C,C*C->Prop),
P A x -> forall (B:Type)(y:B*B), #JMeq (B*B) y (A*A) x -> P B y.
Proof.
intros.
Fail destruct H0.
Abort.
Is JMeq_ind3_r provable?
If not:
Is it safe to assume it as an axiom?
Is it reducible to a simpler and safe axiom?
It's not provable. JMeq is essentially two equality proofs bundled together, one for the types and one for the values. In this case, we get from the hypothesis that A * A = B * B. From this, it is not provable that A = B, so we cannot convert a P A x into P B y.
If A * A = B * B implies A = B, that means that the pair type constructor is injective. Type constructor injectivity in general (i.e. for all types) is inconsistent with classical logic and also with univalence. For some type constructors, injectivity is provable, but not for pairs.
Is it safe to assume it as an axiom?
If you use classical logic or univalence then it isn't. Otherwise, it probably is, but I would instead try to rephrase the problem so that type constructor injectivity does not come up.

Understanding the induction on evidence in coq

I am working on the theorem ev_ev__ev in IndProp.v of Software Foundations (Vol 1: Logical Foundations).
Theorem ev_ev__ev : forall n m,
even (n+m) -> even n -> even m.
Proof.
intros n m Enm En. induction En as [| n' Hn' IHn'].
- (* En: ev_0 *) simpl in Enm. apply Enm.
- (* En: ev_SS n' Hn': even n'
with IHn': even (n' + m) -> even m *)
apply IHn'. simpl in Enm. inversion Enm as [| n'm H]. apply H.
Qed.
where even is defined as:
Inductive even : nat -> Prop :=
| ev_0 : even 0
| ev_SS (n : nat) (H : even n) : even (S (S n)).
At the point of the second bullet -, the context as well as the goal is as follows:
m, n' : nat
Enm : even (S (S n') + m)
Hn' : even n'
IHn' : even (n' + m) -> even m
______________________________________(1/1)
even m
I understand how m, n', Enm, Hn' in the context are generated. However, how is IHn' generated?
Induction hypotheses are systematically created for premises of constructors that are in the same type family. So, you can look at each constructor independently.
Assume you have an inductive definition of a type that starts with:
Inductive arbitraryName : A -> B -> Prop :=
An induction principle called arbitraryName_ind will be created, which starts with a quantification over an arbitrary predicate usually called P with the same type
forall P : A -> B -> Prop,
Now, if you have a constructor of the form
arbitrary_constructor : forall x y, arbitraryName x y -> ...
The induction principle will have a sub-clause for this constructor that starts with the same quantifications over all variables in the constructor, the same hypothesis, plus an induction hypothesis for the premise that relies on arbitraryName.
forall x y, arbitraryName x y -> P x y -> ...
Finally, each constructor of the inductive definition has to finish with an application of the defined type family (in this case arbitraryName). The end of the clause for this constructor apply the function P to the same argument.
Let's go back to arbitrary_constructor and suppose it has the following full type:
arbitrary_constructor : forall x y, arbitraryName x y -> arbitraryName (g x y) (h x y)
In that case the clause in the induction principle is :
(forall x y, arbitraryName x y -> P x y -> P (g x y) (h x y))
In the case of even, there is a constructor ev_SS that has the following shape:
ev_SS : forall x, even x -> even (S (S x))
So the clause that is generated has the following shape:
(forall x, even x -> P x -> P (S (S x)))
The induction hypothesis IHn' corresponds exactly to this P in the clause.
The full induction principle has the following shape.
forall P : nat -> Prop, P 0 ->
(forall x, even x -> P x -> P (S (S x))) ->
forall n, even n -> P n
When you type induction En, this theorem is applied. The hypothesis even n, where n is universally quantified, is matched with the text of En in the goal at that moment. It turns out that the statement of that hypothesis is even n (the n here is fixed in the goal) so the universally quantified n is instantiated with the local n from the goal context. Then, the tactic tries to find all the hypotheses in the context where this n appears. In this case, there is Enm, so this hypothesis is used to define the P on which the induction principle will be instantiated. In a sense, what happens is that Enm is put back in the goal's conclusion, as if one had executed revert Enm.
We need P n to be the same thing as even (n + m) -> even m. The most natural solution is that P is equal to the function fun x => even (x + m) -> even m
So in the second case of the proof by induction, a new n' is introduced and P is applied to n' to give the contents of the induction hypothesis:
(even (n' + m) -> even m)
and P is applied to S (S n') to give the contents of the final goal.
even (S (S n') + m) -> even m
Now, at the time of calling the induction tactic, the hypothesis Enm was in the context, so the statement even (S (S n') + m), which is morally an offspring of Enm is put back in the context with the same name. Note that there was already a hypothesis named Enm in the other goal, but the statement was again different.
It is normal that you have a question on how this induction hypothesis was generated, because what happens actually involves several operations.

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)

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.

How to introduce a new existential condition from a witness in Coq?

My question relates to how to construct an exist term in the set of conditions/hypotheses.
I have the following intermediate proof state:
X : Type
P : X -> Prop
H : (exists x : X, P x -> False) -> False
x : X
H0 : P x -> False
______________________________________(1/1)
P x
In my mind, I know that because of H0, x is a witness for (exists x : X, P x -> False), and I want to introduce a name:
w: (exists x : X, P x -> False)
based on the above reasoning and then use it with apply H in w to generate a False in the hypothesis, and finally inversion the False.
But I don't know what tactic/syntax to use to introduce the witness w above. The best I can reach so far is that Check (ex_intro _ (fun x => P x -> False) x H0)). gives False.
Can someone explain how to introduce the existential condition, or an alternative way to finish the proof?
Thanks.
P.S. What I have for the whole theorem to prove is:
Theorem not_exists_dist :
excluded_middle ->
forall (X:Type) (P : X -> Prop),
~ (exists x, ~ P x) -> (forall x, P x).
Proof.
unfold excluded_middle. unfold not.
intros exm X P H x.
destruct (exm (P x)).
apply H0.
Check (H (ex_intro _ (fun x => P x -> False) x H0)).
Here, since you already know how to construct a term of type False, you can add it to the context using pose proof. This gives:
pose proof (H (ex_intro (fun x => P x -> False) x H0))
You can even directly destruct the term, which solves the goal.
destruct (H (ex_intro (fun x => P x -> False) x H0))
Another way to finish your proof is to prove False. You can change the goal to False with tactics like exfalso or contradiction. With this approach, you can use hypotheses of the form _ -> False that are otherwise difficult to manipulate. For your proof, you can write:
exfalso. apply H. (* or directly, contradiction H *)
exists x. assumption.
You could use the assert tactic:
assert(w: exists x, P x -> False).
It will ask you to prove this statement in a new sub-goal, and will add w to your existing goal. For this kind of trivial proof, you can inline the proof directly:
assert(w: exists x, P x -> False) by (exists x; exact H0).