Understanding Coq through a simple theorem proof - coq

I'm very new to Coq, and now I'm stuck trying to understand how Coq "reasons" with a simple theorem:
Theorem andb_true_elim2 : forall b c : bool,
andb b c = true -> c = true.
I supposed that the proof would be just:
Proof.
intros b c.
destruct c.
- destruct b.
+ reflexivity.
+ reflexivity.
- destruct b.
+ reflexivity.
+ reflexivity.
Qed.
But it fails with:
In environtment
H: true && false = true
Unable to unify "true" with "false"
The subgoal failing is the third reflexivity, where c is false and b is true:
1 subgoal
______________________________________(1/1)
true && false = true -> false = true
Why is that? Wasn't it equivalent to an implication?
true && (false = true) -> (false = true)
true && false -> false
false -> false
true

There are a few issues with this proof. First, you misunderstood what Coq wanted; the actual goal was the following:
((true && false) = true) -> (false = true)
This does not follow by reflexivity, as the conclusion of this formula, false = true, is an equality between two syntactically different expressions.
Second, Coq does not simplify the operators -> and = in the manner you described. Coq's theory allows automatic simplification in a few select expressions, such as those defined by case analysis. For instance, && is syntactic sugar for the andb function, which is defined in the standard library as follows:
Definition andb b c :=
if b then c else false.
When Coq sees an expression such as false && true, it expands it to the equivalent if false then true else false, which in turn simplifies to the else branch true. You can test this by calling the simpl tactic on the problematic branch.
The -> and = operators, on the other hand, are defined differently: the first one is a primitive in the logic, whereas the other one is a so-called inductive proposition. Neither of those can be automatically simplified in Coq, because they express concepts that are in general not computable: for instance, we can use = to express the equality of two functions f and g that take infinitely many natural numbers as inputs. This question discusses this difference in more detail.
If you want, you can state your theorem in a purely computable way with alternate definitions of implication and equality:
Definition negb b := if b then false else true.
Definition eqb b c := if b then c else negb c.
Definition implb b c := if b then c else true.
Lemma test : forall b c, (implb (eqb (andb b c) true) (eqb c true))
= true.
Proof. intros [] []; reflexivity. Qed.
However, a statement like this is generally harder to use in Coq.

Related

Are all proofs of (true=true) the same?

Can I prove the following in Coq?
Lemma bool_uip (H1 : true = true): H1 = eq_refl true.
i.e. that all proofs of true = true are the same?
From it follows for example forall c (H1 H2: c = true), H1 = H2.
It would be nice to not have to add any axiom (like UIP). I found the following thread that suggests that it might be the case:
Proof in COQ that equality is reflexivity
Here's a proof written as an explicit term.
Definition bool_uip (H1 : true = true): H1 = eq_refl true :=
match H1 as H in _ = b
return match b return (_ = b) -> Prop with
| true => fun H => H = eq_refl true
| false => fun _ => False
end H with
| eq_refl => eq_refl
end.
The type of H1 : true = _ is inductive with one index (_). Pattern-matching proceeds by first generalizing that type to true = b (in clause), and instantiating the index b in every branch.
The main obstacle to overcome is that this generalization H1 : true = b makes the result type H1 = eq_refl true no longer well-typed (the two sides have different types). The solution is to pattern-match on b to realign the types (in one branch; the other branch is unused and we can in fact put anything instead of False).
We can use the same technique to prove uniqueness of identity proofs whenever the type of the "equalees" (here true of type bool) is decidable.

Coq how to target and transform hypotheses to show that they're false?

