Exists
Existential Quantification
- Given any possible value v of type T,
- the proposition P holds when we replace x with v.
- There is at least one value v of type T, such that
- the proposition P holds when we replace x with v.
Lemma four_is_even : ∃ n : nat, 4 = n + n.
Proof.
(* We want to show 4 is even, so we need to find a number n such
that n + n = 4. If we try 2 we have 2 + 2 = 4, which seems
to work. *)
∃ 2. reflexivity.
Qed.
Proof.
(* We want to show 4 is even, so we need to find a number n such
that n + n = 4. If we try 2 we have 2 + 2 = 4, which seems
to work. *)
∃ 2. reflexivity.
Qed.
Conversely, if we have an existential hypothesis ∃ x, P in
the context, we can destruct it to obtain a witness x and a
hypothesis stating that P holds of x.
Theorem exists_example_2 : ∀ n,
(∃ m, n = 4 + m) →
(∃ o, n = 2 + o).
Proof.
(* WORKED IN CLASS *)
intros n [m Hm]. (* note implicit destruct here *)
∃ (2 + m).
apply Hm. Qed.
(∃ m, n = 4 + m) →
(∃ o, n = 2 + o).
Proof.
(* WORKED IN CLASS *)
intros n [m Hm]. (* note implicit destruct here *)
∃ (2 + m).
apply Hm. Qed.
Exercise: 1 star, standard, especially useful (dist_not_exists)
Prove that "P holds for all x" implies "there is no x for which P does not hold." (Hint: destruct H as [x E] works on existential assumptions!)
Theorem dist_not_exists : ∀ (X:Type) (P : X → Prop),
(∀ x, P x) → ¬ (∃ x, ¬ P x).
Proof.
(* FILL IN HERE *) Admitted.
☐
(∀ x, P x) → ¬ (∃ x, ¬ P x).
Proof.
(* FILL IN HERE *) Admitted.
☐
Exercise: 1 star, standard, especially useful (dist_not_forall)
Prove that "there exists an x for which P holds" implies "it is not the case that for all x P does not hold." (Hint: destruct H as [x E] works on existential assumptions!)
Theorem dist_not_forall : ∀ (X:Type) (P : X → Prop),
(∃ x, P x) → ¬ (∀ x, ¬ P x).
Proof.
(* FILL IN HERE *) Admitted.
☐
(∃ x, P x) → ¬ (∀ x, ¬ P x).
Proof.
(* FILL IN HERE *) Admitted.
☐
Exercise: 2 stars, standard, optional (dist_exists_or)
Prove that existential quantification distributes over disjunction.
Theorem dist_exists_or : ∀ (X:Type) (P Q : X → Prop),
(∃ x, P x ∨ Q x) ↔ (∃ x, P x) ∨ (∃ x, Q x).
Proof.
(* FILL IN HERE *) Admitted.
☐
(∃ x, P x ∨ Q x) ↔ (∃ x, P x) ∨ (∃ x, Q x).
Proof.
(* FILL IN HERE *) Admitted.
☐
Propositions and Booleans
- (1) that evenb n returns true, or
- (2) that there exists some k such that n = double k.
Exercise: 2 stars, standard, optional (evenb_S)
One inconvenient aspect of our definition of evenb n is the recursive call on n - 2. This makes proofs about evenb n harder when done by induction on n, since we may need an induction hypothesis about n - 2. The following lemma gives an alternative characterization of evenb (S n) that works better with induction:
Theorem evenb_double : ∀ k, evenb (double k) = true.
Proof.
intros k. induction k as [|k' IHk'].
- reflexivity.
- simpl double. simpl evenb. apply IHk'.
Qed.
Proof.
intros k. induction k as [|k' IHk'].
- reflexivity.
- simpl double. simpl evenb. apply IHk'.
Qed.
Theorem evenb_double_conv : ∀ n,
∃ k, n = if evenb n then double k
else S (double k).
Proof.
(* FILL IN HERE *) Admitted.
☐
∃ k, n = if evenb n then double k
else S (double k).
Proof.
(* FILL IN HERE *) Admitted.
☐
Theorem even_bool_prop : ∀ n,
evenb n = true ↔ ∃ k, n = double k.
evenb n = true ↔ ∃ k, n = double k.
Proof.
intros n. split.
- intros H. destruct (evenb_double_conv n) as [k Hk].
rewrite Hk. rewrite H. ∃ k. reflexivity.
- intros [k Hk]. rewrite Hk. apply evenb_double.
Qed.
intros n. split.
- intros H. destruct (evenb_double_conv n) as [k Hk].
rewrite Hk. rewrite H. ∃ k. reflexivity.
- intros [k Hk]. rewrite Hk. apply evenb_double.
Qed.
In view of this theorem, we say that the boolean
computation evenb n reflects the logical proposition
∃ k, n = double k.
However, even when the boolean and propositional formulations of a
claim are equivalent from a purely logical perspective, they need
not be equivalent operationally.
Equality provides an extreme example: knowing that eqb n m =
true is generally of little direct help in the middle of a proof
involving n and m; however, if we convert the statement to the
equivalent form n = m, we can rewrite with it.
The case of even numbers is also interesting. Recall that,
when proving the backwards direction of even_bool_prop (i.e.,
evenb_double, going from the propositional to the boolean
claim), we used a simple induction on k. On the other hand, the
converse (the evenb_double_conv exercise) required a clever
generalization, since we can't directly prove (∃ k, n =
double k) → evenb n = true.
For these examples, the propositional claims are more useful than
their boolean counterparts, but this is not always the case. For
instance, we cannot test whether a general proposition is true or
not in a function definition; as a consequence, the following code
fragment is rejected:
Coq complains that n = 2 has type Prop, while it expects
an elements of bool (or some other inductive type with two
elements). The reason for this error message has to do with the
computational nature of Coq's core language, which is designed
so that every function that it can express is computable and
total. One reason for this is to allow the extraction of
executable programs from Coq developments. As a consequence,
Prop in Coq does not have a universal case analysis operation
telling whether any given proposition is true or false, since such
an operation would allow us to write non-computable functions.
Although general non-computable properties cannot be phrased as
boolean computations, it is worth noting that even many
computable properties are easier to express using Prop than
bool, since recursive function definitions are subject to
significant restrictions in Coq. For instance, later we'll shows
how to define the property that two lists are permutations of each
a given string using Prop. Doing the same with bool would
amount to the is_permutation_of function we wrote on day
6... which (as we'll see) is more complicated, harder to
understand, and harder to reason about than the Prop we'll
define.
Conversely, an important side benefit of stating facts using
booleans is enabling some proof automation through computation
with Coq terms, a technique known as proof by reflection.
Consider the following statement:
The most direct proof of this fact is to give the value of k
explicitly.
Proof. ∃ 500. reflexivity. Qed.
On the other hand, the proof of the corresponding boolean
statement is even simpler:
What is interesting is that, since the two notions are equivalent,
we can use the boolean formulation to prove the other one without
mentioning the value 500 explicitly:
Although we haven't gained much in terms of proof size in
this case, larger proofs can often be made considerably simpler by
the use of reflection. As an extreme example, the Coq proof of
the famous 4-color theorem uses reflection to reduce the
analysis of hundreds of different cases to a boolean computation.
We won't cover reflection in any real detail, but it serves as a
good example showing the complementary strengths of booleans and
general propositions.
As we go on to prove more interesting (and challenging!) things
about our programs, the various iff lemmas relating computation to
logic will surely come in handy.
We have seen that it is not possible to test whether or not a
proposition P holds while defining a Coq function. You may be
surprised to learn that a similar restriction applies to proofs!
In other words, the following intuitive reasoning principle is not
derivable in Coq:
Classical vs. Constructive Logic
To understand operationally why this is the case, recall
that, to prove a statement of the form P ∨ Q, we use the left
and right tactics, which effectively require knowing which side
of the disjunction holds. But the universally quantified P in
excluded_middle is an arbitrary proposition, which we know
nothing about. We don't have enough information to choose which
of left or right to apply, just as Coq doesn't have enough
information to mechanically decide whether P holds or not inside
a function.
However, if we happen to know that P is reflected in some
boolean term b, then knowing whether it holds or not is trivial:
we just have to check the value of b.
Theorem restricted_excluded_middle : ∀ P b,
(P ↔ b = true) → P ∨ ¬ P.
Proof.
(* Let a proposition P and boolean b be given.
Assume that P holds if and only if b = true.
We must show P ∨ ¬ P.
*)
intros P [] H.
(* We go by cases on b.
If b is true, by our assumption we know P holds, so we have P.
Otherwise, we likewise know by our assumption that P does not
hold, so we have ¬P. *)
- left. rewrite H. reflexivity.
- right. rewrite H. intros contra. discriminate contra.
Qed.
(P ↔ b = true) → P ∨ ¬ P.
Proof.
(* Let a proposition P and boolean b be given.
Assume that P holds if and only if b = true.
We must show P ∨ ¬ P.
*)
intros P [] H.
(* We go by cases on b.
If b is true, by our assumption we know P holds, so we have P.
Otherwise, we likewise know by our assumption that P does not
hold, so we have ¬P. *)
- left. rewrite H. reflexivity.
- right. rewrite H. intros contra. discriminate contra.
Qed.
In particular, the excluded middle is valid for equations n = m,
between natural numbers n and m.
Theorem restricted_excluded_middle_eq : ∀ (n m : nat),
(∀ n m, n = m ↔ eqb n m = true) → (* we'll prove this on day 15 *)
n = m ∨ n ≠ m.
Proof.
intros n m eqb_true_iff.
apply (restricted_excluded_middle (n = m) (eqb n m)).
apply eqb_true_iff.
Qed.
(∀ n m, n = m ↔ eqb n m = true) → (* we'll prove this on day 15 *)
n = m ∨ n ≠ m.
Proof.
intros n m eqb_true_iff.
apply (restricted_excluded_middle (n = m) (eqb n m)).
apply eqb_true_iff.
Qed.
It may seem strange that the general excluded middle is not
available by default in Coq; after all, any given claim must be
either true or false. Nonetheless, there is an advantage in not
assuming the excluded middle: statements in Coq can make stronger
claims than the analogous statements in standard mathematics.
Notably, if there is a Coq proof of ∃ x, P x, it is
possible to explicitly exhibit a value of x for which we can
prove P x -- in other words, every proof of existence is
necessarily constructive.
Logics like Coq's, which do not assume the excluded middle, are
referred to as constructive logics.
More conventional logical systems such as ZFC, in which the
excluded middle does hold for arbitrary propositions, are referred
to as classical.
The following example illustrates why assuming the excluded middle
may lead to non-constructive proofs:
Claim: There exist irrational numbers a and b such that a ^
b is rational.
Proof: It is not difficult to show that sqrt 2 is irrational.
If sqrt 2 ^ sqrt 2 is rational, it suffices to take a = b =
sqrt 2 and we are done. Otherwise, sqrt 2 ^ sqrt 2 is
irrational. In this case, we can take a = sqrt 2 ^ sqrt 2 and
b = sqrt 2, since a ^ b = sqrt 2 ^ (sqrt 2 × sqrt 2) = sqrt 2 ^
2 = 2. ☐
Do you see what happened here? We used the excluded middle to
consider separately the cases where sqrt 2 ^ sqrt 2 is rational
and where it is not, without knowing which one actually holds!
Because of that, we wind up knowing that such a and b exist but
we cannot determine what their actual values are (at least, using
this line of argument).
As useful as constructive logic is, it does have its limitations:
There are many statements that can easily be proven in classical
logic but that have much more complicated constructive proofs, and
there are some that are known to have no constructive proof at all!
Fortunately, the excluded middle is known to be compatible with
Coq's logic, allowing us to add it safely as an axiom. However, we
will not need to do so in this book: the results that we cover can
be developed entirely within constructive logic at negligible extra
cost.
It takes some practice to understand which proof techniques must be
avoided in constructive reasoning, but arguments by contradiction,
in particular, are infamous for leading to non-constructive proofs.
Here's a typical example: suppose that we want to show that there
exists x with some property P, i.e., such that P x. We start
by assuming that our conclusion is false; that is, ¬ ∃ x, P
x. From this premise, it is not hard to derive ∀ x, ¬ P x.
If we manage to show that this intermediate fact results in a
contradiction, we arrive at an existence proof without ever
exhibiting a value of x for which P x holds!
The technical flaw here, from a constructive standpoint, is that we
claimed to prove ∃ x, P x using a proof of ¬ ¬ (∃ x, P
x). Allowing ourselves to remove double negations from arbitrary
statements is equivalent to assuming the excluded middle. Thus,
this line of reasoning cannot be encoded in Coq without assuming
additional axioms.
Only one of the following lemmas is provable in constructive
logic. Which? Why isn't the other provable?
Exercise: 2 stars, standard (forall_exists)
In classical logic, ∀ and ∃ are dual: negating one gets you to the other. We saw some of this duality with dist_not_exists and dist_not_forall.
Lemma not_exists__forall_not : ∀ {X : Type} (P : X → Prop),
(¬ ∃ x, P x) → ∀ x, ¬ P x.
Proof. (* FILL IN HERE *) Admitted.
Lemma not_forall__exists_not : ∀ {X : Type} (P : X → Prop),
(¬ ∀ x, P x) → ∃ x, ¬ P x.
Proof.
(* FILL IN HERE *) Admitted.
(¬ ∃ x, P x) → ∀ x, ¬ P x.
Proof. (* FILL IN HERE *) Admitted.
Lemma not_forall__exists_not : ∀ {X : Type} (P : X → Prop),
(¬ ∀ x, P x) → ∃ x, ¬ P x.
Proof.
(* FILL IN HERE *) Admitted.
In addition to doing one of these proofs, please briefly explain
why the other doesn't work.
(* FILL IN HERE *)
☐
☐
(* 2022-01-12 10:20 *)