how to do a proof for subset in Isabelle - set

I'm trying to do some proofs manually in Isabelle but I'm struggling with the following proof:
lemma "(A ∩ B) ∪ C ⊆ A ∪ C "
I'm trying to transform it Propositional Logic then prove it.
So here's what I tried:
lemma "(A ∩ B) ∪ C ⊆ A ∪ C "
apply (subst subset_iff)+
apply(rule allI)
apply (rule impI)
(*here normally we should try to get rid of Union and Inter*)
apply(subst Un_iff)+
apply(subst (asm) Un_iff)+
apply(subst Inter_iff) (*not working*)
I'm stuck at the last step, could someone please help me finish this proof and explain how should one find the right theorems till the end?
I use find_theorems, but it takes a lot of time + the only useful (and understandable) ressource I found so far is this link:
https://www.inf.ed.ac.uk/teaching/courses/ar/isabelle/FormalCheatSheet.pdf
and some very few random lecture notes containing almost the same content as the link above...
Other resources I found are 100+ pages and do not look like a place to start for a beginner...
Thanks in advance

First writing such kind of proofs manually is not useful as it can be solved by blast. It is mostly reserved for advanced users. The only documentation I know is the old tutorial, Section 5.
Anyway, you have the wrong intersection theorems: you want to use Int_iff. Here is the full proof:
lemma "(A ∩ B) ∪ C ⊆ A ∪ C "
apply (subst subset_iff)+
apply(rule allI)
apply (rule impI)
(*here normally we should try to get rid of Union and Inter*)
apply(subst Un_iff)+
apply(subst (asm) Un_iff)
apply(subst (asm) Int_iff)
apply (elim disjE)
apply (elim conjE)
apply (rule disjI1)
apply assumption
apply (rule disjI2)
apply assumption
done
How did would I find such proof? I know by heart the low-level theorems on implication, conjunction, and disjunction (allI, impI, conjI, conjE, disjE, disjI1,...). There is a consistent naming convention (I: intro rule, E: elimination rule, D: destruction rule), so it is not so hard to remember.
For the rest, searching with find_theorems (or the query panel) is the way to go.
Here is the proof I would write (but the other one is nicer for teaching: conjE is way more important than IntE):
lemma "(A ∩ B) ∪ C ⊆ A ∪ C "
apply (rule subset_iff[THEN iffD2])
apply(intro allI impI)
apply (elim UnE)
apply (elim IntE)
apply (rule UnI1)
apply assumption
apply (rule UnI2)
apply assumption
done

Related

Solve specific combination in propositional logic rule set (SAT Solver)

