How to make use of a hypothesis containing forall in Coq? - 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.

Related

How to prove this DeMorgan law without using automation tactics in Coq?

This is the law I'm trying to prove here:
Goal forall (X : Type) (p : X -> Prop), (exists x, ~ p x) <-> ~ (forall x, p x).
Here's my code up to a point where I don't know in which direction to head:
Proof.
intros. split.
- intros. destruct H as [x H]. intros nh. apply H. apply (nh x).
- intros H.
What is shown as the subgoal and the premises I have seem to be provable, but what's the move?
I've tried going with exfalso., to apply H. afterwards.
Which gives me another premise of x : X and a subgoal of px.
Don't know what to do after. Thanks for the help!
The right-to-left direction is not provable in intuitionistic logic. Coming up with a witness for the existential requires any axiom that moves you to classical logic. For instance, with the principle of excluded middle:
Axiom excluded_middle : forall (P : Prop), P \/ ~ P.
Goal forall (X : Type) (p : X -> Prop),
(exists x, ~ p x) <-> ~ (forall x, p x).
Proof.
intros. split.
- intros. destruct H as [x H]. intros nh. apply H. apply (nh x).
- intros Hnfapx.
(* new hyp: Hnfapx : ~ (forall x, p x) *)
pose proof (excluded_middle (exists x, ~ p x)) as [? | Hnexnpx]; [assumption|].
(* new hyp: Hnexnpx : ~ (exists x, ~ p x)
from this (and excluded middle again) we can deduce (forall x, p x)
this contradicts Hnfapx *)
exfalso. apply Hnfapx. intros x.
(* new hyp: x : X
goal: p x *)
pose proof (excluded_middle (p x)) as [? | Hnpx]; [assumption|].
(* new hyp: Hnpx : ~ p x
so there exists x such that ~ p x
this contradicts Hnexnpx *)
exfalso. apply Hnexnpx. exists x. assumption.
Qed.
More generally, intuitionistic logic loses (some directions of) the De Morgan laws. Indeed, a De Morgan law expresses a duality between two logical connectives through negation. This is fine in classical logic because double negation cancels out. But that’s not the case in intuitionistic logic: the elimination of double negation (∀ P, ¬¬P → P) is not provable. This principle is, in fact, equivalent to the principle of excluded middle. (However, (∀ P, ¬¬¬P → ¬P) is provable.)
That’s why intuitionistic logic requires both quantifiers ∃ and ∀: none is definable in terms of the other one.
(This was first said as comments; I was expecting someone to come up with a more thorough answer but, since no-one did, I am posting mine now. Thanks #Arthur Azevedo De Amorim for correcting me on which axiom is sufficient.)

What does the tactic destruct do in the proof below?

I was reading the series Software Foundations by Benjamin Pierce. And in the Chapter Logic in the first book I came across a problem.
In the proof of the theorem
Theorem not_exists_dist :
excluded_middle ->
forall (X:Type) (P : X -> Prop),
~ (exists x, ~ P x) -> (forall x, P x).
where excluded_middle refers to
Definition excluded_middle := forall P : Prop,
P \/ ~ P.
And the proof of theorem can be as follows:
Proof.
unfold excluded_middle.
intros exmid X P H x.
destruct (exmid (P x)) as [H1 | H2].
- apply H1.
- destruct H.
exists x. apply H2.
Qed.
What puzzled me is the destruct H in the second case. What does the tactic destruct do here? It seems different from What I've known about it before.
(H here is ~ (exists x : X, ~ P x)).
After using destruct H, the subgoal is tranformed from P x into exists x : X, ~ P x.
When you destruct a term of the form A -> B you get a goal for A and the goals for what destruct B would result in. not A is defined as A -> False so B is False in your case and destruct B results in no goals. So you end up with just A.
Here is a long form proof of what is going on:
Theorem not_exists_dist :
excluded_middle ->
forall (X:Type) (P : X -> Prop),
~ (exists x, ~ P x) -> (forall x, P x).
Proof.
unfold excluded_middle.
intros exmid X P H x.
destruct (exmid (P x)) as [H1 | H2].
- apply H1.
- assert(ex (fun x : X => not (P x))) as H3.
exists x. apply H2.
specialize (H H3).
destruct H.
Qed.

How to do induction differently?

I am doing an exercise in Coq and trying to prove if a list equals to its reverse, it's a palindrome. Here is how I define palindromes:
Inductive pal {X : Type} : list X -> Prop :=
| emptypal : pal []
| singlpal : forall x, pal [x]
| inducpal : forall x l, pal l -> pal (x :: l ++ [x]).
Here is the theorem:
Theorem palindrome3 : forall {X : Type} (l : list X),
l = rev l -> pal l.
According to my definition, I will need to do the induction my extracting the front and tail element but apparently coq won't let me do it, and if I force it to do so, it gives an induction result that definitely doesn't make any sense:
Proof.
intros X l H. remember (rev l) as rl. induction l, rl.
- apply emptypal.
- inversion H.
- inversion H.
- (* stuck *)
context:
1 subgoals
X : Type
x : X
l : list X
x0 : X
rl : list X
Heqrl : x0 :: rl = rev (x :: l)
H : x :: l = x0 :: rl
IHl : x0 :: rl = rev l -> l = x0 :: rl -> pal l
______________________________________(1/1)
pal (x :: l)
aparently the inductive context is terribly wrong. is there any way I can fix the induction?
The solution I propose here is probably not the shortest one, but I think it is rather natural.
My solution consists in defining an induction principle on list specialized to your problem.
Consider natural numbers. There is not only the standard induction nat_ind where you prove P 0 and forall n, P n -> P (S n). But there are other induction schemes, e.g., the strong induction lt_wf_ind, or the two-step induction where you prove P 0, P 1 and forall n, P n -> P (S (S n)). If the standard induction scheme is not strong enough to prove the property you want, you can try another one.
We can do the same for lists. If the standard induction scheme list_ind is not enough, we can write another one that works. In this idea, we define for lists an induction principle similar to the two-step induction on nat (and we will prove the validity of this induction scheme using the two-step induction on nat), where we need to prove three cases: P [], forall x, P [x] and forall x l x', P l -> P (x :: l ++ [x']). The proof of this scheme is the difficult part. Applying it to deduce your theorem is quite straightforward.
I don't know if the two-step induction scheme is part of the standard library, so I introduce it as an axiom.
Axiom nat_ind2 : forall P : nat -> Prop, P 0 -> P 1 ->
(forall n : nat, P n -> P (S (S n))) -> forall n : nat, P n.
Then we prove the induction scheme we want.
Lemma list_ind2 : forall {A} (P : list A -> Prop) (P_nil : P [])
(P_single : forall x, P [x])
(P_cons_snoc : forall x l x', P l -> P (x :: l ++ [x'])),
forall l, P l.
Proof.
intros. remember (length l) as n. symmetry in Heqn. revert dependent l.
induction n using nat_ind2; intros.
- apply length_zero_iff_nil in Heqn. subst l. apply P_nil.
- destruct l; [discriminate|]. simpl in Heqn. inversion Heqn; subst.
apply length_zero_iff_nil in H0. subst l. apply P_single.
- destruct l; [discriminate|]. simpl in Heqn.
inversion Heqn; subst. pose proof (rev_involutive l) as Hinv.
destruct (rev l). destruct l; discriminate. simpl in Hinv. subst l.
rewrite app_length in H0.
rewrite PeanoNat.Nat.add_comm in H0. simpl in H0. inversion H0.
apply P_cons_snoc. apply IHn. assumption.
Qed.
You should be able to conclude quite easily using this induction principle.
Theorem palindrome3 : forall {X : Type} (l : list X),
l = rev l -> pal l.

