Coq: destruct (co)inductive hypothesis without losing information - coq

Consider the following development:
Require Import Relation RelationClasses.
Set Implicit Arguments.
CoInductive stream (A : Type) : Type :=
| scons : A -> stream A -> stream A.
CoInductive stream_le (A : Type) {eqA R : relation A}
`{PO : PartialOrder A eqA R} :
stream A -> stream A -> Prop :=
| le_step : forall h1 h2 t1 t2, R h1 h2 ->
(eqA h1 h2 -> stream_le t1 t2) ->
stream_le (scons h1 t1) (scons h2 t2).
If I have a hypothesis stream_le (scons h1 t1) (scons h2 t2), it would be reasonable for the destruct tactic to turn it into a pair of hypotheses R h1 h2 and eqA h1 h2 -> stream_le t1 t2. But that's not what happens, because destruct loses information whenever doing anything non-trivial. Instead, new terms h0, h3, t0, t3 are introduced into the context, with no recall that they are respectively equal to h1, h2, t1, t2.
I would like to know if there is a quick and easy way to do this kind of "smart destruct". Here is what i have right now:
Theorem stream_le_destruct : forall (A : Type) eqA R
`{PO : PartialOrder A eqA R} (h1 h2 : A) (t1 t2 : stream A),
stream_le (scons h1 t1) (scons h2 t2) ->
R h1 h2 /\ (eqA h1 h2 -> stream_le t1 t2).
Proof.
intros.
destruct H eqn:Heq.
remember (scons h1 t1) as s1 eqn:Heqs1;
remember (scons h2 t2) as s2 eqn:Heqs2;
destruct H;
inversion Heqs1; subst; clear Heqs1;
inversion Heqs2; subst; clear Heqs2.
split; assumption.
Qed.

