Proof irrelevance (2) - coq

Let's assume we have two proofs for a simple lemma.
Lemma l1: exists x:nat, x <> 0.
exists 1.
intro.
discriminate.
Defined.
Lemma l2: exists x:nat, x <> 0.
exists 2.
discriminate.
Defined.
Intuitively, I would say that those are two different proofs.
So, can I prove the following lemma?
Lemma l3: l1 <> l2
I suppose this is undecidable.
What happens if we introduce the Univalence Axiom ?

First, a small note on terminology. There is another sense of "undecidable" often used in theoretical computer science to refer to problems of deciding, given an arbitrary element of some set, whether a fixed property holds or not of that element. If there is an algorithm computable by, say, a Turing machine, that correctly answers the question for any possible input, we say the problem is decidable; otherwise, it is undecidable. Your notion of "undecidable" is often referred to as "independence" (The two issues are of course, related. The problem of whether an arbitrary Coq proposition is provable or not is undecidable.)
Now, back to your question. I believe (although I am not entirely sure) that your lemma l3 cannot be proved or refuted in Coq even if you incorporate the univalence axiom. The reason is that the univalence axiom only violates proof irrelevance for a particular kind of proposition: equality assertions. And there is nothing about it that has any obvious consequences for existential quantification. Perhaps some intuition here can help. There is a computationally relevant analog of existential quantification (that is, something that lives in Type) that allows you to prove your principle, independently of assuming univalence:
Lemma l1: { x:nat | x <> 0 }.
exists 1.
intro.
discriminate.
Defined.
Lemma l2: { x:nat | x <> 0 }.
exists 2.
discriminate.
Defined.
Lemma l3: l1 <> l2.
Proof.
intros H. inversion H.
Qed.
However, even if this is possible for this type, it is still safe to assume irrelevance for existential quantification, because Coq's logic prevents us from manipulating its proofs in a way that allow us to extract which witnesses were used.

Related

Proof by contradiction in Coq

I am trying to understand the apparent paradox of the logical framework of theorem provers like Coq not including LEM yet also being able to construct proofs by contradiction. Specifically the intuitionistic type theory that these theorem provers are based on does not allow for any logical construction of the form ¬(¬P)⇒P, and so what is required in order to artificially construct this in a language like Coq? And how is the constructive character of the system preserved if this is allowed?
I think you are mixing up two related uses of contradiction in logic. One is the technique of proof by contradiction, which says that you can prove P by proving ~ (~ P) -- that is, by showing that ~ P entails a contradiction. This technique is actually not available in general in constructive logics like Coq, unless one of the following applies.
You add the excluded middle forall P, P \/ ~ P as an axiom. Coq supports this, but this addition means that you are not working in a constructive logic anymore.
The proposition P is known to be decidable (i.e., P \/ ~ P holds). This is the case, for example, for the equality of two natural numbers n and m, which we can prove by induction.
The proposition P is of the form ~ Q. Since Q -> ~ (~ Q) holds constructively, by the law of contrapositives (which is also valid constructively), we obtain ~ (~ (~ Q)) -> (~ Q).
The other use of contradiction is the principle of explosion, which says that anything follows once you assume a contradiction (i.e., False in Coq). Unlike proof by contradiction, the principle of explosion is always valid in constructive logic, so there is no paradox here.
In constructive logic, by definition, a contradiction is an inhabitant of the empty type 0, and, also by definition, the negation ¬P of a proposition P is a function of type: P -> 0 that gives an inhabitant of the empty type 0 from an inhabitant (a proof) of P.
If you assume an inhabitant (proof) of P, and derive constructively an inhabitant of 0, you have defined a function inhabiting the type P -> 0, i.e. a proof of ¬P. This is a constructive sort of proof by contradiction: assume P, derive a contradiction, conclude ¬P.
Now if you assume ¬P and derive a contradiction, you have a constructive proof of ¬¬P, but cannot conclude constructively that you have a proof of P: for this you need the LEM axiom.

How to leave a goal unfinished in Coq

