How to do cases with an inductive type in Coq - logic

I wan to use the destruct tactic to prove a statement by cases. I have read a couple of examples online and I'm confused. Could someone explain it better?
Here is a small example (there are other ways to solve it but try using destruct):
Inductive three := zero
| one
| two.
Lemma has2b2: forall a:three, a<>zero /\ a<>one -> a=two.
Now some examples online suggest doing the following:
intros. destruct a.
In which case I get:
3 subgoals H : zero <> zero /\ zero <> one
______________________________________(1/3)
zero = two
______________________________________(2/3)
one = two
______________________________________(3/3)
two = two
So, I want to prove that the first two cases are impossible. But the machine lists them as subgoals and wants me to PROVE them... which is impossible.
Summary:
How to exactly discard the impossible cases?
I have seen some examples using inversion but I don't understand the procedure.
Finally, what happens if my lemma depends on several inductive types and I still want to cover ALL cases?

How to discard impossible cases? Well, it's true that the first two obligations are impossible to prove, but note they have contradicting assumptions (zero <> zero and one <> one, respectively). So you will be able to prove those goals with tauto (there are also more primitive tactics that will do the trick, if you are interested).
inversion is a more advanced version of destruct. Additional to 'destructing' the inductive, it will sometimes generate some equalities (that you may need). It itself is a simple version of induction, which will additionally generate an induction hypothesis for you.
If you have several inductive types in your goal, you can destruct/invert them one by one.
More detailed walk-through:
Inductive three := zero | one | two .
Lemma test : forall a, a <> zero /\ a <> one -> a = two.
Proof.
intros a H.
destruct H. (* to get two parts of conjunction *)
destruct a. (* case analysis on 'a' *)
(* low-level proof *)
compute in H. (* to see through the '<>' notation *)
elimtype False. (* meaning: assumptions are contradictory, I can prove False from them *)
apply H.
reflexivity.
(* can as well be handled with more high-level tactics *)
firstorder.
(* the "proper" case *)
reflexivity.
Qed.

