I have to prove the following statement, however I am getting the error The type of H is not inductive. when trying to use inversion statement:
How can I do that correctly?
Variables phi: Prop.
Section absurd_rule.
Hypothesis H1: phi -> true = false.
Lemma absurd_rule: ~phi.
Proof.
intro H.
inversion H.
End absurd_rule.
inversion is not the right rule to be used here, as there is nothing to invert on H : phi.
Let's take a pause after you intro H:
H1 : phi -> true = false
H : phi
______________________________________(1/1)
False
First of all, note that H1 H : true = false (simple application). Let's take advantage of it by writing apply H1 in H:
H : true = false
______________________________________(1/1)
False
Almost there! Now, it is necessarily contradictory that true = false, and that's because of conflicting constructors.
There is a dedicated rule to deal with such cases, namingly discriminate H.
No more subgoals, we are there. The full proof session looks like this:
Variables phi: Prop.
Section absurd_rule.
Hypothesis H1 : phi -> true = false.
Lemma absurd_rule : ~phi.
Proof.
intro H.
apply H1 in H.
discriminate H.
Qed.
Also, worth noting that you can use False to describe bottom (lowercase false is a different thing -- an inductive boolean, instead of an empty Prop).
A simpler version of your proof would be just
Variables phi: Prop.
Section absurd_rule.
Hypothesis H1 : phi -> False.
Lemma absurd_rule : ~phi.
Proof.
assumption.
Qed.
...which is not a big discovery, because you just assumed phi to be false.
After a second of reflection...
You can't "prove a rule". Rules are semantics of the language, laws you use to derive conclusions from assumptions. They are not "theorems" to be proven, but a sort of prior reasoning you use to manipulate sentences. They are even distinct from axioms, it's something on the meta level. You can prove an implication, but not a deduction rule.
Thus, the "solution" to your problem is just an identity. Your absurd_rule is just a lemma that not phi implies not phi, which is trivially true -- remember that in intuitionistic logic negation is very often defined as to imply false.
Related
I'm reading the book Software Foundations and got stuck at the very beginning.
The author defined a boolean type and common operations:
Inductive bool: Type :=
| true
| false.
Definition orb (b1: bool) (b2: bool) : bool :=
match b1 with
| true => true
| false => b2
end.
So let's say we want to prove the correctness of the or function.
The author wrote a test followed by a proof:
Example test_orb1: (orb true false) = true.
Proof. simpl. reflexivity. Qed.
Could someone explain to me what simpl. reflexivity mean? Is there any other way we can prove this simple test?
simpl is a tactic evaluating the goal. In your case, after executing it, the goal will be left to true = true.
reflexivity is a tactic discharging goals of the shape x = x (in its simplest incarnation). What it does under the hood is to provide the proof term eq_refl : x = x as a solution to the current proof obligation.
Now, there are many ways to achieve this thing that ultimately will produce the same (rather trivial) proof eq_refl (try doing Print test_orb1.). First, the simpl operation is not needed because Coq will do some computations when applying a term (in particular when calling reflexivity). Second, you could obtain the same effect as reflexivity by calling constructor, apply eq_refl or refine eq_refl. These are tactics with different goals but that happen to coincide here.
Inductive Foo : nat -> Type :=
| a : Foo 1.
(* ... *)
Goal forall m, Foo m -> m = 1.
Proof.
auto.
Fail Qed.
Is there a straightforward approach to do this?
You can use Hint Extern together with a tactic script that executes the case analysis. For example, this one will use destruct if the argument is a variable, and use inversion_clear otherwise:
Inductive Foo : nat -> Type :=
| a : Foo 1.
Hint Extern 1 => match goal with
| [ H : Foo ?m |- _ ]
=> first [ is_var m; destruct H | inversion_clear H ]
end.
Goal forall m, Foo m -> m = 1.
Proof.
auto.
Qed.
Via Programming Language Foundations, chapter Theory and Practice of Automation in Coq Proofs:
Note that proof search tactics never perform any rewriting step (tactics rewrite, subst), nor any case analysis on an arbitrary data structure or property (tactics destruct and inversion), nor any proof by induction (tactic induction). So, proof search is really intended to automate the final steps from the various branches of a proof. It is not able to discover the overall structure of a proof.
So there is really no way to do this; this goal should be solved manually, and then added to the hint database (Hint blah.).
I currently am at chapter 5 of "Software foundations" but felt the need to get back to chapter one to clarify a couple of things. In particular there is an exercise I did not quite digested, in which we are asked to use destruct twice to prove a result on booleans. Here it is with names and other details changed.
Inductive bool: Type :=
|true: bool
|false: bool.
Definition fb (b1:bool) (b2:bool) : bool :=
match b1, b2 with
| false, false => false
| _, _ => true
end.
Theorem th: forall a b: bool,
fb a b = false -> b = false.
Proof.
intros [] [] H.
- rewrite <- H. reflexivity.
- reflexivity.
- rewrite <- H. reflexivity.
- reflexivity.
Qed.
When at the first tick, context and goal are both nonsense:
H : fb true true = false
______________________________________(1/1)
true = false
Second tick the hypothesis is false. Third tick is same kind of nonsense as first one. Only fourth tick is reasonable with:
H : fb false false = false
______________________________________(1/1)
false = false
I understand that by the rewrite rules, all these things do work. However I have the impression we are quitting the narrow path of truth for the wilderness of falsity. More precisely, and AFAIK, a false hypothesis can be made to prove ANY statement, true or false. Here we use it to prove that false = true, OK why not, but still that makes me feel somewhat uncomfortable. I would not have expected a proof assistant to allow this.
Elaborating a bit
In a typical proof by contradiction, I would pick an hypothesis at random, and derive the goal till I find either a tautology or a contradiction. I would then conclude whether my hypothesis was true or false.
What happens here, in cases 1 (same for case 3), Coq starts from an hypothesis that is false:
H : fb true true = false
applies it to a goal that is a contradiction:
true = false
and combines them to find a tautology.
That is not a way of reasoning I am aware of. That recalls student 'jokes' where starting with 0=1 any absurd result on natural numbers can be proven.
Followup
So this morning during my commute I was thinking about what I had just written above. I now believe that cases 1 and 3 are proper proofs by contradiction. Indeed H is false and we use it to prove a goal that is a false. Hypotheses (values of a and b) have to be rejected. What may have confused me is that using rewrite we are doing part of the way "backward", starting from the goal.
I am a bit undecided for case 2, which reads:
H : fb true false = false
______________________________________(1/1)
false = false
which is basically false -> true, a tautology under the "principle of explosion". I would not think that could be used so directly in a proof.
Oh well, not sure I completely understood what's under the hood, but trust in Coq is untouched. Gotta go on and return to chapter 5. Thanks all for your comments.
First of all, thanks for providing a self-contained code.
I understand your uneasiness proving a goal using rewrite when you know that what you really ought to do is to derive a contradiction from the hypotheses. That does not make the reasoning incorrect though. It is true that under such assumptions you can prove this goal.
However I also think that this does not make the proof script really readable. In your example, you are considering all possible cases and it happens that three out of these four are impossible. When we read your proof we cannot see that. To make it clear that you are in an impossible case, there are a few tactic which are useful to say "look, I am now going to prove a contradiction to rule out this case".
One of them is exfalso. It will replace the current goal by False (since anything can be derived from False, as mentioned by #ejgallego in a comment).
A second one is absurd to say "I am now going to prove some statement and its negation" (this is basically equivalent to proving False).
A third one which is enough in your case is discriminate. It tries to find in the hypotheses a contradictory equality, such as true = false.
Theorem th: forall a b: bool,
fb a b = false -> b = false.
Proof.
intros [] [] H.
- discriminate.
- discriminate.
- discriminate.
- reflexivity.
Qed.
Now, just so you know, discriminate and reflexivity are both tried by the easy tactic. Thus the following proof will work as well (but it does not show what is going on and thus falls out of the scope of this question):
Theorem th: forall a b: bool,
fb a b = false -> b = false.
Proof.
intros [] [] H; easy.
Qed.
and this is syntactic sugar for the same proof:
Theorem th: forall a b: bool,
fb a b = false -> b = false.
Proof.
now intros [] [] H.
Qed.
In mathematics, we often proceed as follows: "Now let us consider two cases, the number k can be even or odd. For the even case, we can say exists k', 2k' = k..."
Which expands to the general idea of reasoning about an entire set of objects by disassembling it into several disjunct subsets that can be used to reconstruct the original set.
How is this reasoning principle captured in coq considering we do not always have an assumption that is one of the subsets we want to deconstruct into?
Consider the follow example for demonstration:
forall n, Nat.Even n => P n.
Here we can naturally do inversion on Nat.Even n to get n = 2*x (and an automatically-false eliminated assumption that n = 2*x + 1). However, suppose we have the following:
forall n, P n
How can I state: "let us consider even ns and odd ns". Do I need to first show that we have decidable forall n : nat, even n \/ odd n? That is, introduce a new (local or global) lemma listing all the required subsets? What are the best practices?
Indeed, to reason about a splitting of a class of objects in Coq you need to show an algorithm splitting them, unless you want to reason classically (there is nothing wrong with that).
IMO, a key point is getting such decidability hypotheses "for free". For instance, you could implement odd : nat -> bool as a boolean function, as it is done in some libraries, then you get the splitting for free.
[edit]
You can use some slightly more convenient techniques for pattern matching, by enconding the pertinent cases as inductives:
Require Import PeanoNat Nat Bool.
CoInductive parity_spec (n : nat) : Type :=
| parity_spec_odd : odd n = true -> parity_spec n
| parity_spec_even: even n = true -> parity_spec n
.
Lemma parityP n : parity_spec n.
Proof.
case (even n) eqn:H; [now right|left].
now rewrite <- Nat.negb_even, H.
Qed.
Lemma test n : even n = true \/ odd n = true.
Proof. now case (parityP n); auto. Qed.
Let us assume that we want to prove the following (totally contrived) lemma.
Lemma lem : (forall n0 : nat, 0 <= n0 -> 0 <= S n0) -> forall n, le 0 n.
We want to apply nat_ind to prove it. Here is a possible proof:
Proof.
intros H n. apply nat_ind. constructor. exact H.
Qed.
But why not directly using H in the apply tactic, using something like apply (nat_ind _ _ H) or eapply (nat_ind _ _ H) ? But the first one fails, and the second one hides the remaining goal in an existential variable.
Is it possible in apply or its derivatives to skip hypotheses in order to specify the other arguments while keeping them as classic goals in the remainder of the proof ?
If you do
intros. refine (nat_ind _ _ H _).
then you only have
0 <= 0
left. Is that useful in your case?
Another approach (more universal than in my other answer) would be using the apply ... with ... construct, like this:
intros H n.
apply nat_ind with (2 := H).
Here, 2 is referring to the inductive step parameter of nat_ind (see the Coq v8.5 reference manual, 8.1.3):
In a bindings list of the form (ref_1 := term_1) ... (ref_n := term_n), ref is either an ident or a num. ... If ref_i is some number n, this number denotes the n-th non dependent premise of the term, as determined by the type of term.
This partial proof
intros H n.
apply nat_ind, H.
will give you 0 <= 0 as the only subgoal left.
This approach uses the apply tactic, but does not answer the question in its generality, since it will work only if you want to instantiate the last parameter (which is the case for the example in the question).
Here is quote from the Coq reference manual:
apply term_1 , ... , term_n
This is a shortcut for apply term_1 ; [ .. | ... ; [ .. | apply term_n ]... ], i.e. for the successive applications of term_(i+1) on the last subgoal generated by apply term_i, starting from the application of term_1.
Also, since it's just syntactic sugar, the solution may be considered cheating (and, I guess, abuse of the original intent of the Coq tactics developers) in the context of the question.