I'm trying to prove that if two lists of booleans are equal (using a definition of equality that walks the lists structurally in the obvious way), then they have the same length.
In the course of doing so, however, I end up in a situation with a hypothesis that is false/uninhabited, but not literally False (and thus can't be targeted by the contradiction tactic).
Here's what I have so far.
Require Import Coq.Lists.List.
Require Export Coq.Bool.Bool.
Require Import Lists.List.
Import ListNotations.
Open Scope list_scope.
Open Scope nat_scope.
Fixpoint list_bool_eq (a : list bool) (b: list bool) : bool :=
match (a, b) with
| ([], []) => true
| ([], _) => false
| (_, []) => false
| (true::a', true::b') => list_bool_eq a' b'
| (false::a', false::b') => list_bool_eq a' b'
| _ => false
end.
Fixpoint length (a : list bool) : nat :=
match a with
| [] => O
| _::a' => S (length a')
end.
Theorem equal_implies_same_length : forall (a b : list bool) , (list_bool_eq a b) = true -> (length a) = (length b).
intros.
induction a.
induction b.
simpl. reflexivity.
After this, the "goal state" (what's the right word?) of coq as shown by coqide looks like this.
2 subgoals
a : bool
b : list bool
H : list_bool_eq [] (a :: b) = true
IHb : list_bool_eq [] b = true -> length [] = length b
______________________________________(1/2)
length [] = length (a :: b)
______________________________________(2/2)
length (a :: a0) = length b
Clearing away some of the extraneous detail...
Focus 1.
clear IHb.
We get
1 subgoal
a : bool
b : list bool
H : list_bool_eq [] (a :: b) = true
______________________________________(1/1)
length [] = length (a :: b)
To us, as humans, length [] = length (a :: b) is clearly false/uninhabited, but that's okay because H : list_bool_eq [] (a :: b) = true is false too.
However, the hypothesis H is not literally False, so we can't just use contradiction.
How do I target/"focus my attention from the perspective of Coq" on the hypothesis H so I can show that it's uninhabited. Is there something roughly analogous to a proof bullet -, +, *, { ... } that creates a new context inside my proof specifically for showing that a given hypothesis is false?
If you simplify your hypothesis (simpl in H), you will see that it is equivalent to false = true. At that point, you can conclude the goal with the easy tactic, which is capable of discharging such "obvious" contradictions even when they are syntactically equal to False. As a matter of fact, you should not even need to perform the simplification beforehand; easy should be powerful enough to figure out what is contradictory by itself.
(It would have been better to prove the following stronger result: forall l1 l2, list_bool_eq l1 l2 = true <-> l1 = l2.)

Proof on booleans, false = true

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.

Function of comparison coq

I want to make a function of natural numbers comparison in coq
I declare a Set of invariant contain sup, inf, egal
Inductive invr:Type:=inf | sup | egal.
And I define a function comparaison
Definition comparaison (inv:invr)(a b:nat):bool:=
match invr with
|inf => if (a < b) then true else false
|sup => if (a > b) then true else false
|egal=> if (a = b) then true else false
end.
But it does not work! Thanks for your response.
You are trying to match type (set) invr with its constructors values instead of variable inv, so you get an error
The term "invr" has type "Set" while it is expected to have type
"invr".
You need to do the matching for inv, not invr
Definition comparaison (inv:invr)(a b:nat):bool:=
match inv with
|inf => if (a < b) then true else false
|sup => if (a > b) then true else false
|egal=> if (a = b) then true else false
end.
Also make sure that you have <, >, = notations are defined to return bool, because by default they return Prop, which can't be used in if/else. So you need to use beq_nat, and leb from Arith.
Simplified final version (removed redundant if/else branches).
Require Import Coq.Arith.Arith.
Inductive invr : Type:= inf | sup | egal.
Definition comparaison (inv:invr)(a b:nat):bool:=
match inv with
|inf => leb a b
|sup => leb b a
|egal=> beq_nat a b
end.
This is a typical beginner mistake.
< stands for lt, which has type:
lt : nat -> nat -> Prop
That is, a < b is just a proposition, not a procedure that computes whether a is less than b!
The same goes for equality.
What you want to use is a function that computes the truth of these propositions, either as a boolean or as a richer type:
In the library Arith:
beq_nat: nat -> nat -> bool
leb: nat -> nat -> bool
(* or the more informative versions which return proofs of what they decide *)
eq_nat_dec: forall n m : nat, {n = m} + {n <> m}
lt_dec: forall n m : nat, {n < m} + {~ n < m}
So the following is a valid expression:
if beq_nat a b then true else false
Also note that the following is a valid expression equivalent to the precedent one (since beq_nat returns a bool):
beq_nat a b

coq change premise 'negation of not equal' to 'equal'

Suppose I have a premise like this:
H2: ~ a b c <> a b c
And I wish to change it to:
a b c = a b c
Where
a is Term -> Term -> Term
b and c are both Term
How can I do it? Thanks!
If you unfold the definitions of ~ and <>, you hypothesis has the following type:
H2: (a b c = a b c -> False) -> False
Therefore, what you wish to achieve is what logicians usually call "double negation elimination". It is not an intuitionistically-provable theorem, and is therefore defined in the Classical module of Coq (see http://coq.inria.fr/distrib/V8.4/stdlib/Coq.Logic.Classical_Prop.html for details):
Classical.NNPP : forall (p : Prop), ~ ~ p -> p
I assume your actual problem is more involved than a b c = a b c, but for the sake of mentioning it, if you really care about obtaining that particular hypothesis, you can safely prove it without even looking at H2:
assert (abc_refl : a b c = a b c) by reflexivity.
If your actual example is not immediately reflexive and the equality is actually false, maybe you want to turn your goal into showing that H2 is absurd. You can do so by eliminating H2 (elim H2., which is basically doing a cut on the False type), and you will end up in the context:
H2 : ~ a b c <> a b c
EQ : a b c = a b c
=====================
False
I'm not sure whether all of this helps, but you might have oversimplified your problem so that I cannot provide more insight on what your real problem is.
Just a little thought to add to Ptival's answer - if your desired goal was not trivially solved by reflexivity, you could still make progress provided you had decidable equality on your Term, for example by applying this little lemma:
Section S.
Parameter T : Type.
Parameter T_eq_dec : forall (x y : T), {x = y} + {x <> y}.
Lemma not_ne : forall (x y : T), ~ (x <> y) -> x = y.
Proof.
intros.
destruct (T_eq_dec x y); auto.
unfold not in *.
assert False.
apply (H n).
contradiction.
Qed.
End S.