In Isabelle, you can leave a goal unfinished in two ways:
sorry: will leave your proof and the fact can be used in later proofs.
oops: will leave the proof but the fact cannot be used in later proofs.
Is there similar functionality in Coq that would allow me to leave a goal unfinished to come back later to it? This is useful to sketch the structure of the proof while not filling in all the details. Note that the approach in How to switch the current goal in Coq? modifies the proof structure. That's not what I'm looking for.
You have several ways to terminate a proof in Coq. You probably know Qed which asserts the proof is completed. There is also Defined for when you want the proof to have computational content.
The things you are looking for are:
Admitted which admits the proof, so it can be used later;
Abort which gives up on proving the lemma.
They can be used that way:
Lemma foo : forall n, n = 0.
Proof.
intro n. destruct n.
- reflexivity.
-
Abort.
Lemma bar : forall n, n = n.
Admitted.
In both cases you can have a partial proof script before the Admitted/Abort or none at all.
As #HTNW points out, you can also use the equivalent tactics admit and give_up inside subgoals of the proof. Using those, the proof however has to be concluded using either Admitted or Abort.
Lemma lem : forall A, A + A -> A.
Proof.
intros A h.
destruct h.
- admit.
- give_up.
Admitted.
The partial proof is in any case thrown away with this solution.
If for some reason you want to keep using a partial proof (for instance if you want to compute with it), a common trick is to use an axiom to close the goals that you want to leave for later.
Axiom cheating : forall A, A.
Tactic Notation "cheat" := apply cheating.
Lemma lem : forall A, A + A -> A.
Proof.
intros A h.
destruct h.
- cheat.
- cheat.
Defined. (* This is now ok *)
You have to be careful using that trick though. You can check that a lemma has been proven without axioms using Print Assumptions lem. If it says "closed under context" you're good, otherwise it will lists the axioms it depends on and if cheating appears you know it's not entirely proven.

Decide disjunctions in sort Prop

I am interested in the probably false lemma :
Lemma decideOr : forall (P Q : Prop),
(P \/ Q) -> {P} + {Q}.
that asserts we can algorithmically decide any proof of an or in sort Prop. Of course, Coq does not let us destruct the input to extract it in sort Set. However, a proof of P \/ Q is a lambda-term that Coq accepts to print, so external tools can process it.
First question : can this lambda-term be decided outside of Coq (assuming the term uses no axioms, only plain Coq) ? It might be, because the rules of constructive logic demand that all disjunctions be explicitely chosen, without cheating by a proof by contradiction. So can we code a parser of Coq proof terms, and try to decide whether the first or the second operand of the or was proved ? If the term starts with or_introl or or_intror we are done. So I guess the problems are when the term is a lambda-application. But then Coq terms are strongly normalizing, so we reduce it to a normal form and it seems it will start with either or_introl or or_intror.
Second question : if this problem can be decided outside of Coq, what prevents us from internalizing it within Coq, ie proving lemma decideOr above ?
First question
Yes, you can write a program that takes as input a Coq proof of A \/ B and outputs true or false depending on which side was used to prove the disjunction. Indeed, if you write
Compute P.
in Coq, where P : A \/ B, Coq will normalize the proof P and print which constructor was used. This will not work if P uses proofs that end in Qed (because those are not unfolded by the evaluator), but in principle it is possible to replace Qed by Defined everywhere and make it work.
Second question
What prevents us from proving decideOr is that the designers of Coq wanted to have a type of propositions that supports the excluded middle (using an axiom) while allowing programs to execute. If decideOr were a theorem and we wanted to use the excluded middle (classical : forall A : Prop, A \/ ~ A), it would not be possible to execute programs that branch on the result of decideOr (classical A). This does not mean that decideOr is false: it is perfectly possible to admit it as an axiom. There is a difference between not being provable ("there does not exist a proof of A") and being refutable ("there exists a proof of ~ A").

Proof by counterexample in Coq