How do you determine which terms to call intros on in coq

I am a beginner with coq, so this may be a trivial question. Sometimes I can't figure out which terms I need to call intros on, when writing a Theorem. A simple example,
Theorem silly1 : forall (n m o p : nat),
n = m ->
[n;o] = [n;p] ->
[n;o] = [m;p].
Proof.
intros n m o p eq1 eq2.
rewrite <- eq1.
apply eq2. Qed.
I know based on the goal, that I will probably need to call intros on (n m o p), but why do I need to use it on eq1 and eq2.
Also, in some other Theorems, you may need to use intros on the type parameter, the hypothesis, or the inductive hypothesis. Example
Theorem trans_eq : forall (X:Type) (n m o : X),
n = m -> m = o -> n = o.
Proof.
intros X n m o eq1 eq2. rewrite -> eq1. rewrite -> eq2.
reflexivity. Qed.
Theorem silly3' : forall (n : nat),
(beq_nat n 5 = true -> beq_nat (S (S n)) 7 = true) ->
true = beq_nat n 5 ->
true = beq_nat (S (S n)) 7.
Proof.
intros n eq H.
symmetry in H. apply eq in H. symmetry in H.
apply H. Qed.
So I guess what I'm asking is...when I start proving a theorem, how should I go about reasoning through the goals, to determine which terms I need to call intros on?
An example of what gallais is refering to is this.
Theorem example_1 : forall A B, (A -> B) -> A -> B.
Proof. intros ? ? H1. apply H1. Qed.
Theorem example_2 : forall A B, (A -> B) -> A -> B.
Proof. intros ? ? H1 H2. apply H1. apply H2. Qed.
Print example_1.
Print example_2.
Another example of when it can be problematic is using introduction before using induction. This makes the induction hypothesis different.
Fixpoint reverse_helper {A : Type} (l1 l2 : list A) : list A :=
match l1 with
| nil => l2
| cons x l1 => reverse_helper l1 (cons x l2)
end.
Theorem example_3 : forall A (l1 l2 : list A), reverse_helper l1 l2 = app (reverse_helper l1 nil) l2.
Proof. intros. induction l1. simpl. reflexivity. simpl. try rewrite IHl1. Abort.
Theorem example_4 : forall A (l1 l2 : list A), reverse_helper l1 l2 = app (reverse_helper l1 nil) l2.
Proof. induction l1. intros. simpl. reflexivity. intros. simpl. rewrite (IHl1 (cons a l2)). rewrite (IHl1 (cons a nil)). Admitted.
Otherwise, you should use introduction whenever you can. You won't be able to use whatever is being quantified over or the antecedents of an implication until you do.
By the way
H1 : A1
...
Hn : An
___
B
is equivalent to
H1: A1, ..., Hn: An ⊢ B.
When you prove something interactively, you're using a sequent calculus starting from the conclusion and working your way back to the hypotheses.