In the car industry you have thousand of different variants of components available to choose from when you buy a car. Not every component is combinable, so for each car there exist a lot of rules that are expressed in propositional logic. In my case each car has between 2000 and 4000 rules.
They look like this:
A → B ∨ C ∨ D
C → ¬F
F ∧ G → D
...
where "∧" = "and" / "∨" = "or" / "¬" = "not" / "→" = "implication".
With the tool "limboole" (http://fmv.jku.at/limboole/) I am able to to convert the propositional logic expressions into conjunctive normal form (CNF). This is needed in case I have to use a SAT solver.
Now, I would like to check the buildability feasibility for specific components within the rule set. For example, for each of the following expressions or combinations, I would like to check if the are feasible within the rule set.
(A) ∧ (B)
(A) ∧ (C ∨ F)
(B ∨ G)
...
My question is how to solve this problem. I asked a similar questions before (Tool to solve propositional logic / boolean expressions (SAT Solver?)), but with a different focus and now I am stuck again. Or I just do not understand it.
One option is to calculate all solutions with an ALLSAT approach of the rule set. Then I could check if each combination is part of any solution. If yes, I can derive that this specific combination is feasible.
Another option would be, that I add the combination to the rule set and then run a normal SAT solver. But I would have to do it for each expression I want to check.
What do you think is the most elegant or rather easiest way to solve this problem?
The best method which is known to me is to use "incremental solving under assumptions" technique. It was motivated by the same problem you have: multiple SAT instances (CNF formulae) which have some common subformulae.
Formally, you have some core Boolean formula C in CNF. And you have a set of assumptions {A_i}, i=1..n, where A_i is a Boolean formula in CNF also.
On the step 0 you provide to the solver your core formula C. It tries to solve it, says a result to you and save its state (lets call this state as core-state). If formula C is satisfiable, on the step i you provide assumption A_i to the solver and it continues its execution from the core-state. Actually, it tries to solve a formula C ∧ A_i but not from the beginning.
You can find a bunch of papers related to this topic easily, where much information is located. Also, you can check you favorite SAT-solver for the support of this technique.

proving not (iff a (not a)) with basic tactics

My experience proving contradictory things in Coq is very limited and I can't find an explicit way to prove the following theorem with basic tactics:
Theorem thrm : forall a, not (iff a (not a)).
I can prove it immediately with firstorder or intuition, but these tactics are like magic to me, my impression is that they involve some sophisticated automation. What would be a more explicit way to prove this theorem with simple explicit tactics such as rewrite, destruct, apply, assert?
In order to prove a negated proposition not something, one can use the intros tactic to add the expectedly-wrong assumption to the context and then prove that the context indeed is inconsistent. This is due to the fact not something is an abbreviation for something -> False. You can notice this by typing Print not. or during a proof, unfold not. to substitute the goal accordingly.
Then, to discharge the goal so obtained, several tactics may be used depending on the context, for example:
tactics intros, apply, exact and assumption for minimal propositional logic;
tactics such as destruct, inversion, discriminate or injection in the presence of inductive types;
etc., see the Coq reference manual
In your example, intros, destruct, apply and assumption are enough:
Theorem thrm : forall a, not (iff a (not a)).
Proof.
intros a Hiff; destruct Hiff as [H1 H2].
apply H1; apply H2; intros Ha; apply H1; assumption.
Qed.
Note that the proof can also be shortened to this equivalent version:
Theorem thrm : forall a, not (iff a (not a)).
Proof. now intros a [H1 H2]; apply H1; apply H2; intros Ha; apply H1. Qed.
where now something is a notation for something; easy (cf. the doc).
Hoping this helps

Solve ~(P /\ Q) |- Q -> ~P in Isabelle

~(P /\ Q) |- Q -> ~P
I don't know where to start.
Negation confuses me.
I have to solve this in Isabelle (a program), but if someone explains how to solve using natural deduction, it will be enough help.
This is an example that the quality of an SO question is many times determined by an answer, not the question. I kind of give this answer to thank M.Eberl for another useful answer, since I can't make comments.
As to a comment above, that you may be asking a homework question, the comment is valid, but if you're confused by negation, then you're mostly doomed anyway, until you make progress, so even one complete answer wouldn't help you, and here, there's no right answer.
The formula is so basic, except through applying step-by-step rules, it would be hard for anyone to prove that they understand what they're proved, without going through the multitude of tedious steps to do so.
For example:
lemma "~(P ∧ Q) ==> Q --> ~P"
by auto
Surely that gets you nothing, if the requirement is that you demonstrate understanding.
I've largely made progress "by the method of absorption over time", and in his answer, M.Eberl gave a significant outline of the basics of natural deduction. My interest in it was to mess around and see if I could absorb a little more.
As to rule and erule, there is the cheat sheet:
http://www.phil.cmu.edu/~avigad/formal/FormalCheatSheet.pdf
As to the proof of logic by means of Isabelle, Isabelle/HOL is so big and involved, that a little help, once, doesn't get you much, though collectively, it's all important.
A basic, logic equivalency
I learned long ago the equivalent statement of an implication. It's even in HOL.thy, line 998:
lemma disj_not2: "(P | ~Q) = (Q --> P)"
From that, it's easy to see, along with DeMorgon's laws (line 993 of HOL.thy), that you stated an equivalency in your question.
Well, of course, not quite, and that's where all the hassle comes in. Rearranging things, based on trivial equivalencies, to finally prove the equivalency. (While also knowing what the notation means, such as that your |- will be ==>. I use ASCII because I don't trust the graphical in browsers.)
M.Eberl mentioned structured proofs. Consider this one:
lemma "~(P ∧ Q) ==> Q --> ~P"
proof-
fix P Q :: bool
assume "~(P ∧ Q)"
hence "~P ∨ ~Q" by simp
hence "~Q ∨ ~P" by metis
thus "Q --> ~P" by metis
qed
What would I deserve in points, for homework? Nothing much. It's actually a testimony that metis knows how to use basic first-order logic. Otherwise, how did it know to make the jump from ~Q ∨ ~P to Q --> ~P?
Assuming you are talking about Isabelle/HOL, you can use ‘single-step tactics’ like rule, erule, assumption with the basic natural deduction rules. The ones you will probably need for your proposition are:
introduction rules notI, conjI, disjE impI
elimination rules like notE, conjE, disjE, impE
destruction rules like mp (modus ponens), conjunct1, conjunct2
If you want to find out what a particular rule means, just write e.g. thm notI and Isabelle will display the statement of the theorem.
You can set up a goal like
lemma "¬(P ∧ Q) ⟹ Q ⟶ ¬P"
and then write e.g.
apply (rule impI)
to apply the introduction rules for implication, which leaves you with the updated goal state
goal (1 subgoal):
1. ¬ (P ∧ Q) ⟹ Q ⟹ ¬ P
Now you find the next appropriate rule and apply that one etc. until all subgoals are solved. Then you can write done and your proof is complete.
As for assumption and erule: if you end up with a goal that has some P to prove and P is already in the assumptions, you can use apply assumption to solve it. (erule is like rule with assumption chained directly after it and is often convenient for applying elimination rules)
However, this kind of proof is very tedious to do. A better way would be to do the whole proof in Isar, Isabelle's structured proof language. For an introduction to Isar, you can have a look at chapter 5 of Concrete Semantics.
Similar to a JIT compiler, this is a LJEFAATGAA answer (learn just enough from another answer to give an answer).
This is more about what I learned than about what others may learn, which may help others learn; the Isabelle learning curve is quite brutal. I'd think the time has come and gone for the OP's need for help.
Except for M.Eberl's answer to exI and refl behavior explanation needed, it would still be a mystery to me about why rule thm produces specific goal states, for a particular thm, and why rule thm produces the message Failed to apply initial proof method.
Except for the precise outline given by Chris, with the rules and braces, I wouldn't have been able to fill in the precise details. An example that if a person has the time to learn, it's better for them to be given a partial answer, to make them do a little work, than to give them the complete answer.
Two main driving points
After a few comments, I show my proof from the outline. It got me the following understanding from having to work out the details, where I talk as if I know I'm right:
The use of apply(rule thm) is being applied to a combination of the chained facts and the goal statement, where this, in the output, displays one or more chained facts.
Braces start and end a local context/scope. Variables inside and outside the context/scope work as we would expect them to work, that is, as scope normally works in programming languages. So if I state fix P Q :: bool at the beginning of a proof, then state fix Q :: bool in a sub-context, the Q in the sub-context refers to a different variable than the parent-context Q.
Having properly credited Chris, I insert his outline here, so it can easily be compared to the Isar source:
1. ~(P & Q) premise
2. { Q assumption
3. { P assumption
4. P & Q and-introduction 3, 2
5. _|_ negation-elimination 1, 4 }
6. ~P negation-introduction 3-5 }
7. Q -> ~P implication-introduction 2-6
The source:
lemma "~(P & Q) ==> Q --> ~P"
proof-
fix P Q :: bool
assume a1: "~(P & Q)"
{
assume a2: "Q"
{
assume a3: "P"
have a4: "P & Q"
apply(rule conjI) apply(rule a3) by(rule a2)
(* NOTE: have to set 'notE' up right. Next 'hence False' doesn't do it. *)
(* hence False apply(rule) by(metis a1) *)
(* 'rule' applies the default of 'conjI', because there is the fact
'this: P & Q', which comes from 'hence'; 'rule notE' gives an error.*)
from a1 a4
have False (* From 'this' and 'goal': ~(P & Q) ⟹ P & Q ==> False *)
by(rule notE) (* notE: ~P ==> P ==> R *)
}
hence "~P"
apply(rule notI) by(assumption)
}
thus "Q --> ~P"
apply(rule impI) by(assumption)
qed
Understanding scope better
Thinking was being required at my statement have False. I wasn't setting things up right for notE. Just to see if I was on the right track, I would execute sledgehammer, but it wasn't able to prove False within that context.
It was because I was on auto-pilot, and was using fix Q :: bool and fix P :: bool in the two local contexts. I took them out and sledgehammer easily found proofs.
That's an example of a person knowing some logic, but not knowing how to implement the logic correctly in the languages Isabelle/HOL and Isabelle/Isar.
Next, I had to learn how to set up things correctly for apply(rule notE).
Belaboring a point
Part of my understanding about the above source comes from seeing the phrase chained facts in isar-ref.pdf. Minor exposure to the natural deduction rules, along with M.Eberl's explanation about unification, instantiation, and resolution finally helped make sense of what happens in the output panel.
Above, I have hence False commented out, and then use have False. Fortunately, in Isabelle, there are multiple ways to do things, but the goal was to apply notE. Even with that, there are different Isar keywords that can be used to set things up.
Anyway, seeing how chained facts are used with rule was a light-bulb moment. I guess here's effectively what's involved at the statement have False, as it relates to notE:
term "~P ==> P ==> R" (* notE: line 376 of HOL.thy *)
lemma "~(P & Q) ⟹ P & Q ==> False"
by(rule notE)
If I had an account, I would upvote the question to get rid of that -1.
Thanks to Chris for giving the precise outline.
Since you explicitly mentioned natural deduction. In a specific flavour of natural deduction -- where lines are numbered and the scope of assumptions is explicitly marked by boxes (denoted by curly braces below) -- one way of proving your statement is the following:
1. ~(P & Q) premise
2. { Q assumption
3. { P assumption
4. P & Q and-introduction 3, 2
5. _|_ negation-elimination 1, 4 }
6. ~P negation-introduction 3-5 }
7. Q -> ~P implication-introduction 2-6
Actually, since your goal is to prove an implication, you only have one choice at the start, namely implication introduction.
It would be a good exercise to translate the above proof as faithfully as possible into a structured Isar proof (e.g., using what is called "raw proof blocks" and incidentally also denoted by curly braces in Isabelle).

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.

How to do cases with an inductive type in Coq

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.

Resources