After proving tens of lemmas in propositional and predicate calculus (some more challenging than others but generally still provable on an intro-apply-destruct autopilot) I hit one starting w/ ~forall and was immediately snagged. Clearly, my understanding and knowledge of Coq was lacking. So, I'm asking for a low-level Coq technique for proving statements of the general form
~forall A [B].., C -> D.
exists A [B].., ~(C -> D).
In words, I'm hoping for a general Coq recipy for setting up and firing counterexamples. (The main reason for quantifying over functions above is that it's a (or the) primitive connective in Coq.) If you want examples, I suggest e.g.
~forall P Q: Prop, P -> Q.
~forall P: Prop, P -> ~P.
There is a related question which neither posed nor answered mine, so I suppose it's not a duplicate.
Recall that ~ P is defined as P -> False. In other words, to show such a statement, it suffices to assume P and derive a contradiction. The crucial point is that you are allowed to use P as a hypothesis in any way you like. In the particular case of universally quantified statements, the specialize tactic might come in handy. This tactic allows us to instantiate a universally quantified variable with a particular value. For instance,
Goal ~ forall P Q, P -> Q.
Proof.
intros contra.
specialize (contra True False). (* replace the hypothesis
by [True -> False] *)
apply contra. (* At this point the goal becomes [True] *)
trivial.
Qed.

Why Coq doesn't allow inversion, destruct, etc. when the goal is a Type?

When refineing a program, I tried to end proof by inversion on a False hypothesis when the goal was a Type. Here is a reduced version of the proof I tried to do.
Lemma strange1: forall T:Type, 0>0 -> T.
intros T H.
inversion H. (* Coq refuses inversion on 'H : 0 > 0' *)
Coq complained
Error: Inversion would require case analysis on sort
Type which is not allowed for inductive definition le
However, since I do nothing with T, it shouldn't matter, ... or ?
I got rid of the T like this, and the proof went through:
Lemma ex_falso: forall T:Type, False -> T.
inversion 1.
Qed.
Lemma strange2: forall T:Type, 0>0 -> T.
intros T H.
apply ex_falso. (* this changes the goal to 'False' *)
inversion H.
Qed.
What is the reason Coq complained? Is it just a deficiency in inversion, destruct, etc. ?
I had never seen this issue before, but it makes sense, although one could probably argue that it is a bug in inversion.
This problem is due to the fact that inversion is implemented by case analysis. In Coq's logic, one cannot in general perform case analysis on a logical hypothesis (i.e., something whose type is a Prop) if the result is something of computational nature (i.e., if the sort of the type of the thing being returned is a Type). One reason for this is that the designers of Coq wanted to make it possible to erase proof arguments from programs when extracting them into code in a sound way: thus, one is only allowed to do case analysis on a hypothesis to produce something computational if the thing being destructed cannot alter the result. This includes:
Propositions with no constructors, such as False.
Propositions with only one constructor, as long as that constructor takes no arguments of computational nature. This includes True, Acc (the accessibility predicated used for doing well-founded recursion), but excludes the existential quantifier ex.
As you noticed, however, it is possible to circumvent that rule by converting some proposition you want to use for producing your result to another one you can do case analysis on directly. Thus, if you have a contradictory assumption, like in your case, you can first use it to prove False (which is allowed, since False is a Prop), and then eliminating False to produce your result (which is allowed by the above rules).
In your example, inversion is being too conservative by giving up just because it cannot do case analysis on something of type 0 < 0 in that context. It is true that it can't do case analysis on it directly by the rules of the logic, as explained above; however, one could think of making a slightly smarter implementation of inversion that recognizes that we are eliminating a contradictory hypothesis and adds False as an intermediate step, just like you did. Unfortunately, it seems that we need to do this trick by hand to make it work.
In addition to Arthur's answer, there is a workaround using constructive_definite_description axiom. Using this axiom in a function would not allow to perform calculations and extract code from it, but it still could be used in other proofs:
From Coq Require Import Description.
Definition strange1: forall T:Type, 0>0 -> T.
intros T H.
assert (exists! t:T, True) as H0 by inversion H.
apply constructive_definite_description in H0.
destruct H0 as [x ?].
exact x.
Defined.
Or same function without proof editing mode:
Definition strange2 (T: Type) (H: 0 > 0): T :=
proj1_sig (constructive_definite_description (fun _ => True) ltac: (inversion H)).
Also there's a stronger axiom constructive_indefinite_description that converts a proposition exists x:T, P x (without uniqueness) into a corresponding sigma-type {x:T | P x}.