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.
Related
Well, the code
From mathcomp Require Import ssreflect ssrnat ssrbool eqtype.
Unset Strict Implicit.
Unset Printing Implicit Defensive.
Inductive nat_rels m n : bool -> bool -> bool -> Set :=
| CompareNatLt of m < n : nat_rels m n true false false
| CompareNatGt of m > n : nat_rels m n false true false
| CompareNatEq of m == n : nat_rels m n false false true.
Lemma natrelP m n : nat_rels m n (m < n) (m > n) (m == n).
Proof.
case (leqP m n); case (leqP n m).
move => H1 H2; move: (conj H1 H2) => {H1} {H2} /andP.
rewrite -eqn_leq => /eqP /ssrfun.esym /eqP H.
by rewrite H; constructor.
move => H. rewrite leq_eqVlt => /orP.
case.
Error is Error: Case analysis on sort Set is not allowed for inductive definition or.
The last goal before the case is
m, n : nat
H : m < n
============================
m == n \/ m < n -> nat_rels m n true false (m == n)
I've already used this construction (rewrite leq_eqVlt => /orP; case) in very similar situation and it just worked:
Lemma succ_max_distr n m : (maxn n m).+1 = maxn (n.+1) (m.+1).
Proof.
wlog : m n / m < n => H; last first.
rewrite max_l /maxn; last by exact: ltnW.
rewrite leqNgt.
have: m.+1 < n.+2 by apply: ltnW.
by move => ->.
case: (leqP n m); last by apply: H.
rewrite leq_eqVlt => /orP. case.
What is the difference between two cases?
and Why "Case analysis on sort Set is not allowed for inductive definition or"?
The difference between the two cases is the sort of the goal (Set vs Prop) when you execute the case command. In the first situation your goal is nat_rels ... and you declared that inductive in Set; in the second situation your goal is an equality that lands in Prop.
The reason why you can't do a case analysis on \/ when the goal is in Set (the first situation) is because \/ has been declared as Prop-valued. The main restriction associated to such a declaration is that you cannot use informative content from a Prop to build something in Set (or more generally Type), so that Prop is compatible with an erasure-semantic at extraction time.
In particular, doing a case analysis on \/ gives away the side of the \/ that is valid, and you can't be allowed to use that information for building some data in Set.
You have at least two solutions at your disposal:
You could move your family nat_rels from Set to Prop if that's compatible with what you want to do later on.
Or you could use the fact that the hypothesis that you want to branch on is decidable and find a way to produce some {m == n} + { m <n } out of m <= n; here the notation { _ } + { _ } is the Set-valued disjunction of proposition.
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.
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.)
I was curious about how the discriminate tactic works behind the curtain. Therefore I did some experiments.
First a simple Inductive definition:
Inductive AB:=A|B.
Then a simple lemma which can be proved by the discriminate tactic:
Lemma l1: A=B -> False.
intro.
discriminate.
Defined.
Let's see what the proof looks like:
Print l1.
l1 =
fun H : A = B =>
(fun H0 : False => False_ind False H0)
(eq_ind A
(fun e : AB => match e with
| A => True
| B => False
end) I B H)
: A = B -> False
This looks rather complicated and I do not understand what is happening here. Therefore I tried to prove the same lemma more explicitly:
Lemma l2: A=B -> False.
apply (fun e:(A=B) => match e with end).
Defined.
Let's again see what Coq has made with this:
Print l2.
l2 =
fun e : A = B =>
match
e as e0 in (_ = a)
return
(match a as x return (A = x -> Type) with
| A => fun _ : A = A => IDProp
| B => fun _ : A = B => False
end e0)
with
| eq_refl => idProp
end
: A = B -> False
Now I am totally confused. This is still more complicated.
Can anyone explain what is going on here?
Let's go over this l1 term and describe every part of it.
l1 : A = B -> False
l1 is an implication, hence by Curry-Howard correspondence it's an abstraction (function):
fun H : A = B =>
Now we need to construct the body of our abstraction, which must have type False. The discriminate tactic chooses to implement the body as an application f x, where f = fun H0 : False => False_ind False H0 and it's just a wrapper around the induction principle for False, which says that if you have a proof of False, you can get a proof of any proposition you want (False_ind : forall P : Prop, False -> P):
(fun H0 : False => False_ind False H0)
(eq_ind A
(fun e : AB => match e with
| A => True
| B => False
end) I B H)
If we perform one step of beta-reduction, we'll simplify the above into
False_ind False
(eq_ind A
(fun e : AB => match e with
| A => True
| B => False
end) I B H)
The first argument to False_ind is the type of the term we are building. If you were to prove A = B -> True, it would have been False_ind True (eq_ind A ...).
By the way, it's easy to see that we can simplify our body further - for False_ind to work it needs to be provided with a proof of False, but that's exactly what we are trying to construct here! Thus, we can get rid of False_ind completely, getting the following:
eq_ind A
(fun e : AB => match e with
| A => True
| B => False
end) I B H
eq_ind is the induction principle for equality, saying that equals can be substituted for equals:
eq_ind : forall (A : Type) (x : A) (P : A -> Prop),
P x -> forall y : A, x = y -> P y
In other words, if one has a proof of P x, then for all y equal to x, P y holds.
Now, let's create step-by-step a proof of False using eq_ind (in the end we should obtain the eq_ind A (fun e : AB ...) term).
We start, of course, with eq_ind, then we apply it to some x - let's use A for that purpose. Next, we need the predicate P. One important thing to keep in mind while writing P down is that we must be able to prove P x. This goal is easy to achieve - we are going to use the True proposition, which has a trivial proof. Another thing to remember is the proposition we are trying to prove (False) - we should be returning it if the input parameter is not A.
With all the above the predicate almost writes itself:
fun x : AB => match x with
| A => True
| B => False
end
We have the first two arguments for eq_ind and we need three more: the proof for the branch where x is A, which is the proof of True, i.e. I. Some y, which will lead us to the proposition we want to get proof of, i.e. B, and a proof that A = B, which is called H at the very beginning of this answer. Stacking these upon each other we get
eq_ind A
(fun x : AB => match x with
| A => True
| B => False
end)
I
B
H
And this is exactly what discriminate gave us (modulo some wrapping).
Another answer focuses on the discriminate part, I will focus on the manual proof. You tried:
Lemma l2: A=B -> False.
apply (fun e:(A=B) => match e with end).
Defined.
What should be noted and makes me often uncomfortable using Coq is that Coq accepts ill-defined definitions that it internally rewrites into well-typed terms. This allows to be less verbose, since Coq adds itself some parts. But on the other hand, Coq manipulates a different term than the one we entered.
This is the case for your proof. Naturally, the pattern-matching on e should involve the constructor eq_refl which is the single constructor of the eq type. Here, Coq detects that the equality is not inhabited and thus understands how to modify your code, but what you entered is not a proper pattern-matching.
Two ingredients can help understand what is going on here:
the definition of eq
the full pattern-matching syntax, with as, in and return terms
First, we can look at the definition of eq.
Inductive eq {A : Type} (x : A) : A -> Prop := eq_refl : x = x.
Note that this definition is different from the one that seems more natural (in any case, more symmetric).
Inductive eq {A : Type} : A -> A -> Prop := eq_refl : forall (x:A), x = x.
This is really important that eq is defined with the first definition and not the second. In particular, for our problem, what is important is that, in x = y, x is a parameter while y is an index. That is to say, x is constant across all the constructors while y can be different in each constructor. You have the same difference with the type Vector.t. The type of the elements of a vector will not change if you add an element, that's why it is implemented as a parameter. Its size, however, can change, that's why it is implemented as an index.
Now, let us look at the extended pattern-matching syntax. I give here a very brief explanation of what I have understood. Do not hesitate to look at the reference manual for safer information. The return clause can help specify a return type that will be different for each branch. That clause can use the variables defined in the as and in clauses of the pattern-matching, which binds respectively the matched term and the type indices. The return clause will both be interpreted in the context of each branch, substituting the variables of as and in using this context, to type-check the branches one by one, and be used to type the match from an external point of view.
Here is a contrived example with an as clause:
Definition test n :=
match n as n0 return (match n0 with | 0 => nat | S _ => bool end) with
| 0 => 17
| _ => true
end.
Depending on the value of n, we are not returning the same type. The type of test is forall n : nat, match n with | 0 => nat | S _ => bool end. But when Coq can decide in which case of the match we are, it can simplify the type. For example:
Definition test2 n : bool := test (S n).
Here, Coq knows that, whatever is n, S n given to test will result as something of type bool.
For equality, we can do something similar, this time using the in clause.
Definition test3 (e:A=B) : False :=
match e in (_ = c) return (match c with | B => False | _ => True end) with
| eq_refl => I
end.
What's going on here ? Essentially, Coq type-checks separately the branches of the match and the match itself. In the only branch eq_refl, c is equal to A (because of the definition of eq_refl which instantiates the index with the same value as the parameter), therefore we claimed we returned some value of type True, here I. But when seen from an external point of view, c is equal to B (because e is of type A=B), and this time the return clause claims that the match returns some value of type False. We use here the capability of Coq to simplify pattern-matching in types that we have just seen with test2. Note that we used True in the other cases than B, but we don't need True in particular. We only need some inhabited type, such that we can return something in the eq_refl branch.
Going back to the strange term produced by Coq, the method used by Coq does something similar, but on this example, certainly more complicated. In particular, Coq often uses types IDProp inhabited by idProp when it needs useless types and terms. They correspond to True and I used just above.
Finally, I give the link of a discussion on coq-club that really helped me understand how extended pattern-matching is typed in 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