Double induction in Coq

Basically, I would like to prove that following result:
Lemma nat_ind_2 (P: nat -> Prop): P 0 -> P 1 -> (forall n, P n -> P (2+n)) ->
forall n, P n.
that is the recurrence scheme of the so called double induction.
I tried to prove it applying induction two times, but I am not sure that I will get anywhere this way. Indeed, I got stuck at that point:
Proof.
intros. elim n.
exact H.
intros. elim n0.
exact H0.
intros. apply (H1 n1).
Actually, there's a much simpler solution. A fix allows recursion (aka induction) on any subterm while nat_rect only allows recursion on the immediate subterm of a nat. nat_rect itself is defined with a fix, and nat_ind is just a special case of nat_rect.
Definition nat_rect_2 (P : nat -> Type) (f1 : P 0) (f2 : P 1)
(f3 : forall n, P n -> P (S (S n))) : forall n, P n :=
fix nat_rect_2 n :=
match n with
| 0 => f1
| 1 => f2
| S (S m) => f3 m (nat_rect_2 m)
end.
#Rui's fix solution is quite general. Here is an alternative solution that uses the following observation: when proving this lemma mentally, you use somewhat stronger induction principle. For example if P holds for two consecutive numbers it becomes easy to make it hold for the next pair:
Lemma nat_ind_2 (P: nat -> Prop): P 0 -> P 1 -> (forall n, P n -> P (2+n)) ->
forall n, P n.
Proof.
intros P0 P1 H.
assert (G: forall n, P n /\ P (S n)).
induction n as [ | n [Pn PSn]]; auto.
split; try apply H; auto.
apply G.
Qed.
Here G proves something redundant, yet calling the induction tactic for it brings sufficient context for near-trivial proof.
I think well-founded induction is necessary for that.
Require Import Arith.
Theorem nat_rect_3 : forall P,
(forall n1, (forall n2, n2 < n1 -> P n2) -> P n1) ->
forall n, P n.
Proof.
intros P H1 n1.
apply Acc_rect with (R := lt).
info_eauto.
induction n1 as [| n1 H2].
apply Acc_intro. intros n2 H3. Check lt_n_0. Check (lt_n_0 _). Check (lt_n_0 _ H3). destruct (lt_n_0 _ H3).
destruct H2 as [H2]. apply Acc_intro. intros n2 H3. apply Acc_intro. intros n3 H4. apply H2. info_eauto with *.
Defined.
Theorem nat_rect_2 : forall P,
P 0 ->
P 1 ->
(forall n, P n -> P (S (S n))) ->
forall n, P n.
Proof.
intros ? H1 H2 H3.
induction n as [n H4] using nat_rect_3.
destruct n as [| [| n]].
info_eauto with *.
info_eauto with *.
info_eauto with *.
Defined.
A fun observation: Rui's answer is the fixpoint translation of NonNumeric's answer, which is the generalization of user1861759's answer for any n, not just n = 2.
In other words, these answers are all fine, and actually deeply related to one another, by the correspondence between terminating fixpoints and generalized induction.