Indeed, inversion basically does what you want, however as Arthur pointed out it is a bit unstable, mainly due to the different congruence steps.
Under the hood, inversion just calls a version of destruct, but remembering some equalities first. As you have well discovered, pattern matching in Coq will "forget" arguments of constructors, except if these are variables, then, all the variables under the scope of the destruct will be instantiated.
What does that mean? It means that in order to properly destruct an inductive I : Idx -> Prop, you want to get your goal of the form: I x -> Q x, so that destructing the I x will also refine the x in Q. Thus, a standard transformation for an inductive I term and goal Q (f term) is to rewrite it to I x -> x = term -> Q (f x). Then, destructing I x will get you x instantiated to the proper index.
With that in mind, it may be a good exercise to implement inversion manually using the case: tactic of Coq 8.7;
From Coq Require Import ssreflect.
Theorem stream_le_destruct A eqA R `{PO : PartialOrder A eqA R} (h1 h2 : A) (t1 t2 : stream A) :
stream_le (scons h1 t1) (scons h2 t2) ->
R h1 h2 /\ (eqA h1 h2 -> stream_le t1 t2).
Proof.
move E1: (scons h1 t1) => sc1; move E2: (scons h2 t2) => sc2 H.
by case: sc1 sc2 / H E1 E2 => h1' h2' t1' t2' hr ih [? ?] [? ?]; subst.
Qed.
You can read the manual for more details, but basically with the first line, we create the equalities we need; then, in the second we can destruct the term and get the proper instantiations solving the goal. A good effect of the case: tactic is that, contrary to destruct, it will try to prevent us from destructing a term without first bringing its dependencies into scope.

Calling destruct will not directly give you what you want. You need to use inversion instead.
Theorem stream_le_destruct : forall h1 h2 t1 t2,
stream_le (scons h1 t1) (scons h2 t2) ->
h1 <= h2 /\ (h1 = h2 -> stream_le t1 t2).
Proof.
intros.
inversion H; subst; clear H.
split; assumption.
Qed.
Unfortunately, the inversion tactic is quite ill behaved, as it tends to generate a lot of spurious equality hypotheses, making it hard to name them consistently. One (somewhat heavyweight, admittedly) alternative is to use inversion only to prove a lemma like the one you did, and apply this lemma in proofs instead of calling inversion.

Related

Take a conjunction of two hypotheses and create a new hypothesis in Coq

I'm wondering as destruct H as (H1 & H2). on hypothesis H : p /\ q creates two hypotheses H1 : p and H2 : q, if there is any tactic that does the other way around. That is, taking two hypotheses and creating one with conjunction of those.
Here are two possibilities, using the assert tactic:
Goal forall A B : Prop, A -> B -> A /\ B.
Proof.
intros A B HA HB.
assert (H1 : A /\ B). { now split. }
assert (H2 := conj HA HB).
Abort.

How do I apply the proposition of the form P->Q->R to two hypotheses P and Q simultaneously in Coq?

I tried to prove forall P Q R : Prop, P -> Q -> (P -> Q -> R) -> R. My proof is the following.
Goal forall P Q R : Prop, P -> Q -> (P -> Q -> R) -> R.
Proof.
intros P Q R H1 H2 H3.
apply H3 in H1.
exact H1.
exact H2.
Qed.
When apply H3 in H1, two goals will appear. However, I want to obtain R more directly like apply H3 in H1 and H2. But I couldn't find such a way. How do I achieve this?
I already know that the following is also fine. But this is not what I want. I don't want to increase goals.
Goal forall P Q R : Prop, P -> Q -> (P -> Q -> R) -> R.
Proof.
intros P Q R H1 H2 H3.
apply H3.
exact H1.
exact H2.
Qed.
You can apply H1 and H2 to H3 yourself directly, without using the apply tactic.
Your H3 is of type P -> Q -> R (a function that takes proofs of P and Q and returns a proof of R). So, the expression H3 H1 H2 has type R.
With this you can simplify your proof to the following:
Goal forall P Q R : Prop, P -> Q -> (P -> Q -> R) -> R.
Proof.
intros P Q R H1 H2 H3.
apply (H3 H1 H2).
Qed.
In fact, your proof is exactly the same as the one above because all the apply tactic does is applying a function to an argument.

How to make use of a hypothesis containing forall in Coq?

I am trying to prove the equivalence of P \/ Q and ~ P -> Q, under the assumption of Excluded Middle,
Theorem eq_of_or :
excluded_middle ->
forall P Q : Prop,
(P \/ Q) <-> (~ P -> Q).
where the Excluded Middle is the following.
Definition excluded_middle := forall P : Prop, P \/ ~ P.
Actually, the proof of one direction does not require the Excluded Middle. In my attempt at proving the other direction, I get stuck when I am trying to utilize the Excluded Middle among the hypotheses,
Proof.
intros EM P Q. split.
{ intros [H | H]. intros HNP.
- unfold not in HNP. exfalso.
apply HNP. apply H.
- intros HNP. apply H. }
{ intros H. unfold excluded_middle in EM.
unfold not in EM. unfold not in H.
}
where the current environment is the following:
1 subgoal
EM : forall P : Prop, P \/ (P -> False)
P, Q : Prop
H : (P -> False) -> Q
______________________________________(1/1)
P \/ Q
I understand that under such circumstance, what we need to do next is to do something like the "case analysis" of P, including the use of tactics left and right, if my proof makes sense till now.
Thanks in advance for any advice and suggestion!
You can instantiate EM : forall P : Prop, P \/ ~ P with any proposition (I instantiated it with P below and destructed it immediately), since
EM is essentially a function that takes an arbitrary proposition P and returns a proof of either P or ~ P.
Theorem eq_of_or' :
excluded_middle ->
forall P Q : Prop, (~ P -> Q) -> P \/ Q.
Proof.
intros EM P Q.
destruct (EM P) as [p | np]. (* <- the key part is here *)
- left. apply p.
- right.
apply (H np).
(* or, equivalently, *)
Undo.
apply H.
apply np.
Undo 2.
(* we can also combine two `apply` into one: *)
apply H, np.
Qed.

Combining two Coq hypotheses

So I have two hypotheses, one that is h : A -> B, and the other which is h2 : A. How can I get h3 : B to appear in my hypotheses?
pose proof (h h2) as h3.
introduces h3 : B as a new hypothesis,
specialize (h h2).
modifies h : A -> B into h : B -- this can be useful if you won't need h later, and symmetrically,
apply h in h2.
converts h2 : A into h2 : B.
Another (not very convenient) way would be to
assert B as h3 by exact (h h2).
That's what the pose proof variant is equivalent to.
Also, in a simple case like the following, you can solve your goal without introducing a new hypothesis:
Goal forall (A B : Prop), (A -> B) -> A -> B.
intros A B h h2.
apply (h h2).
Qed.

rewrite works for = but not for <-> (iff) in Coq

I have the following during a proof, in which I need to replace normal_form step t with value t as there is a proven theorem that there are equivalent.
H1 : t1 ==>* t1' /\ normal_form step t1'
t2' : tm
H2 : t2 ==>* t2' /\ normal_form step t2'
______________________________________(1/1)
exists t' : tm, P t1 t2 ==>* t' /\ normal_form step t'
The equivalence theorem is:
Theorem nf_same_as_value
: forall t : tm, normal_form step t <-> value t
Now, I can use this theorem to rewrite normal_form occurrences in the hypotheses, but not in the goal. That is
rewrite nf_same_as_value in H1; rewrite nf_same_as_value in H2.
works on the hypothesis, but rewrite nf_same_as_value. on the goal gives:
Error:
Found no subterm matching "normal_form step ?4345" in the current goal.
Is the rewrite on the goal here impossible theoretically, or is it an implementation issue?
-- Edit --
My confusion here is that if we define normal_form step = value, the rewrite would have worked. If we define forall t, normal_form step t <-> value t, then the rewrite works if normal_form step is not quoted in an existential, but does not work if it is in an existential.
Adapting #Matt 's example,
Require Export Coq.Setoids.Setoid.
Inductive R1 : Prop -> Prop -> Prop :=
|T1_refl : forall P, R1 P P.
Inductive R2 : Prop -> Prop -> Prop :=
|T2_refl : forall P, R2 P P.
Theorem Requal : R1 = R2.
Admitted.
Theorem Requiv : forall x y, R1 x y <-> R2 x y.
Admitted.
Theorem test0 : forall y, R2 y y -> exists x, R1 x x.
Proof.
intros. rewrite <- Requal in H. (*works*) rewrite Requal. (*works as well*)
Theorem test2 : forall y, R2 y y -> exists x, R1 x x.
Proof.
intros. rewrite <- Requiv in H. (*works*) rewrite Requiv. (*fails*)
What confuses me is why the last step has to fail.
1 subgoal
y : Prop
H : R1 y y
______________________________________(1/1)
exists x : Prop, R1 x x
Is this failure related to functional extensionality?
The error message is particularly confusing:
Error:
Found no subterm matching "R1 ?P ?P0" in the current goal.
There is exactly one subterm matching R1 _ _, namely R1 x x.
Also, per #larsr, the rewrite works if eexists is used
Theorem test1 : forall y, R2 y y -> exists x, R1 x x.
Proof.
intros. eexists. rewrite Requiv. (*works as well*) apply H. Qed.
What did eexists add here?
The rewrite cannot go under the existential quantifier. You'll need to instantiate t' first before you can do the rewrite. Note that econstructor may be a useful tactic in this case, which can replace the existential quantifier with a unification variable.
EDIT in response to OP's comment
This will still not work for equality. As an example, try:
Inductive R1 : Prop -> Prop -> Prop :=
|T1_refl : forall P, R1 P P.
Inductive R2 : Prop -> Prop -> Prop :=
|T2_refl : forall P, R2 P P.
Theorem Req : forall x y, R1 x y = R2 x y.
Admitted.
Theorem test : forall y, R2 y y -> exists x, R1 x x.
Proof.
intros. rewrite Req. (*rewrite still fails*)
The issue is not actually about equality vs. iff, the issue relates to rewriting under a binding (in this case a lambda). The implementation of exists x : A, P is really just syntax for ex A (fun x => P x), so the rewrite is failing not because of the iff, but because the rewrite tactic does not want to go under the binding for x in (fun x => P x). It seems as though there might be a way to do this with setoid_rewrite, however, I don't have any experience with this.