IndProp1: Inductively Defined Propositionspart 1
Set Warnings "-notation-overridden,-parsing,-deprecated-hint-without-locality".
From LF Require Export Logic.
From LF Require Export Logic.
Inductively Defined Propositions
The Collatz Conjecture
Fixpoint div2 (n : nat) :=
match n with
0 ⇒ 0
| 1 ⇒ 0
| S (S n) ⇒ S (div2 n)
end.
Definition f (n : nat) :=
if even n then div2 n
else (3 × n) + 1.
match n with
0 ⇒ 0
| 1 ⇒ 0
| S (S n) ⇒ S (div2 n)
end.
Definition f (n : nat) :=
if even n then div2 n
else (3 × n) + 1.
Next, we look at what happens when we repeatedly apply f to some
given starting number. For example, f 12 is 6, and f 6 is
3, so by repeatedly applying f we get the sequence 12, 6, 3,
10, 5, 16, 8, 4, 2, 1.
Similarly, if we start with 19, we get the longer sequence 19,
58, 29, 88, 44, 22, 11, 34, 17, 52, 26, 13, 40, 20, 10, 5, 16, 8,
4, 2, 1.
Both of these sequences eventually reach 1. The question posed
by Collatz was: Does the sequence starting from any natural
number eventually reach 1?
To formalize this question in Coq, we might try to define a
recursive function that computes the total number of steps that
it takes for such a sequence to reach 1.
This definition is rejected by Coq's termination checker, since
the argument to the recursive call, f n, is not "obviously
smaller" than n.
Indeed, this isn't just a silly limitation of the termination
checker. Functions in Coq are required to be total, and checking
that this particular function is total would be equivalent to
settling the Collatz conjecture!
Fortunately, there is another way to do it: We can express the
concept "reaches 1 eventually" as an inductively defined
property of numbers reaches1 : nat → Prop. Intuitively, this
property is defined by a set of rules:
So there are three ways to prove that a number n reaches 1 in
the Collatz sequence:
——————————— (reach_one)
reaches1 1
——————————— (reach_even)
reaches1 2
——————————— (reach_even)
reaches1 4
——————————— (reach_even)
reaches1 8
——————————— (reach_even)
reaches1 16
——————————— (reach_odd)
reaches1 5
——————————— (reach_even)
reaches1 10
——————————— (reach_odd)
reaches1 3
——————————— (reach_even)
reaches1 6
——————————— (reach_even)
reaches1 12
Formally in Coq, reaches1 is an inductively defined property
of numbers:
(reach_one) | |
reaches1 1 |
Even n reaches1 (div2 n) | (reach_even) |
reaches1 n |
~Even n reaches1 ((3 * n) + 1) | (reach_odd) |
reaches1 n |
- n is 1;
- n is even and div2 n reaches 1;
- n is odd and (3 × n) + 1 reaches 1.
——————————— (reach_one)
reaches1 1
——————————— (reach_even)
reaches1 2
——————————— (reach_even)
reaches1 4
——————————— (reach_even)
reaches1 8
——————————— (reach_even)
reaches1 16
——————————— (reach_odd)
reaches1 5
——————————— (reach_even)
reaches1 10
——————————— (reach_odd)
reaches1 3
——————————— (reach_even)
reaches1 6
——————————— (reach_even)
reaches1 12
Inductive reaches1 : nat → Prop :=
| reach_one : reaches1 1
| reach_even (n : nat) : Even n →
reaches1 (div2 n) →
reaches1 n
| reach_odd (n : nat) : ¬Even n →
reaches1 ((3 × n) + 1) →
reaches1 n.
| reach_one : reaches1 1
| reach_even (n : nat) : Even n →
reaches1 (div2 n) →
reaches1 n
| reach_odd (n : nat) : ¬Even n →
reaches1 ((3 × n) + 1) →
reaches1 n.
The details of how such inductive definitions are written are not
important and will be explained later. For the moment, note that
the 3 constructors correspond exactly to the 3 rules above.
The Collatz conjecture then states that the sequence beginning
from any number reaches 1:
If you succeed in proving this conjecture, you've got a bright
future as a number theorist. But don't spend too long on it --
it's been open since 1937!
Binary relations
(le_n) | |
le n n |
le n m | (le_S) |
le n (S m) |
Inductive le : nat → nat → Prop :=
| le_n (n : nat) : le n n
| le_S (n m : nat) : le n m → le n (S m).
| le_n (n : nat) : le n n
| le_S (n m : nat) : le n m → le n (S m).
This is a bit simpler and more elegant than the Boolean function
leb we defined in Basics. As usual, le and leb are
equivalent, and there is an exercise about that.
The Collatz step function f also allows us to define a
corresponding binary relation:
This Collatz step relation is useful in conjunction with the
reflexive and transitive closure operation below.
Reflexive and Transitive Closure
R x y | (rt_step) |
clos_refl_trans R x y |
(rt_refl) | |
clos_refl_trans R x x |
clos_refl_trans R x y clos_refl_trans R y z | (rt_trans) |
clos_refl_trans R x z |
Inductive clos_refl_trans {X: Type} (R: X→X→Prop) : X→X→Prop :=
| rt_step (x y : X) :
R x y →
clos_refl_trans R x y
| rt_refl (x : X) :
clos_refl_trans R x x
| rt_trans (x y z : X) :
clos_refl_trans R x y →
clos_refl_trans R y z →
clos_refl_trans R x z.
| rt_step (x y : X) :
R x y →
clos_refl_trans R x y
| rt_refl (x : X) :
clos_refl_trans R x x
| rt_trans (x y z : X) :
clos_refl_trans R x y →
clos_refl_trans R y z →
clos_refl_trans R x z.
The reflexive and transitive closure of a binary relation
cannot, in general, be expressed in first-order logic. The logic
of Coq is, however, much more powerful, and can easily define such
inductive relations.
This enables an equivalent definition of the Collatz conjecture:
This cms (Collatz multi-step) relation defined in terms of
clos_refl_trans allows for more interesting derivations than the
linear ones of the directly defined reaches1 relation:
f 16 = 8 f 8 = 4 f 4 = 2 f 2 = 1
————————(rt_step) ———————(rt_step) ———————(rt_step) ———————(rt_step)
cms 16 8 cms 8 4 cms 4 2 cms 2 1
—————————————————————————(rt_trans) ————————————————————————(rt_trans)
cms 16 4 cms 4 1
—————————————————————————————————————————————(rt_trans)
cms 16 1
f 16 = 8 f 8 = 4 f 4 = 2 f 2 = 1
————————(rt_step) ———————(rt_step) ———————(rt_step) ———————(rt_step)
cms 16 8 cms 8 4 cms 4 2 cms 2 1
—————————————————————————(rt_trans) ————————————————————————(rt_trans)
cms 16 4 cms 4 1
—————————————————————————————————————————————(rt_trans)
cms 16 1
Exercise: 1 star, standard, optional (close_refl)
How would you modify this definition so that it defines transitive closure (i.e. not reflexive)? How about reflexive, symmetric, and transitive closure?
(* FILL IN HERE *)
☐
☐
Permutations
(perm3_swap12) | |
Perm3 [a;b;c] [b;a;c] |
(perm3_swap23) | |
Perm3 [a;b;c] [a;c;b] |
Perm3 l1 l2 Perm3 l2 l3 | (perm3_trans) |
Perm3 l1 l3 |
————————(perm_swap12) —————————————————————(perm_swap23)
Perm3 [1;2;3] [2;1;3] Perm3 [2;1;3] [2;3;1]
——————————————————————————————(perm_trans) ————————————(perm_swap12)
Perm3 [1;2;3] [2;3;1] Perm [2;3;1] [3;2;1]
—————————————————————————————————————————————————————(perm_trans)
Perm3 [1;2;3] [3;2;1]
Inductive Perm3 {X : Type} : list X → list X → Prop :=
| perm3_swap12 (a b c : X) :
Perm3 [a;b;c] [b;a;c]
| perm3_swap23 (a b c : X) :
Perm3 [a;b;c] [a;c;b]
| perm3_trans (l1 l2 l3 : list X) :
Perm3 l1 l2 → Perm3 l2 l3 → Perm3 l1 l3.
| perm3_swap12 (a b c : X) :
Perm3 [a;b;c] [b;a;c]
| perm3_swap23 (a b c : X) :
Perm3 [a;b;c] [a;c;b]
| perm3_trans (l1 l2 l3 : list X) :
Perm3 l1 l2 → Perm3 l2 l3 → Perm3 l1 l3.
This definition says:
- If l2 can be obtained from l1 by swapping the first and second elements, then l2 is a permutation of l1.
- If l2 can be obtained from l1 by swapping the second and third elements, then l2 is a permutation of l1.
- If l2 is a permutation of l1 and l3 is a permutation of l2, then l3 is a permutation of l1.
Exercise: 1 star, standard, optional (perm)
According to this definition, is [1;2;3] a permutation of itself?
(* FILL IN HERE *)
☐
☐
Evenness (yet again)
- The number 0 is even.
- If n is even, then S (S n) is even.
(ev_0) | |
ev 0 |
ev n | (ev_SS) |
ev (S (S n)) |
———— (ev_0)
ev 0
———————————— (ev_SS)
ev (S (S 0))
———————————————————— (ev_SS)
ev (S (S (S (S 0))))
This definition is interestingly different from previous uses of
Inductive. For one thing, we are defining not a Type (like
nat) or a function yielding a Type (like list), but rather a
function from nat to Prop -- that is, a property of numbers.
But what is really new is that, because the nat argument of ev
appears to the right of the colon on the first line, it is
allowed to take different values in the types of different
constructors: 0 in the type of ev_0 and S (S n) in the type
of ev_SS. Accordingly, the type of each constructor must be
specified explicitly (after a colon), and each constructor's type
must have the form ev n for some natural number n.
In contrast, recall the definition of list:
Inductive list (X:Type) : Type :=
| nil
| cons (x : X) (l : list X). or equivalently:
Inductive list (X:Type) : Type :=
| nil : list X
| cons (x : X) (l : list X) : list X. This definition introduces the X parameter globally, to the left of the colon, forcing the result of nil and cons to be the same type (i.e., list X). But if we had tried to bring nat to the left of the colon in defining ev, we would have seen an error:
Inductive list (X:Type) : Type :=
| nil
| cons (x : X) (l : list X). or equivalently:
Inductive list (X:Type) : Type :=
| nil : list X
| cons (x : X) (l : list X) : list X. This definition introduces the X parameter globally, to the left of the colon, forcing the result of nil and cons to be the same type (i.e., list X). But if we had tried to bring nat to the left of the colon in defining ev, we would have seen an error:
Fail Inductive wrong_ev (n : nat) : Prop :=
| wrong_ev_0 : wrong_ev 0
| wrong_ev_SS (H: wrong_ev n) : wrong_ev (S (S n)).
(* ===> Error: Last occurrence of "wrong_ev" must have "n" as 1st
argument in "wrong_ev 0". *)
| wrong_ev_0 : wrong_ev 0
| wrong_ev_SS (H: wrong_ev n) : wrong_ev (S (S n)).
(* ===> Error: Last occurrence of "wrong_ev" must have "n" as 1st
argument in "wrong_ev 0". *)
In an Inductive definition, an argument to the type constructor
on the left of the colon is called a "parameter", whereas an
argument on the right is called an "index" or "annotation."
For example, in Inductive list (X : Type) := ..., the X is a
parameter, while in Inductive ev : nat → Prop := ..., the
unnamed nat argument is an index.
We can think of the inductive definition of ev this as defining
a Coq property ev : nat → Prop, together with "evidence
constructors" ev_0 : ev 0 and
ev_SS : ∀ n, ev n → ev (S (S n)). In fact, Coq also
accepts the following equivalent definition of ev:
Module EvPlayground.
Inductive ev : nat → Prop :=
| ev_0 : ev 0
| ev_SS : ∀ (n : nat), ev n → ev (S (S n)).
End EvPlayground.
Inductive ev : nat → Prop :=
| ev_0 : ev 0
| ev_SS : ∀ (n : nat), ev n → ev (S (S n)).
End EvPlayground.
These evidence constructors can be thought of as "primitive
evidence of evenness", and they can be used just like proven
theorems. In particular, we can use Coq's apply tactic with the
constructor names to obtain evidence for ev of particular
numbers...
... or we can use function application syntax to combine several
constructors:
In this way, we can also prove theorems that have hypotheses
involving ev.
Theorem ev_plus4 : ∀ n, ev n → ev (4 + n).
Proof.
intros n. simpl. intros Hn. apply ev_SS. apply ev_SS. apply Hn.
Qed.
Proof.
intros n. simpl. intros Hn. apply ev_SS. apply ev_SS. apply Hn.
Qed.
Constructing Evidence for Permutations
Lemma Perm3_rev : Perm3 [1;2;3] [3;2;1].
Proof.
apply perm3_trans with (l2:=[2;3;1]).
- apply perm3_trans with (l2:=[2;1;3]).
+ apply perm3_swap12.
+ apply perm3_swap23.
- apply perm3_swap12.
Qed.
Proof.
apply perm3_trans with (l2:=[2;3;1]).
- apply perm3_trans with (l2:=[2;1;3]).
+ apply perm3_swap12.
+ apply perm3_swap23.
- apply perm3_swap12.
Qed.
And again we can equivalently use function application syntax to
combine several constructors. Note that the Coq type checker can
infer not only types, but also nats and lists.
Lemma Perm3_rev' : Perm3 [1;2;3] [3;2;1].
Proof.
apply (perm3_trans _ [2;3;1] _
(perm3_trans _ [2;1;3] _
(perm3_swap12 _ _ _)
(perm3_swap23 _ _ _))
(perm3_swap12 _ _ _)).
Qed.
Proof.
apply (perm3_trans _ [2;3;1] _
(perm3_trans _ [2;1;3] _
(perm3_swap12 _ _ _)
(perm3_swap23 _ _ _))
(perm3_swap12 _ _ _)).
Qed.
So the informal derivation trees we drew above are not too far
from what's happening formally. Formally we're using the evidence
constructors to build evidence trees, similar to the trees we
built using the constructors of data types such as nat, list,
binary trees storing numbers, etc.
Exercise: 1 star, standard (Perm3)
Lemma Perm3_ex1 : Perm3 [1;2;3] [2;3;1].
Proof.
(* FILL IN HERE *) Admitted.
Lemma Perm3_refl : ∀ (X : Type) (a b c : X),
Perm3 [a;b;c] [a;b;c].
Proof.
(* FILL IN HERE *) Admitted.
☐
Proof.
(* FILL IN HERE *) Admitted.
Lemma Perm3_refl : ∀ (X : Type) (a b c : X),
Perm3 [a;b;c] [a;b;c].
Proof.
(* FILL IN HERE *) Admitted.
☐
Using Evidence in Proofs
- E = ev_0 and n = O, or
- E = ev_SS n' E', where n = S (S n') and E' is evidence for ev n'.
Destructing and Inverting Evidence
Theorem ev_inversion : ∀ (n : nat),
ev n →
(n = 0) ∨ (∃ n', n = S (S n') ∧ ev n').
Proof.
intros n E. destruct E as [ | n' E'] eqn:EE.
- (* E = ev_0 : ev 0 *)
left. reflexivity.
- (* E = ev_SS n' E' : ev (S (S n')) *)
right. ∃ n'. split. reflexivity. apply E'.
Qed.
ev n →
(n = 0) ∨ (∃ n', n = S (S n') ∧ ev n').
Proof.
intros n E. destruct E as [ | n' E'] eqn:EE.
- (* E = ev_0 : ev 0 *)
left. reflexivity.
- (* E = ev_SS n' E' : ev (S (S n')) *)
right. ∃ n'. split. reflexivity. apply E'.
Qed.
Facts like this are often called "inversion lemmas" because they
allow us to "invert" some given information to reason about all
the different ways it could have been derived. Here, there are two ways to prove ev n, and the inversion
lemma makes this explicit.
Exercise: 1 star, standard (le_inversion)
Let's prove a similar inversion lemma for le.
Theorem le_inversion : ∀ (n m : nat),
le n m →
(n = m) ∨ (∃ m', m = S m' ∧ le n m').
Proof.
(* FILL IN HERE *) Admitted.
☐
le n m →
(n = m) ∨ (∃ m', m = S m' ∧ le n m').
Proof.
(* FILL IN HERE *) Admitted.
☐
Theorem evSS_ev : ∀ n, ev (S (S n)) → ev n.
Proof.
intros n E. apply ev_inversion in E. destruct E as [H0|H1].
- discriminate H0.
- destruct H1 as [n' [Hnn' E']]. injection Hnn' as Hnn'.
rewrite Hnn'. apply E'.
Qed.
Proof.
intros n E. apply ev_inversion in E. destruct E as [H0|H1].
- discriminate H0.
- destruct H1 as [n' [Hnn' E']]. injection Hnn' as Hnn'.
rewrite Hnn'. apply E'.
Qed.
Note how the inversion lemma produces two subgoals, which
correspond to the two ways of proving ev. The first subgoal is
a contradiction that is discharged with discriminate. The
second subgoal makes use of injection and rewrite.
Coq provides a handy tactic called inversion that factors out
this common pattern, saving us the trouble of explicitly stating
and proving an inversion lemma for every Inductive definition we
make.
Here, the inversion tactic can detect (1) that the first case,
where n = 0, does not apply and (2) that the n' that appears
in the ev_SS case must be the same as n. It includes an
"as" annotation similar to destruct, allowing us to assign
names rather than have Coq choose them.
Theorem evSS_ev' : ∀ n,
ev (S (S n)) → ev n.
Proof.
intros n E. inversion E as [| n' E' Hnn'].
(* We are in the E = ev_SS n' E' case now. *)
apply E'.
Qed.
ev (S (S n)) → ev n.
Proof.
intros n E. inversion E as [| n' E' Hnn'].
(* We are in the E = ev_SS n' E' case now. *)
apply E'.
Qed.
The inversion tactic can apply the principle of explosion to
"obviously contradictory" hypotheses involving inductively defined
properties, something that takes a bit more work using our
inversion lemma. Compare:
Theorem one_not_even : ¬ ev 1.
Proof.
intros H. apply ev_inversion in H. destruct H as [ | [m [Hm _]]].
- discriminate H.
- discriminate Hm.
Qed.
Theorem one_not_even' : ¬ ev 1.
Proof. intros H. inversion H. Qed.
Proof.
intros H. apply ev_inversion in H. destruct H as [ | [m [Hm _]]].
- discriminate H.
- discriminate Hm.
Qed.
Theorem one_not_even' : ¬ ev 1.
Proof. intros H. inversion H. Qed.
Exercise: 1 star, standard (inversion_practice)
Prove the following result using inversion. (For extra practice, you can also prove it using the inversion lemma.)
Theorem inversion_ex1 : ∀ (n m o : nat),
[n; m] = [o; o] → [n] = [m].
Proof.
intros n m o H. inversion H. reflexivity. Qed.
Theorem inversion_ex2 : ∀ (n : nat),
S n = O → 2 + 2 = 5.
Proof.
intros n contra. inversion contra. Qed.
[n; m] = [o; o] → [n] = [m].
Proof.
intros n m o H. inversion H. reflexivity. Qed.
Theorem inversion_ex2 : ∀ (n : nat),
S n = O → 2 + 2 = 5.
Proof.
intros n contra. inversion contra. Qed.
Here's how inversion works in general.
The ev_double exercise above allows us to easily show that
our new notion of evenness is implied by the two earlier ones
(since, by even_bool_prop in chapter Logic, we already
know that those are equivalent to each other). To show that all
three coincide, we just need the following lemma.
- Suppose the name H refers to an assumption P in the current context, where P has been defined by an Inductive declaration.
- Then, for each of the constructors of P, inversion H generates a subgoal in which H has been replaced by the specific conditions under which this constructor could have been used to prove P.
- Some of these subgoals will be self-contradictory; inversion throws these away.
- The ones that are left represent the cases that must be proved to establish the original goal. For those, inversion adds to the proof context all equations that must hold of the arguments given to P -- e.g., S (S n') = n in the proof of evSS_ev).
We could try to proceed by case analysis or induction on n. But
since ev is mentioned in a premise, this strategy seems
unpromising, because (as we've noted before) the induction
hypothesis will talk about n-1 (which is not even!). Thus, it
seems better to first try inversion on the evidence for ev.
Indeed, the first case can be solved trivially. And we can
seemingly make progress on the second case with a helper lemma.
intros n E. inversion E as [EQ' | n' E' EQ'].
- (* E = ev_0 *) ∃ 0. reflexivity.
- (* E = ev_SS n' E' *)
- (* E = ev_0 *) ∃ 0. reflexivity.
- (* E = ev_SS n' E' *)
Unfortunately, the second case is harder. We need to show ∃
n0, S (S n') = double n0, but the only available assumption is
E', which states that ev n' holds. Since this isn't directly
useful, it seems that we are stuck and that performing case
analysis on E was a waste of time.
If we look more closely at our second goal, however, we can see
that something interesting happened: By performing case analysis
on E, we were able to reduce the original result to a similar
one that involves a different piece of evidence for ev: namely
E'. More formally, we could finish our proof if we could show
that
∃ k', n' = double k', which is the same as the original statement, but with n' instead of n. Indeed, it is not difficult to convince Coq that this intermediate result would suffice.
∃ k', n' = double k', which is the same as the original statement, but with n' instead of n. Indeed, it is not difficult to convince Coq that this intermediate result would suffice.
assert (H: (∃ k', n' = double k')
→ (∃ n0, S (S n') = double n0)).
{ intros [k' EQ'']. ∃ (S k'). simpl.
rewrite <- EQ''. reflexivity. }
apply H.
→ (∃ n0, S (S n') = double n0)).
{ intros [k' EQ'']. ∃ (S k'). simpl.
rewrite <- EQ''. reflexivity. }
apply H.
Unfortunately, now we are stuck. To see this clearly, let's
move E' back into the goal from the hypotheses.
generalize dependent E'.
Now it is obvious that we are trying to prove another instance
of the same theorem we set out to prove -- only here we are
talking about n' instead of n.
Abort.
Induction on Evidence
Lemma ev_Even : ∀ n,
ev n → Even n.
Proof.
unfold Even. intros n E.
induction E as [|n' E' IH].
- (* E = ev_0 *)
∃ 0. reflexivity.
- (* E = ev_SS n' E', with IH : Even n' *)
destruct IH as [k Hk]. rewrite Hk.
∃ (S k). simpl. reflexivity.
Qed.
ev n → Even n.
Proof.
unfold Even. intros n E.
induction E as [|n' E' IH].
- (* E = ev_0 *)
∃ 0. reflexivity.
- (* E = ev_SS n' E', with IH : Even n' *)
destruct IH as [k Hk]. rewrite Hk.
∃ (S k). simpl. reflexivity.
Qed.
Here, we can see that Coq produced an IH that corresponds
to E', the single recursive occurrence of ev in its own
definition. Since E' mentions n', the induction hypothesis
talks about n', as opposed to n or some other number.
The equivalence between the second and third definitions of
evenness now follows.
Theorem ev_Even_iff : ∀ n,
ev n ↔ Even n.
Proof.
intros n. split.
- (* -> *) apply ev_Even.
- (* <- *) unfold Even. intros [k Hk]. rewrite Hk. apply ev_double.
Qed.
ev n ↔ Even n.
Proof.
intros n. split.
- (* -> *) apply ev_Even.
- (* <- *) unfold Even. intros [k Hk]. rewrite Hk. apply ev_double.
Qed.
As we will see in later chapters, induction on evidence is a
recurring technique across many areas -- in particular for
formalizing the semantics of programming languages.
The following exercises provide simpler examples of this
technique, to help you familiarize yourself with it.
Exercise: 2 stars, standard (ev_sum)
Theorem ev_ev__ev : ∀ n m,
ev (n+m) → ev n → ev m.
(* Hint: There are two pieces of evidence you could attempt to induct upon
here. If one doesn't work, try the other. *)
Proof.
(* FILL IN HERE *) Admitted.
☐
ev (n+m) → ev n → ev m.
(* Hint: There are two pieces of evidence you could attempt to induct upon
here. If one doesn't work, try the other. *)
Proof.
(* FILL IN HERE *) Admitted.
☐
Exercise: 3 stars, standard, optional (ev_plus_plus)
This exercise can be completed without induction or case analysis. But, you will need a clever assertion and some tedious rewriting. Hint: Is (n+m) + (n+p) even?
Theorem ev_plus_plus : ∀ n m p,
ev (n+m) → ev (n+p) → ev (m+p).
Proof.
(* FILL IN HERE *) Admitted.
☐
ev (n+m) → ev (n+p) → ev (m+p).
Proof.
(* FILL IN HERE *) Admitted.
☐
Exercise: 4 stars, advanced, optional (ev'_ev)
In general, there may be multiple ways of defining a property inductively. For example, here's a (slightly contrived) alternative definition for ev:
Inductive ev' : nat → Prop :=
| ev'_0 : ev' 0
| ev'_2 : ev' 2
| ev'_sum n m (Hn : ev' n) (Hm : ev' m) : ev' (n + m).
| ev'_0 : ev' 0
| ev'_2 : ev' 2
| ev'_sum n m (Hn : ev' n) (Hm : ev' m) : ev' (n + m).
Prove that this definition is logically equivalent to the old one.
To streamline the proof, use the technique (from the Logic
chapter) of applying theorems to arguments, and note that the same
technique works with constructors of inductively defined
propositions.
Lemma Perm3_symm : ∀ (X : Type) (l1 l2 : list X),
Perm3 l1 l2 → Perm3 l2 l1.
Proof.
intros X l1 l2 E.
induction E as [a b c | a b c | l1 l2 l3 E12 IH12 E23 IH23].
- apply perm3_swap12.
- apply perm3_swap23.
- apply (perm3_trans _ l2 _).
× apply IH23.
× apply IH12.
Qed.
Perm3 l1 l2 → Perm3 l2 l1.
Proof.
intros X l1 l2 E.
induction E as [a b c | a b c | l1 l2 l3 E12 IH12 E23 IH23].
- apply perm3_swap12.
- apply perm3_swap23.
- apply (perm3_trans _ l2 _).
× apply IH23.
× apply IH12.
Qed.
Lemma Perm3_In : ∀ (X : Type) (x : X) (l1 l2 : list X),
Perm3 l1 l2 → In x l1 → In x l2.
Proof.
(* FILL IN HERE *) Admitted.
☐
Perm3 l1 l2 → In x l1 → In x l2.
Proof.
(* FILL IN HERE *) Admitted.
☐
Lemma Perm3_NotIn : ∀ (X : Type) (x : X) (l1 l2 : list X),
Perm3 l1 l2 → ¬In x l1 → ¬In x l2.
Proof.
(* FILL IN HERE *) Admitted.
☐
Perm3 l1 l2 → ¬In x l1 → ¬In x l2.
Proof.
(* FILL IN HERE *) Admitted.
☐
Exercise: 2 stars, standard, optional (NotPerm3)
Proving that something is NOT a permutation is quite tricky. Some of the lemmas above, like Perm3_In can be useful for this.Inductive Relations
Just like properties, relations can be defined inductively. One
useful example is the "less than or equal to" relation on numbers
that we briefly saw above.
Inductive le : nat → nat → Prop :=
| le_n (n : nat) : le n n
| le_S (n m : nat) (H : le n m) : le n (S m).
Notation "n <= m" := (le n m).
| le_n (n : nat) : le n n
| le_S (n m : nat) (H : le n m) : le n (S m).
Notation "n <= m" := (le n m).
(We've written the definition a bit differently this time,
giving explicit names to the arguments to the constructors and
moving them to the left of the colons.)
Proofs of facts about ≤ using the constructors le_n and
le_S follow the same patterns as proofs about properties, like
ev above. We can apply the constructors to prove ≤
goals (e.g., to show that 3<=3 or 3<=6), and we can use
tactics like inversion to extract information from ≤
hypotheses in the context (e.g., to prove that (2 ≤ 1) →
2+2=5.)
Here are some sanity checks on the definition. (Notice that,
although these are the same kind of simple "unit tests" as we gave
for the testing functions we wrote in the first few lectures, we
must construct their proofs explicitly -- simpl and
reflexivity don't do the job, because the proofs aren't just a
matter of simplifying computations.)
Theorem test_le1 :
3 ≤ 3.
Proof.
(* WORKED IN CLASS *)
apply le_n. Qed.
Theorem test_le2 :
3 ≤ 6.
Proof.
(* WORKED IN CLASS *)
apply le_S. apply le_S. apply le_S. apply le_n. Qed.
Theorem test_le3 :
(2 ≤ 1) → 2 + 2 = 5.
Proof.
(* WORKED IN CLASS *)
intros H. inversion H. inversion H2. Qed.
3 ≤ 3.
Proof.
(* WORKED IN CLASS *)
apply le_n. Qed.
Theorem test_le2 :
3 ≤ 6.
Proof.
(* WORKED IN CLASS *)
apply le_S. apply le_S. apply le_S. apply le_n. Qed.
Theorem test_le3 :
(2 ≤ 1) → 2 + 2 = 5.
Proof.
(* WORKED IN CLASS *)
intros H. inversion H. inversion H2. Qed.
The "strictly less than" relation n < m can now be defined
in terms of le.
The ≥ is defined in terms of ≤.
From the definition of le, we can sketch the behaviors of
destruct, inversion, and induction on a hypothesis H
providing evidence of the form le e1 e2. Doing destruct H
will generate two cases. In the first case, e1 = e2, and it
will replace instances of e2 with e1 in the goal and context.
In the second case, e2 = S n' for some n' for which le e1 n'
holds, and it will replace instances of e2 with S n'.
Doing inversion H will remove impossible cases and add generated
equalities to the context for further use. Doing induction H
will, in the second case, add the induction hypothesis that the
goal holds when e2 is replaced with n'.
Here are a number of facts about the ≤ and < relations that
we are going to need later in the course. The proofs make good
practice exercises.
Exercise: 3 stars, standard, especially useful (le_facts)
Lemma le_trans : ∀ m n o, m ≤ n → n ≤ o → m ≤ o.
Proof.
(* FILL IN HERE *) Admitted.
Theorem O_le_n : ∀ n,
0 ≤ n.
Proof.
(* FILL IN HERE *) Admitted.
Theorem n_le_m__Sn_le_Sm : ∀ n m,
n ≤ m → S n ≤ S m.
Proof.
(* FILL IN HERE *) Admitted.
Theorem Sn_le_Sm__n_le_m : ∀ n m,
S n ≤ S m → n ≤ m.
Proof.
(* FILL IN HERE *) Admitted.
Theorem le_plus_l : ∀ a b,
a ≤ a + b.
Proof.
(* FILL IN HERE *) Admitted.
☐
Proof.
(* FILL IN HERE *) Admitted.
Theorem O_le_n : ∀ n,
0 ≤ n.
Proof.
(* FILL IN HERE *) Admitted.
Theorem n_le_m__Sn_le_Sm : ∀ n m,
n ≤ m → S n ≤ S m.
Proof.
(* FILL IN HERE *) Admitted.
Theorem Sn_le_Sm__n_le_m : ∀ n m,
S n ≤ S m → n ≤ m.
Proof.
(* FILL IN HERE *) Admitted.
Theorem le_plus_l : ∀ a b,
a ≤ a + b.
Proof.
(* FILL IN HERE *) Admitted.
☐
Theorem plus_le : ∀ n1 n2 m,
n1 + n2 ≤ m →
n1 ≤ m ∧ n2 ≤ m.
Proof.
(* FILL IN HERE *) Admitted.
Theorem plus_le_cases : ∀ n m p q,
n + m ≤ p + q → n ≤ p ∨ m ≤ q.
n1 + n2 ≤ m →
n1 ≤ m ∧ n2 ≤ m.
Proof.
(* FILL IN HERE *) Admitted.
Theorem plus_le_cases : ∀ n m p q,
n + m ≤ p + q → n ≤ p ∨ m ≤ q.
Hint: May be easiest to prove by induction on n.
Proof.
(* FILL IN HERE *) Admitted.
☐
(* FILL IN HERE *) Admitted.
☐
Theorem plus_le_compat_l : ∀ n m p,
n ≤ m →
p + n ≤ p + m.
Proof.
(* FILL IN HERE *) Admitted.
Theorem plus_le_compat_r : ∀ n m p,
n ≤ m →
n + p ≤ m + p.
Proof.
(* FILL IN HERE *) Admitted.
Theorem le_plus_trans : ∀ n m p,
n ≤ m →
n ≤ m + p.
Proof.
(* FILL IN HERE *) Admitted.
☐
n ≤ m →
p + n ≤ p + m.
Proof.
(* FILL IN HERE *) Admitted.
Theorem plus_le_compat_r : ∀ n m p,
n ≤ m →
n + p ≤ m + p.
Proof.
(* FILL IN HERE *) Admitted.
Theorem le_plus_trans : ∀ n m p,
n ≤ m →
n ≤ m + p.
Proof.
(* FILL IN HERE *) Admitted.
☐
Theorem lt_ge_cases : ∀ n m,
n < m ∨ n ≥ m.
Proof.
(* FILL IN HERE *) Admitted.
Theorem n_lt_m__n_le_m : ∀ n m,
n < m →
n ≤ m.
Proof.
(* FILL IN HERE *) Admitted.
Theorem plus_lt : ∀ n1 n2 m,
n1 + n2 < m →
n1 < m ∧ n2 < m.
Proof.
(* FILL IN HERE *) Admitted.
☐
n < m ∨ n ≥ m.
Proof.
(* FILL IN HERE *) Admitted.
Theorem n_lt_m__n_le_m : ∀ n m,
n < m →
n ≤ m.
Proof.
(* FILL IN HERE *) Admitted.
Theorem plus_lt : ∀ n1 n2 m,
n1 + n2 < m →
n1 < m ∧ n2 < m.
Proof.
(* FILL IN HERE *) Admitted.
☐
Theorem leb_complete : ∀ n m,
n <=? m = true → n ≤ m.
Proof.
(* FILL IN HERE *) Admitted.
Theorem leb_correct : ∀ n m,
n ≤ m →
n <=? m = true.
n <=? m = true → n ≤ m.
Proof.
(* FILL IN HERE *) Admitted.
Theorem leb_correct : ∀ n m,
n ≤ m →
n <=? m = true.
Hint:
Proof.
(* FILL IN HERE *) Admitted.
(* FILL IN HERE *) Admitted.
Hint: The next two can easily be proved without using induction.
Theorem leb_iff : ∀ n m,
n <=? m = true ↔ n ≤ m.
Proof.
(* FILL IN HERE *) Admitted.
Theorem leb_true_trans : ∀ n m o,
n <=? m = true → m <=? o = true → n <=? o = true.
Proof.
(* FILL IN HERE *) Admitted.
☐
n <=? m = true ↔ n ≤ m.
Proof.
(* FILL IN HERE *) Admitted.
Theorem leb_true_trans : ∀ n m o,
n <=? m = true → m <=? o = true → n <=? o = true.
Proof.
(* FILL IN HERE *) Admitted.
☐
Exercise: 3 stars, standard, especially useful (R_provability)
We can define three-place relations, four-place relations, etc., in just the same way as binary relations. For example, consider the following three-place relation on numbers:
Inductive R : nat → nat → nat → Prop :=
| c1 : R 0 0 0
| c2 m n o (H : R m n o ) : R (S m) n (S o)
| c3 m n o (H : R m n o ) : R m (S n) (S o)
| c4 m n o (H : R (S m) (S n) (S (S o))) : R m n o
| c5 m n o (H : R m n o ) : R n m o
.
| c1 : R 0 0 0
| c2 m n o (H : R m n o ) : R (S m) n (S o)
| c3 m n o (H : R m n o ) : R m (S n) (S o)
| c4 m n o (H : R (S m) (S n) (S (S o))) : R m n o
| c5 m n o (H : R m n o ) : R n m o
.
- Which of the following propositions are provable?
- R 1 1 2
- R 2 2 6
- If we dropped constructor c5 from the definition of R,
would the set of provable propositions change? Briefly (1
sentence) explain your answer.
- If we dropped constructor c4 from the definition of R, would the set of provable propositions change? Briefly (1 sentence) explain your answer.
(* FILL IN HERE *)
(* Do not modify the following line: *)
Definition manual_grade_for_R_provability : option (nat×string) := None.
☐
(* Do not modify the following line: *)
Definition manual_grade_for_R_provability : option (nat×string) := None.
☐
Exercise: 3 stars, standard, optional (R_fact)
The relation R above actually encodes a familiar function. Figure out which function; then state and prove this equivalence in Coq.
Definition fR : nat → nat → nat
(* REPLACE THIS LINE WITH ":= _your_definition_ ." *). Admitted.
Theorem R_equiv_fR : ∀ m n o, R m n o ↔ fR m n = o.
Proof.
(* FILL IN HERE *) Admitted.
☐
(* REPLACE THIS LINE WITH ":= _your_definition_ ." *). Admitted.
Theorem R_equiv_fR : ∀ m n o, R m n o ↔ fR m n = o.
Proof.
(* FILL IN HERE *) Admitted.
☐
Exercise: 4 stars, advanced (subsequence)
A list is a subsequence of another list if all of the elements in the first list occur in the same order in the second list, possibly with some extra elements in between. For example,[1;2;3] is a subsequence of each of the lists
[1;2;3]
[1;1;1;2;2;3]
[1;2;7;3]
[5;6;1;9;9;2;7;3;8] but it is not a subsequence of any of the lists
[1;2]
[1;3]
[5;6;2;1;7;3;8].
- Define an inductive proposition subseq on list nat that
captures what it means to be a subsequence. (Hint: You'll need
three cases.)
- Prove subseq_refl that subsequence is reflexive, that is,
any list is a subsequence of itself.
- Prove subseq_app that for any lists l1, l2, and l3,
if l1 is a subsequence of l2, then l1 is also a subsequence
of l2 ++ l3.
- (Harder) Prove subseq_trans that subsequence is transitive -- that is, if l1 is a subsequence of l2 and l2 is a subsequence of l3, then l1 is a subsequence of l3.
Inductive subseq : list nat → list nat → Prop :=
(* FILL IN HERE *)
.
Theorem subseq_refl : ∀ (l : list nat), subseq l l.
Proof.
(* FILL IN HERE *) Admitted.
Theorem subseq_app : ∀ (l1 l2 l3 : list nat),
subseq l1 l2 →
subseq l1 (l2 ++ l3).
Proof.
(* FILL IN HERE *) Admitted.
Theorem subseq_trans : ∀ (l1 l2 l3 : list nat),
subseq l1 l2 →
subseq l2 l3 →
subseq l1 l3.
Proof.
(* Hint: be careful about what you are doing induction on and which
other things need to be generalized... *)
(* FILL IN HERE *) Admitted.
☐
(* FILL IN HERE *)
.
Theorem subseq_refl : ∀ (l : list nat), subseq l l.
Proof.
(* FILL IN HERE *) Admitted.
Theorem subseq_app : ∀ (l1 l2 l3 : list nat),
subseq l1 l2 →
subseq l1 (l2 ++ l3).
Proof.
(* FILL IN HERE *) Admitted.
Theorem subseq_trans : ∀ (l1 l2 l3 : list nat),
subseq l1 l2 →
subseq l2 l3 →
subseq l1 l3.
Proof.
(* Hint: be careful about what you are doing induction on and which
other things need to be generalized... *)
(* FILL IN HERE *) Admitted.
☐
Exercise: 2 stars, standard, optional (R_provability2)
Suppose we give Coq the following definition:Inductive R : nat → list nat → Prop :=
| c1 : R 0 []
| c2 n l (H: R n l) : R (S n) (n :: l)
| c3 n l (H: R (S n) l) : R n l. Which of the following propositions are provable?
- R 2 [1;0]
- R 1 [1;2;1;0]
- R 6 [3;2;1;0]
(* FILL IN HERE *)
☐
☐
(* 2023-08-16 16:28 *)