IndProp1: Inductively Defined Propositionspart 1

Set Warnings "-notation-overridden,-parsing,-deprecated-hint-without-locality".
From LF Require Export Logic.

Inductively Defined Propositions

In the Logic chapter, we looked at several ways of writing propositions, including conjunction, disjunction, and existential quantification.
In this chapter, we bring yet another new tool into the mix: inductively defined propositions.
To begin, some examples...

The Collatz Conjecture

The Collatz Conjecture is a famous open problem in number theory.
Its statement is surprisingly simple. First, we define a function f on numbers, as follows:
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.
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.
Fail Fixpoint reaches1_in (n : nat) : nat :=
  if n =? 1 then 0
  else 1 + reaches1_in (f n).
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:
   (reach_one)  

reaches1 1
Even n      reaches1 (div2 n) (reach_even)  

reaches1 n
~Even n     reaches1 ((3 * n) + 1) (reach_odd)  

reaches1 n
So there are three ways to prove that a number n reaches 1 in the Collatz sequence:
  • n is 1;
  • n is even and div2 n reaches 1;
  • n is odd and (3 × n) + 1 reaches 1.
We can prove that a number reaches 1 by constructing a (finite) derivation using these rules. For instance, here is the derivation proving that 12 reaches 1 (where we left out the evenness/oddness premises):
                        ——————————— (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:
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.
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:
Conjecture collatz : n, reaches1 n.
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

A binary relation on a set X has Coq type X X Prop. This is a family of propositions parameterized by two elements of X -- i.e., a proposition about pairs of elements of X.
For example, a familiar binary relation on nat is le : nat nat Prop, the less-than-or-equal-to relation, which can be inductively defined by the following two rules:
Module LePlayground.
   (le_n)  

le n n
le n m (le_S)  

le n (S m)
These rules say that there are two ways to show that one number is less than or equal to another: either observe that they are the same number, or, if the second has the form S m, give evidence that the first is less than or equal to m.
This corresponds to the following inductive definition in Coq:
Inductive le : nat nat Prop :=
  | 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:
Definition collatz_step (n m : nat) : Prop := f n = m.
This Collatz step relation is useful in conjunction with the reflexive and transitive closure operation below.

Reflexive and Transitive Closure

The reflexive and transitive closure of a relation R is the smallest relation that contains R and that is reflexive and transitive. This can be defined by the following three rules:
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
Computing the reflexive and transitive closure can be undecidable even for a relation R that is decidable (e.g. collatz_step_rel), so in general we can't expect to define reflexive and transitive closure as a boolean function. Fortunately, Coq allows us to define reflexive and transitive closure as an inductive relation directly encoding the three rules above:
Inductive clos_refl_trans {X: Type} (R: XXProp) : XXProp :=
  | 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:
Definition cms n m := clos_refl_trans collatz_step n m.
Conjecture collatz' : n, cms n 1.
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

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

The familiar mathematical concept of permutation also has an elegant formulation as an inductive relation. For simplicity, let's focus on permutations of lists with exactly three elements. We can define them by the following rules:
   (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
For instance we can derive Perm3 [1;2;3] [3;2;1] as follows:

————————(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]
In Coq Perm3 is given the following inductive definition:
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.
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)

We've already seen two ways of stating a proposition that a number n is even: We can say
(1) even n = true, or
(2) k, n = double k.
A third possibility, which we'll use as a running example for some of this chapter, is to say that n is even if we can establish its evenness from the following two rules:
  • The number 0 is even.
  • If n is even, then S (S n) is even.
(Defining evenness in this way may seem a bit confusing, since we have already seen another perfectly good way of doing it -- "n is even if it is equal to the result of doubling some number". But it makes a convenient running example because it is simple and compact.)
To illustrate how this new definition of evenness works, let's imagine using it to show that 4 is even. First, we give the rules names for easy reference:
   (ev_0)  

ev 0
ev n (ev_SS)  

ev (S (S n))
Now we can use the following derivation to show ev 4:
                           ———— (ev_0)
                           ev 0
                       ———————————— (ev_SS)
                       ev (S (S 0))
                   ———————————————————— (ev_SS)
                   ev (S (S (S (S 0))))
In words, to show that 4 is even, by rule ev_SS, it suffices to show that 2 is even. This, in turn, is again guaranteed by rule ev_SS, as long as we can show that 0 is even. But this last fact follows directly from the ev_0 rule.
We can translate the informal definition of evenness from above into a formal Inductive declaration, where each "way that a number can be even" corresponds to a separate constructor:
Inductive ev : nat Prop :=
  | ev_0 : ev 0
  | ev_SS (n : nat) (H : ev n) : ev (S (S n)).
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:
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". *)

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.
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...
Theorem ev_4 : ev 4.
Proof. apply ev_SS. apply ev_SS. apply ev_0. Qed.
... or we can use function application syntax to combine several constructors:
Theorem ev_4' : ev 4.
Proof. apply (ev_SS 2 (ev_SS 0 ev_0)). Qed.
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.

Exercise: 1 star, standard (ev_double)

Theorem ev_double : n,
  ev (double n).
Proof.
  (* FILL IN HERE *) Admitted.

Constructing Evidence for Permutations

Similarly we can apply the evidence constructors to obtain evidence of Perm3 [1;2;3] [3;2;1]:
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.
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.
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.

Using Evidence in Proofs

Besides constructing evidence that numbers are even, we can also destruct such evidence, reasoning about how it could have been built.
Introducing ev with an Inductive declaration tells Coq not only that the constructors ev_0 and ev_SS are valid ways to build evidence that some number is ev, but also that these two constructors are the only ways to build evidence that numbers are ev.
In other words, if someone gives us evidence E for the proposition ev n, then we know that E must be one of two things:
  • E = ev_0 and n = O, or
  • E = ev_SS n' E', where n = S (S n') and E' is evidence for ev n'.
This suggests that it should be possible to analyze a hypothesis of the form ev n much as we do inductively defined data structures; in particular, it should be possible to argue by case analysis or by induction on such evidence. Let's look at a few examples to see what this means in practice.

Destructing and Inverting Evidence

Suppose we are proving some fact involving a number n, and we are given ev n as a hypothesis. We already know how to perform case analysis on n using destruct or induction, generating separate subgoals for the case where n = O and the case where n = S n' for some n'. But for some proofs we may instead want to analyze the evidence for ev n directly.
As a tool for such proofs, we can formalize the intuitive characterization that we gave above for evidence of ev n, using destruct.
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.
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.
We can use the inversion lemma that we proved above to help structure proofs:
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.
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.
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.

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 SSSSev__even : n,
  ev (S (S (S (S n)))) ev n.
Proof.
  (* FILL IN HERE *) Admitted.

Exercise: 1 star, standard (ev5_nonsense)

Prove the following result using inversion.
Theorem ev5_nonsense :
  ev 5 2 + 2 = 9.
Proof.
  (* FILL IN HERE *) Admitted.
The inversion tactic does quite a bit of work. For example, when applied to an equality assumption, it does the work of both discriminate and injection. In addition, it carries out the intros and rewrites that are typically necessary in the case of injection. It can also be applied to analyze evidence for arbitrary inductively defined propositions, not just equality. As examples, we'll use it to re-prove some theorems from chapter Tactics. (Here we are being a bit lazy by omitting the as clause from inversion, thereby asking Coq to choose names for the variables and hypotheses that it introduces.)
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.
Here's how inversion works in general.
  • 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).
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.
Lemma ev_Even_firsttry : n,
  ev n Even n.
Proof.
  (* WORKED IN CLASS *) unfold Even.
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' *)
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.
    assert (H: ( k', n' = double k')
                ( 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

If this story feels familiar, it is no coincidence: We've encountered similar problems in the Induction chapter, when trying to use case analysis to prove results that required induction. And once again the solution is... induction!
The behavior of induction on evidence is the same as its behavior on data: It causes Coq to generate one subgoal for each constructor that could have used to build that evidence, while providing an induction hypothesis for each recursive occurrence of the property in question.
To prove that a property of n holds for all even numbers (i.e., those for which ev n holds), we can use induction on ev n. This requires us to prove two things, corresponding to the two ways in which ev n could have been constructed. If it was constructed by ev_0, then n=0 and the property must hold of 0. If it was constructed by ev_SS, then the evidence of ev n is of the form ev_SS n' E', where n = S (S n') and E' is evidence for ev n'. In this case, the inductive hypothesis says that the property we are trying to prove holds for n'.
Let's try proving that lemma again:
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.
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.
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_sum : n m, ev n ev m ev (n + m).
Proof.
  (* FILL IN HERE *) Admitted.

Exercise: 3 stars, advanced, especially useful (ev_ev__ev)

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.

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.

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).
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.
Theorem ev'_ev : n, ev' n ev n.
Proof.
 (* FILL IN HERE *) Admitted.
We can do similar inductive proofs on the Perm3 relation:
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.

Exercise: 2 stars, standard (Perm3_In)

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.

Exercise: 1 star, standard, optional (Perm3_NotIn)

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.

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.
Example Perm3_example2 : ¬ Perm3 [1;2;3] [1;2;4].
Proof.
  (* FILL IN HERE *) Admitted.

Inductive Relations

A proposition parameterized by a number (such as ev) can be thought of as a property -- i.e., it defines a subset of nat, namely those numbers for which the proposition is provable. In the same way, a two-argument proposition can be thought of as a relation -- i.e., it defines a set of pairs for which the proposition is provable.
Module Playground.
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).
(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.
The "strictly less than" relation n < m can now be defined in terms of le.
Definition lt (n m : nat) := le (S n) m.

Notation "m < n" := (lt m n).
The is defined in terms of .
Definition ge (m n : nat) : Prop := le n m.
Notation "m >= n" := (ge m n).

End Playground.
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.

Exercise: 2 stars, standard, especially useful (plus_le_facts1)

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.
Hint: May be easiest to prove by induction on n.
Proof.
(* FILL IN HERE *) Admitted.

Exercise: 2 stars, standard, especially useful (plus_le_facts2)

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.

Exercise: 3 stars, standard, optional (lt_facts)

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.

Exercise: 4 stars, standard, optional (leb_le)

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.
Hint:
Proof.
  (* 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.
Module R.

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
.
  • 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.

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.
End R.

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.

Exercise: 2 stars, standard, optional (R_provability2)

Suppose we give Coq the following definition:
    Inductive R : natlist natProp :=
      | 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 *)