If you see an impossible goal, there are two possibilities: either you made a mistake in your proof strategy (perhaps your lemma is wrong), or the hypotheses are contradictory.
If you think the hypotheses are contradictory, you can set the goal to False, to get a little complexity out of the way. elimtype False achieves this. Often, you prove False by proving a proposition P and its negation ~P; the tactic absurd P deduces any goal from P and ~P. If there's a particular hypothesis which is contradictory, contradict H will set the goal to ~H, or if the hypothesis is a negation ~A then the goal will be A (stronger than ~ ~A but usually more convenient). If one particular hypothesis is obviously contradictory, contradiction H or just contradiction will prove any goal.
There are many tactics involving hypotheses of inductive types. Figuring out which one to use is mostly a matter of experience. Here are the main ones (but you will run into cases not covered here soon):
destruct simply breaks down the hypothesis into several parts. It loses information about dependencies and recursion. A typical example is destruct H where H is a conjunction H : A /\ B, which splits H into two independent hypotheses of types A and B; or dually destruct H where H is a disjunction H : A \/ B, which splits the proof into two different subproofs, one with the hypothesis A and one with the hypothesis B.
case_eq is similar to destruct, but retains the connections that the hypothesis has with other hypotheses. For example, destruct n where n : nat breaks the proof into two subproofs, one for n = 0 and one for n = S m. If n is used in other hypotheses (i.e. you have a H : P n), you may need to remember that the n you've destructed is the same n used in these hypotheses: case_eq n does this.
inversion performs a case analysis on the type of a hypothesis. It is particularly useful when there are dependencies in the type of the hypothesis that destruct would forget. You would typically use case_eq on hypotheses in Set (where equality is relevant) and inversion on hypotheses in Prop (which have very dependent types). The inversion tactic leaves a lot of equalities behind, and it's often followed by subst to simplify the hypotheses. The inversion_clear tactic is a simple alternative to inversion; subst but loses a little information.
induction means that you are going to prove the goal by induction (= recursion) on the given hypothesis. For example, induction n where n : nat means that you'll perform integer induction and prove the base case (n replaced by 0) and the inductive case (n replaced by m+1).
Your example is simple enough that you can prove it as “obvious by case analysis on a”.
Lemma has2b2: forall a:three, a<>zero/\a<>one ->a=two.
Proof. destruct a; tauto. Qed.
But let's look at the cases generated by the destruct tactic, i.e. after just intros; destruct a.. (The case where a is one is symmetric; the last case, where a is two, is obvious by reflexivity.)
H : zero <> zero /\ zero <> one
============================
zero = two
The goal looks impossible. We can tell this to Coq, and here it can spot the contradiction automatically (zero=zero is obvious, and the rest is a first-order tautology handled by the tauto tactic).
elimtype False. tauto.
In fact tauto works even if you don't start by telling Coq not to worry about the goal and wrote tauto without the elimtype False first (IIRC it didn't in older versions of Coq). You can see what Coq is doing with the tauto tactic by writing info tauto. Coq will tell you what proof script the tauto tactic generated. It's not very easy to follow, so let's look at a manual proof of this case. First, let's split the hypothesis (which is a conjunction) into two.
destruct H as [H0 H1].
We now have two hypotheses, one of which is zero <> zero. This is clearly false, because it's the negation of zero = zero which is clearly true.
contradiction H0. reflexivity.
We can look in even more detail at what the contradiction tactic does. (info contradiction would reveal what happens under the scene, but again it's not novice-friendly). We claim that the goal is true because the hypotheses are contradictory so we can prove anything. So let's set the intermediate goal to False.
assert (F : False).
Run red in H0. to see that zero <> zero is really notation for ~(zero=zero) which in turn is defined as meaning zero=zero -> False. So False is the conclusion of H0:
apply H0.
And now we need to prove that zero=zero, which is
reflexivity.
Now we've proved our assertion of False. What remains is to prove that False implies our goal. Well, False implies any goal, that's its definition (False is defined as an inductive type with 0 case).
destruct F.

Related

Coq `simpl` reduces `S n + m` to `S(n + m)` for free?

I'm just beginning to learn Coq via software foundations. One of the homework Theorems (with my successful proof elided) in Induction.v is:
Theorem plus_n_Sm : forall n m : nat,
S (n + m) = n + (S m).
Proof.
(* elided per request of authors *)
Qed.
Later, I noticed that the following similar "leftward" statement comes for free with the built-in tactic .simpl:
Example left_extract : forall n m : nat, S n + m = S (n + m).
Proof.
intros. simpl. reflexivity.
Qed.
I've perused the documentation and haven't been able to figure out why .simpl gives us one direction "for free" but the other direction requires a user-supplied proof. The documentation is over my head at this very early point in my learning.
I guess it has something to do with left-ness being built-in and right-ness being not, but the propositions seem to my childlike eyes to be of equal complexity and subtlety. Would someone be so kind as to explain why, and perhaps give me some guidance about what is going on with .simpl?
Why should I NOT be surprised by my finding?
What other good things can I expect from .simpl, so it surprises me less and so I can eventually predict what it's going to do and rely on it?
What's the best way to wade through the theory -- unfolding of iota reductions and what not -- to focus on the relevant bits for this phenomenon? Or do I have to learn all the theory before I can understand this one bit?
I believe your surprise stems from the fact that you are accustomed to think of addition as a primitive concept. It is not, it is a function that has been defined and other primitive concepts are used to explain its behavior.
The addition function is defined by a function with a name written with letters (not the + symbol) in a way that looks like this:
Fixpoint add (n m : nat) : nat :=
match n with
| 0 =>
| S p => S (add p)
end.
You can find this information by typing
Locate "_ + _".
The + notation is used for two functions, only one of them can be applied on numbers.
Coming back to the add function, its very description explains that add 0 m computes to m and add (S n) m computes to S (add m n), but it does not say anything when the second argument has the form S m, it is just not written anywhere. Still the theory of Coq makes it possible to prove the fact.
So the equality that is given for free comes directly from the definition of addition. There are a few other equality statements that are natural to the human eye, but not given for free. They can just be proved by induction.
Would it be possible to design the Coq system in such a way that both equality statements would be given for free? The answer is probably yes, but the theory must be designed carefully for that.

Flattening quantification over relations

I have a Relation f defined as f: A -> B × C. I would like to write a firsr-order formula to constrain this relation to be a bijective function from A to B × C?
To be more precise, I would like the first order counter part of the following formula (actually conjunction of the three):
∀a: A, ∃! bc : B × C, f(a)=bc -- f is function
∀a1,a2: A, f(a1)=f(a2) → a1=a2 -- f is injective
∀(b, c) : B × C, ∃ a : A, f(a)=bc -- f is surjective
As you see the above formulae are in Higher Order Logic as I quantified over the relations. What is the first-order logic equivalent of these formulae if it is ever possible?
PS:
This is more general (math) question, rather than being more specific to any theorem prover, but for getting help from these communities --as I think there are mature understanding of mathematics in these communities-- I put the theorem provers tag on this question.
(Update: Someone's unhappy with my answer, and SO gets me fired up in general, so I say what I want here, and will probably delete it later, I suppose.
I understand that SO is not a place for debates and soapboxes. On the other hand, the OP, qartal, whom I assume is the unhappy one, wants to apply the answer from math.stackexchange.com, where ZFC sets dominates, to a question here which is tagged, at this moment, with isabelle and logic.
First, notation is important, and sloppy notation can result in a question that's ambiguous to the point of being meaningless.
Second, having a B.S. in math, I have full appreciation for the logic of ZFC sets, so I have full appreciation for math.stackexchange.com.
I make the argument here that the answer given on math.stackexchange.com, linked to below, is wrong in the context of Isabelle/HOL. (First hmmm, me making claims under ill-defined circumstances can be annoying to people.)
If I'm wrong, and someone teaches me something, the situation here will be redeemed.
The answerer says this:
First of all in logic B x C is just another set.
There's not just one logic. My immediate reaction when I see the symbol x is to think of a type, not a set. Consider this, which kind of looks like your f: A -> BxC:
definition foo :: "nat => int × real" where "foo x = (x,x)"
I guess I should be prolific in going back and forth between sets and types, and reading minds, but I did learn something by entering this term:
term "B × C" (* shows it's of type "('a × 'b) set" *)
Feeling paranoid, I did this to see if had fallen into a major gotcha:
term "f : A -> B × C"
It gives a syntax error. Here I am, getting all pedantic, and our discussion is ill-defined because the notation is ill-defined.
The crux: the formula in the other answer is not first-order in this context
(Another hmmm, after writing what I say below, I'm full circle. Saying things about stuff when the context of the stuff is ill-defined.)
Context is everything. The context of the other site is generally ZFC sets. Here, it's HOL. That answerer says to assume these for his formula, wich I give below:
Ax is true iff x∈A
Bx is true iff x∈B×C
Rxy is true iff f(x)=y
Syntax. No one has defined it here, but the tag here is isabelle, so I take it to mean that I can substitute the left-hand side of the iff for the right-hand side.
Also, the expression x ∈ A is what would be in the formula in a typical set theory textbook, not Rxy. Therefore, for the answerer's formula to have meaning, I can rightfully insert f(x) = y into it.
This then is why I did a lot of hedging in my first answer. The variable f cannot be in the formula. If it's in the formula, then it's a free variable which is implicitly quantified. Here's the formula in Isar syntax:
term "∀x. (Ax --> (∃y. By ∧ Rxy ∧ (∀z. (Bz ∧ Rxz) --> y = z)))"
Here it is with the substitutions:
∀x. (x∈A --> (∃y. y∈B×C ∧ f(x)=y ∧ (∀z. (z∈B×C ∧ f(x)=z) --> y = z)))
In HOL, f(x) = f x, and so f is implicitly, universally quantified. If this is the case, then it's not first-order.
Really, I should dig deep to recall what I was taught, that f(x)=y means:
(x,f(x)) = (x,y) which means we have to have (x,y)∈(A, B×C)
which finally gets me:
∀x. (x∈A -->
(∃y. y∈B×C ∧ (x,y)∈(A,B×C) ∧ (∀z. (z∈B×C ∧ (x,z)∈(A,B×C)) --> y = z)))
Finally, I guess it turns out that in the context of math.stackexchange.com, it's 100% on.
Am I the only one who feels compulsive about questioning what this means in the context of Isabelle/HOL? I don't accept that everything here is defined well enough to show that it's first order.
Really, qartal, your notation should be specific to a particular logic.
First answer
With Isabelle, I answer the question based on my interpretation of your
f: A -> B x C, which I take as a ZFC set, in particular a subset of the
Cartesian product A x (B x C)
You're sort of mixing notation from the two logics, that of ZFC
sets and that of HOL. Consequently, I might be off on what I think you're
asking.
You don't define your relation, so I keep things simple.
I define a simple ZFC function, and prove the first
part of your first condition, that f is a function. The second part would be
proving uniqueness. It can be seen that f satisfies that, so once a
formula for uniqueness is stated correctly, auto might easily prove it.
Please notice that the
theorem is a first-order formula. The characters ! and ? are ASCII
equivalents for \<forall> and \<exists>.
(Clarifications must abound when
working with HOL. It's first-order logic if the variables are atomic. In this
case, the type of variables are numeral. The basic concept is there. That
I'm wrong in some detail is highly likely.)
definition "A = {1,2}"
definition "B = A"
definition "C = A"
definition "f = {(1,(1,1)), (2,(1,1))}"
theorem
"!a. a \<in> A --> (? z. z \<in> (B × C) & (a,z) \<in> f)"
by(auto simp add: A_def B_def C_def f_def)
(To completely give you an example of what you asked for, I would have to redefine my function so its bijective. Little examples can take a ton of work.)
That's the basic idea, and the rest of proving that f is a function will
follow that basic pattern.
If there's a problem, it's that your f is a ZFC set function/relation, and
the logical infrastructure of Isabelle/HOL is set up for functions as a type.
Functions as ordered pairs, ZFC style, can be formalized in Isabelle/HOL, but
it hasn't been done in a reasonably complete way.
Generalizing it all is where the work would be. For a particular relation, as
I defined above, I can limit myself to first-order formulas, if I ignore that
the foundation, Isabelle/HOL, is, of course, higher-order logic.

Prove or Disprove quantifiers (propositions logic)

What approach can i take to solve these question:
Prove or disprove the following statements. The universe of discourse is N = {1,2,3,4,...}.
(a) ∀x∃y,y = x·x
(b) ∀y∃x,y = x·x
(c) ∃y∀x,y = x·x.
The best way to solve such problems is first to think about them until you're confident that they can be either proven or disproven.
If they can be disproven, then all you have to do to disprove the statement is provide a counterexample. For instance, for b, I can think of the counterexample y=2. There is no number x in N for which n*n = 2. Thus, there is a counterexample, and the statement is false.
If the statement appears to be true, it may be necessary to use some axioms or tautologies to prove the statment. For instance, it is known that two integers that are multiplied together will always produce another integer.
Hopefully this is enough of an approach to get you going.
To prove something exists, find one example for which it is true.
To prove ∀x F(x), take an arbitrary constant a and prove F(a) is true.
Counterexamples can be used to disprove ∀ statements, but not ∃ statements. To disprove ∃x F(x), prove that ∀x !F(x). So, take an arbitrary constant a and show that F(a) is false.

Proof by cases using Coq

I have a simple theorem that I want to prove using proof by cases. An example is given below.
Goal forall a b : Set, a = b \/ a <> b.
Proof
intros a b.
...
How would I go about solving this. And, exactly how would I define a proof by cases using the two possible values of an equality (True or False)?
Any help would be appreciated.
Thanks,
I am pretty sure that equality of Sets is not decidable in Coq. The reasons (to my limited understanding) would be that it is not an inductively-defined set (so, no case analysis for you...), and that it is not a closed set either: everytime you define a new datatype, you create a new family of inhabitants of Set. Therefore, the term that proved the goal you show would need to be updated to reflect these new inhabitants.
As #hardmath mentions in his comment, you may prove your goal using Classical assumptions (Axiom classic : forall P:Prop, P \/ ~ P.).
As #Robin Green mentions in a comment here, you can prove this kind of goal for types that are decidably equal. To this purpose, you may want to get help from the decide equality tactic. See: http://coq.inria.fr/distrib/V8.4/refman/Reference-Manual011.html##tactic121
Your question touches an interesting aspect of Coq: the difference between propositions (i.e., members of Prop) and booleans (i.e., members of bool). Explaining this difference in detail would be somewhat too technical, so I'll just try to focus on your particular example.
Roughly speaking, a Prop in Coq is not something that evaluates to either True or False, like a regular boolean does. Instead, Props have inference rules that can be combined to infer facts. Using those, we can show that a proposition holds, or show that it is contradictory. What makes things subtle is that there is a third possibility, namely that we're not able to either prove or refute the proposition. This happens because Coq is a constructive logic. One of the most well-known consequences of this is that the familiar reasoning principle known as the excluded middle (forall P : Prop, P \/ ~ P) can't be proved in Coq: if you assert that P \/ ~ P, this means you're either able to prove P or to prove ~ P. You can't assert this without knowing which one holds.
It turns out that for some propositions, we can show that P \/ ~ P holds. For instance, it is not hard to show forall n m : nat, n = m \/ n <> m. Following the above remark, this means that for every pair of natural numbers, we are able to produce a proof that they are equal or a proof that they aren't.
On the other hand, if we change nat to Set, like in your example, then we will never be able to prove the theorem. To see why, consider the Set nat * nat of pairs of natural numbers. If we were able to prove your theorem, then it would follow that nat = nat * nat \/ nat <> nat * nat. Again, by the above remark, this means that we're either able to prove nat = nat * nat or nat <> nat * nat. However, because there is a bijection between both types, we can't say that it is contradictory to assume nat = nat * nat, but because the types are not syntactically equal, it is also OK to assume that they are different. Technically speaking, the validity of the proposition nat = nat * nat is independent of Coq's logic.
If you really need the fact that you mentioned, then you need to assert the excluded middle as an axiom (Axiom classical : forall P, P \/ ~ P.), which will allow you to produce proofs of \/ without having an explicit proof of either side and to reason by cases. Then you would be able to proof your example theorem with something like
intros a b. destruct (classical (a = b)).
left. assumption.
right. assumption.
Hope this helps.

How to prove forall n:nat, ~n<n in Coq?

I've been confused for hours and I cannot figure out how to prove
forall n:nat, ~n<n
in Coq. I really need your help. Any suggestions?
This lemma is in the standard library:
Require Import Arith.
Lemma not_lt_refl : forall n:nat, ~n<n.
Print Hint.
Amongst the results is lt_irrefl. A more direct way of realizing that is
info auto with arith.
which proves the goal and shows how:
intro n; simple apply lt_irrefl.
Since you know where to find a proof, I'll just give a hint on how to do it from first principles (which I suppose is the point of your homework).
First, you need to prove a negation. This pretty much means you push n<n as a hypothesis and prove that you can deduce a contradiction. Then, to reason on n<n, expand it to its definition.
intros h H.
red in H. (* or `unfold lt in H` *)
Now you need to prove that S n <= n cannot happen. To do this from first principles, you have two choices at that point: you can try to induct on n, or you can try to induct on <=. The <= predicate is defined by induction, and often in these cases you need to induct on it — that is, to reason by induction on the proof of your hypothesis. Here, though, you'll ultimately need to reason on n, to show that n cannot be an mth successor of S n, and you can start inducting on n straight away.
After induction n, you need to prove the base case: you have the hypothesis 1 <= 0, and you need to prove that this is impossible (the goal is False). Usually, to break down an inductive hypothesis into cases, you use the induction tactic or one of its variants. This tactic constructs a fairly complex dependent case analysis on the hypothesis. One way to see what's going on is to call simple inversion, which leaves you with two subgoals: either the proof of the hypothesis 1 <= 0 uses the le_n constructor, which requires that 1 = 0, or that proof uses the le_S constructor, which requires that S m = 0. In both cases, the requirement is clearly contradictory with the definition of S, so the tactic discriminate proves the subgoal. Instead of simple inversion H, you can use inversion H, which in this particular case directly proves the goal (the impossible hypothesis case is very common, and it's baked into the full-fledged inversion tactic).
Now, we turn to the induction case, where we quickly come to the point where we would like to prove S n <= n from S (S n) <= S n. I recommend that you state this as a separate lemma (to be proved first), which can be generalized: forall n m, S n <= S m -> n <= m.
Require Import Arith.
auto with arith.

Resources