I am learning propositional logic and the rules of inference. The Disjunctive Syllogism rule states that if we have in our premises (P or Q), and also (not P); then we can reach Q.
I can not for the life of me figure out how to do this in Coq. Let's say I have :
H : A \/ B
H0 : ~ A
______________________________________(1/1)
What tactic should I use to reach
H1 : B.
As an extra, I would be glad if someone could share with me the Coq tactic equivalents of basic inference rules, like modus tollens, or disjunctive introduction etc. Is there maybe a plugin I can use?
Coq does not have this tactic built-in, but fortunately you can define your own tactics. Notice that
destruct H as [H1 | H1]; [contradiction |].
puts H1 : B in the context, just as you asked. So you can create an alias for this combined tactic:
Ltac disj_syllogism AorB notA B :=
destruct AorB as [? | B]; [contradiction |].
Now we can easily imitate the disjunctive syllogism rule like so:
Section Foo.
Context (A B : Prop) (H : A \/ B) (H0 : ~ A).
Goal True.
disj_syllogism H H0 H1.
End Foo.
Let me show a couple less automated approaches:
Ltac disj_syllogism AorB notA B :=
let A := fresh "A" in
destruct AorB as [A | B]; [contradiction (notA A) |].
This approach does not ask Coq to find a contradiction, it provides it directly to the contradiction tactic (notA A term). Or we could have used an explicit term with the pose proof tactic:
Ltac disj_syllogism AorB notA B :=
pose proof (match AorB with
| or_introl a => False_ind _ (notA a)
| or_intror b => b
end) as B.
I hope this helps. I'm not sure if some extra explanation is needed -- feel free to ask for clarification and I'll update my answer.
I think you maybe have the wrong expectations on how Coq works? The general way of proving this is essentially a truth-table on the different possibilities:
Lemma it: forall a b, (a \/ b) /\ ~a -> b.
Proof.
intuition.
Show Proof.
Qed.
(fun (a b : Prop) (H : (a \/ b) /\ ~ a) =>
and_ind
(fun (H0 : a \/ b) (H1 : ~ a) =>
or_ind (fun H2 : a => let H3 : False := H1 H2 in False_ind b H3)
(fun H2 : b => H2) H0) H)
If you look at the resulting proof-term, you see the Coq is essentially taking apart the boolean the constructors. We can do this manually and get the same proof-term:
Lemma it: forall a b, (a \/ b) /\ ~a -> b.
Proof.
intros a b H.
induction H.
induction H.
contradict H. exact H0.
exact H.
Qed.
Whereas e.g. modus ponens corresponds to an apply in Coq, I don't think this is "built in" in any direct way.
Afterwards, you can use this lemma (and I'm sure there's a corresponding version somewhere in the standard library) to derive your additional hypothesis through apply.
Related
I am trying to prove the following principle for stream predicates (defined in the standard library).
From Coq Require Import Streams.
Lemma mystream_ind :
forall A (P : Stream A -> Prop),
(forall s, ForAll P (tl s) -> ForAll P s) ->
forall s, ForAll P s.
Proof.
intros A P H.
cofix Cof.
destruct s as [a s].
constructor; auto.
destruct (H (Cons a s) (Cof s)); auto.
Fail Guarded.
Abort.
From my understanding of the syntactical guard conditions imposed by cofix, I will never be able to complete the proof this way because in the proof term, Cof s must appear under H, which is not a constructor nor a match, etc.
Is there another way to do it in Coq? I defined ForAll as an explicit fixpoint with paco and tried to prove the principle, without success (I couldn't instantiate H at all).
EDIT: this lemma is not provable as False can be derived from it by taking P := fun s => False (thank you Maƫlan).
When proving in Coq, it's nice to be able to prove one little piece at a time, and have Coq help keep track of the obligations.
Theorem ModusPonens: forall (A B : Prop), ((A -> B) /\ A) -> B.
Proof.
intros A B [H1 H2].
apply H1.
At this point I can see the proof state to know what is required to finish the proof:
context
H2: B
------
goal: B
But when writing Gallina, do we have to solve the whole thing in one bang, or make lots of little helper functions? I'd love to be able to put use a question mark to ask Coq what it's looking for:
Definition ModusPonens' := fun (A B : Prop) (H : (A -> B) /\ A) =>
match H with
| conj H1 H2 => H1 {?} (* hole of type B *)
end.
It really seems like Coq should be able to do this, because I can even put ltac in there and Coq will find what it needs:
Definition ModusPonens' := fun (A B : Prop) (H : (A -> B) /\ A) =>
match H with
| conj H1 H2 => H1 ltac:(assumption)
end.
If Coq is smart enough to finish writing the definition for me, it's probably smart enough to tell me what I need to write in order to finish the function myself, at least in simple cases like this.
So how do I do this? Does Coq have this kind of feature?
You can use refine for this. You can write underscores which will turn into obligations for you to solve later.
Definition ModusPonens: forall (A B : Prop), ((A -> B) /\ A) -> B.
refine (fun A B H =>
match H with
| conj H1 H2 => H1 _ (* hole of type A *)
end).
Now your goal is to provide an A. This can be discharged with exact H2. Defined.
Use an underscore
Definition ModusPonens' := fun (A B : Prop) (H : (A -> B) /\ A) =>
match H with
| conj H1 H2 => H1 _ (* hole of type A *)
end.
(*
Error: Cannot infer this placeholder of type
"A" in environment:
A, B : Prop
H : (A -> B) /\ A
H1 : A -> B
H2 : A
*)
or use Program
Require Import Program.
Obligation Tactic := idtac. (* By default Program tries to be smart and solve simple obligations automatically. This commands disables it. *)
Program Definition ModusPonens' := fun (A B : Prop) (H : (A -> B) /\ A) =>
match H with
| conj H1 H2 => H1 _ (* hole of type A *)
end.
Next Obligation. intros. (* See the type of the hole *)
I wanted to see a few hands on examples of Coq proofs of the form:
\exists A(x1,...,xn)
essentially where the Goal had an existential quantifier. I was having issues manipulating the goal in meaningful ways to make progress in my proof and wanted to see a few examples of common tactics to manipulate.
What are some good existential quantifiers examples in Coq to prove?
My specific example I had:
Theorem Big_Small_ForwardImpl :
forall (P : Program) (S' : State),
(BigStepR (B_PgmConf P) (B_StateConf S')) -> (ConfigEquivR (S_PgmConf P) (S_BlkConf EmptyBlk S')).
Proof.
intros.
induction P.
unfold ConfigEquivR.
refine (ex_intro _ _ _) .
my context and goals was:
1 subgoal
l : list string
s : Statement
S' : State
H : BigStepR (B_PgmConf (Pgm l s)) (B_StateConf S')
______________________________________(1/1)
exists N : nat, NSmallSteps N (S_PgmConf (Pgm l s)) (S_BlkConf EmptyBlk S')
but then changed to:
1 subgoal
l : list string
s : Statement
S' : State
H : BigStepR (B_PgmConf (Pgm l s)) (B_StateConf S')
______________________________________(1/1)
NSmallSteps ?Goal (S_PgmConf (Pgm l s)) (S_BlkConf EmptyBlk S')
after using the refine (ex_intro _ _ _) tactic. Since I am not sure what is going on I was hoping some simpler examples could show me how to manipulate existential quantifiers in my Coq goal.
helpful comment:
The ?Goal was introduced by Coq as a placeholder for some N that will have to be deduced later in the proof.
The following example is based on the code provided in this answer.
Suppose we have a type T and a binary relation R on elements of type T. For the purpose of this example, we can define those as follows.
Variable T : Type.
Variable R : T -> T -> Prop.
Let us prove the following simple theorem.
Theorem test : forall x y, R x y -> exists t, R x t.
Here is a possible solution.
Proof.
intros. exists y. apply H.
Qed.
Instead of explicitly specifying that y is the element we are looking for, we can rely on Coq's powerful automatic proof mechanisms in order to automatically deduce which variable satisfies R x t:
Proof.
intros.
eexists. (* Introduce a temporary placeholder of the form ?t *)
apply H. (* Coq can deduce from the hypothesis H that ?t must be y *)
Qed.
There exist numerous tactics that make ise of the same automated deduction mechanisms, such as eexists, eapply, eauto, etc.
Note that their names often correspond to usual tactics prefixed with an e.
Currently, I've started working on proving theorems about first-order logic in Coq(VerifiedMathFoundations). I've proved deduction theorem, but then I got stuck with lemma 1 for theorem of correctness. So I've formulated one elegant piece of the lemma compactly and I invite the community to look at it. That is an incomplete the proof of well-foundness of the terms. How to get rid of the pair of "admit"s properly?
(* PUBLIC DOMAIN *)
Require Export Coq.Vectors.Vector.
Require Export Coq.Lists.List.
Require Import Bool.Bool.
Require Import Logic.FunctionalExtensionality.
Require Import Coq.Program.Wf.
Definition SetVars := nat.
Definition FuncSymb := nat.
Definition PredSymb := nat.
Record FSV := {
fs : FuncSymb;
fsv : nat;
}.
Record PSV := MPSV{
ps : PredSymb;
psv : nat;
}.
Inductive Terms : Type :=
| FVC :> SetVars -> Terms
| FSC (f:FSV) : (Vector.t Terms (fsv f)) -> Terms.
Definition rela : forall (x y:Terms), Prop.
Proof.
fix rela 2.
intros x y.
destruct y as [s|f t].
+ exact False.
+ refine (or _ _).
exact (Vector.In x t).
simple refine (#Vector.fold_left Terms Prop _ False (fsv f) t).
intros Q e.
exact (or Q (rela x e)).
Defined.
Definition snglV {A} (a:A) := Vector.cons A a 0 (Vector.nil A).
Definition wfr : #well_founded Terms rela.
Proof.
clear.
unfold well_founded.
assert (H : forall (n:Terms) (a:Terms), (rela a n) -> Acc rela a).
{ fix iHn 1.
destruct n.
+ simpl. intros a b; destruct b.
+ simpl. intros a Q. destruct Q as [L|R].
* admit. (* smth like apply Acc_intro. intros m Hm. apply (iHn a). exact Hm. *)
* admit. (* like in /Arith/Wf_nat.v *)
}
intros a.
simple refine (H _ _ _).
exact (FSC (Build_FSV 0 1) (snglV a)).
simpl.
apply or_introl.
constructor.
Defined.
It is also available here: pastebin.
Update: At least transitivity is needed for well-foundness. I also started a proof, but didn't finished.
Fixpoint Tra (a b c:Terms) (Hc : rela c b) (Hb : rela b a) {struct a}: rela c a.
Proof.
destruct a.
+ simpl in * |- *.
exact Hb.
+ simpl in * |- *.
destruct Hb.
- apply or_intror.
revert f t H .
fix RECU 1.
intros f t H.
(* ... *)
Admitted.
You can do it by defining a height function on Terms, and showing that decreasing rela implies decreasing heights:
Require Export Coq.Vectors.Vector.
Require Export Coq.Lists.List.
Require Import Bool.Bool.
Require Import Logic.FunctionalExtensionality.
Require Import Coq.Program.Wf.
Definition SetVars := nat.
Definition FuncSymb := nat.
Definition PredSymb := nat.
Record FSV := {
fs : FuncSymb;
fsv : nat;
}.
Record PSV := MPSV{
ps : PredSymb;
psv : nat;
}.
Unset Elimination Schemes.
Inductive Terms : Type :=
| FVC :> SetVars -> Terms
| FSC (f:FSV) : (Vector.t Terms (fsv f)) -> Terms.
Set Elimination Schemes.
Definition Terms_rect (T : Terms -> Type)
(H_FVC : forall sv, T (FVC sv))
(H_FSC : forall f v, (forall n, T (Vector.nth v n)) -> T (FSC f v)) :=
fix loopt (t : Terms) : T t :=
match t with
| FVC sv => H_FVC sv
| FSC f v =>
let fix loopv s (v : Vector.t Terms s) : forall n, T (Vector.nth v n) :=
match v with
| #Vector.nil _ => Fin.case0 _
| #Vector.cons _ t _ v => fun n => Fin.caseS' n (fun n => T (Vector.nth (Vector.cons _ t _ v) n))
(loopt t)
(loopv _ v)
end in
H_FSC f v (loopv _ v)
end.
Definition Terms_ind := Terms_rect.
Fixpoint height (t : Terms) : nat :=
match t with
| FVC _ => 0
| FSC f v => S (Vector.fold_right (fun t acc => Nat.max acc (height t)) v 0)
end.
Definition rela : forall (x y:Terms), Prop.
Proof.
fix rela 2.
intros x y.
destruct y as [s|f t].
+ exact False.
+ refine (or _ _).
exact (Vector.In x t).
simple refine (#Vector.fold_left Terms Prop _ False (fsv f) t).
intros Q e.
exact (or Q (rela x e)).
Defined.
Require Import Lia.
Definition wfr : #well_founded Terms rela.
Proof.
apply (Wf_nat.well_founded_lt_compat _ height).
intros t1 t2. induction t2 as [sv2|f2 v2 IH]; simpl; try easy.
intros [t_v|t_sub]; apply Lt.le_lt_n_Sm.
{ clear IH. induction t_v; simpl; lia. }
revert v2 IH t_sub; generalize (fsv f2); clear f2.
intros k v2 IH t_sub.
enough (H : exists n, rela t1 (Vector.nth v2 n)).
{ destruct H as [n H]. apply IH in H. clear IH t_sub.
transitivity (height (Vector.nth v2 n)); try lia; clear H.
induction v2 as [|t2 m v2 IHv2].
- inversion n.
- apply (Fin.caseS' n); clear n; simpl; try lia.
intros n. specialize (IHv2 n). lia. }
clear IH.
assert (H : Vector.fold_right (fun t Q => Q \/ rela t1 t) v2 False).
{ revert t_sub; generalize False.
induction v2 as [|t2 n v2]; simpl in *; trivial.
intros P H; specialize (IHv2 _ H); clear H.
induction v2 as [|t2' n v2 IHv2']; simpl in *; tauto. }
clear t_sub.
induction v2 as [|t2 k v2 IH]; simpl in *; try easy.
destruct H as [H|H].
- apply IH in H.
destruct H as [n Hn].
now exists (Fin.FS n).
- now exists Fin.F1.
Qed.
(Note the use of the custom induction principle, which is needed because of the nested inductives.)
This style of development, however, is too complicated. Avoiding certain pitfalls would greatly simplify it:
The Coq standard vector library is too hard to use. The issue here is exacerbated because of the nested inductives. It would probably be better to use plain lists and have a separate well-formedness predicate on terms.
Defining a relation such as rela in proof mode makes it harder to read. Consider, for instance, the following simpler alternative:
Fixpoint rela x y :=
match y with
| FVC _ => False
| FSC f v =>
Vector.In x v \/
Vector.fold_right (fun z P => rela x z \/ P) v False
end.
Folding left has a poor reduction behavior, because it forces us to generalize over the accumulator argument to get the induction to go through. This is why in my proof I had to switch to a fold_right.
Suppose I have two functions f and g and I know f = g. Is there a forward reasoning 'function application' tactic that will allow me to add f a = g a to the context for some a in their common domain? In this contrived example, I could use assert (f a = g a) followed by f_equal. But I want to do something like this in more complex situations; e.g.,
Lemma fapp : forall (A B : Type) (P Q : A -> B) (a : A),
(fun (a : A) => P a) = (fun (a : A) => Q a) ->
P a = Q a.
I think I can't correctly infer the general problem that you have, given your description and example.
If you already know H : f = g, you can use that to rewrite H wherever you want to show something about f and g, or just elim H to rewrite everything at once. You don't need to assert a helper theorem and if you do, you'll obviously need something like assert or pose proof.
If that equality is hidden underneath some eta-expansion, like in your example, remove that layer and then proceed as above. Here are two (out of many) possible ways of doing that:
intros A B P Q a H. assert (P = Q) as H0 by apply H. rewrite H0; reflexivity.
This solves your example proof by asserting the equality, then rewriting. Another possibility is to define eta reduction helpers (haven't found predefined ones) and using these. That will be more verbose, but might work in more complex cases.
If you define
Lemma eta_reduce : forall (A B : Type) (f : A -> B),
(fun x => f x) = f.
intros. reflexivity.
Defined.
Tactic Notation "eta" constr(f) "in" ident(H) :=
pattern (fun x => f x) in H;
rewrite -> eta_reduce in H.
you can do the following:
intros A B P Q a H. eta P in H. eta Q in H. rewrite H; reflexivity.
(That notation is a bit of a loose cannon and might rewrite in the wrong places. Don't rely on it and in case of anomalies do the pattern and rewrite manually.)
I don't have a lot of experience with Coq or its tactics, but why not just use an auxiliary theorem?
Theorem fapp': forall (t0 t1: Type) (f0 f1: t0 -> t1),
f0 = f1 -> forall (x0: t0), f0 x0 = f1 x0.
Proof.
intros.
rewrite H.
trivial.
Qed.
Lemma fapp : forall (A B : Type) (P Q : A -> B) (a : A),
(fun (a : A) => P a) = (fun (a : A) => Q a) ->
P a = Q a.
Proof.
intros.
apply fapp' with (x0 := a) in H.
trivial.
Qed.