Inductive Principles
Table of Contents
Homepage | Previous: ProofObjects.v | Code | Next: Maps.v
1. Summary
1.1. Terms
induction principle, t_ind
, induction hypothesis, induction
tactic, induction on proof trees, proof objects for induction.
2. Notes
2.1. Basics
An induction proof for P(n)
where n : nat
can be written like this:
- Base case. (
n = 0
) ShowP(0)
holds. - Induction step. (
n = S n'
for somen'
) IH:P(n')
holds. ShowP(S n')
holds.
This is an application of the induction principle for natural numbers. We will call this nat_ind
. In Coq, this is represented as:
Check nat_ind : forall P : nat -> Prop, P 0 -> (forall n : nat, P n -> P (S n)) -> forall n : nat, P n.
And for any other inductively defined type t
, the corresponding induction principle is called t_ind
.
It turns out that the induction
tactic is a wrapper that performs apply t_ind
with some book-keeping.
If we define a type t
with constructors c1 ... cn
, Coq generates a theorem with this shape:
t_ind : forall P : t -> Prop, ... case for c1 ... -> ... case for c2 ... -> ... ... case for cn ... -> forall n : t, P n
It is important to familiarize yourself with the cases generated for the recursive constructors.
Here is a solution to an exercise.
Inductive booltree : Type := | bt_empty | bt_leaf (b : bool) | bt_branch (b : bool) (t1 t2 : booltree). Definition booltree_property_type : Type := booltree -> Prop. Definition base_case (P : booltree_property_type) : Prop := P bt_empty. Definition leaf_case (P : booltree_property_type) : Prop := forall (b : bool), P (bt_leaf b). Definition branch_case (P : booltree_property_type) : Prop := forall (b : bool) (t1 : booltree), P t1 -> forall (t2 : booltree), P t2 -> P (bt_branch b t1 t2). Definition booltree_ind_type := forall (P : booltree_property_type), base_case P -> leaf_case P -> branch_case P -> forall (b : booltree), P b.
2.2. Polymorphism
A polymorphic type on X
is a definition of a family of inductive types indexed by X
.
Note that in the following polymorphic type (list
), whenever list
is in
the body of the declaration, it is always applied to the parameter X
.
Inductive list (X:Type) : Type := | nil : list X | cons : X -> list X -> list X. list_ind : forall (X : Type) (P : list X -> Prop), P [] -> (forall (x : X) (l : list X), P l -> P (x :: l)) -> forall l : list X, P l
The induction principle is also parametrized on X
. It can be thought of as a function that when applied to type X
, gives list_ind
for X
lists.
2.3. Induction Principles for Propositions
Recall ev
, an inductive proposition, from IndProp.v
.
Inductive ev : nat -> Prop := | ev_0 : ev 0 | ev_SS : forall n : nat, ev n -> ev (S (S n)).
Our ev_ind
would then be:
Check ev_ind : forall P : nat -> Prop, P 0 -> (forall n : nat, ev n -> P n -> P (S (S n))) -> forall n : nat, ev n -> P n.
This is a bit different from the induction principles on datatypes.
Quoting, this is what it is in English:
In English,
ev_ind
says: SupposeP
is a property of natural numbers. To show thatP n
holds whenevern
is even, it suffices to show:
P
holds for0
,- for any
n
, ifn
is even andP
holds forn
, thenP
holds forS (S n)
.
It is like an inversion on ev n
, plus an induction hypothesis in the recursive cases. And since P n
is a proposition on n
, it isn’t P
that applies to ev_0
(for instance), but on n = 0
when the case is ev_0
, or for le
’s case (a binary relation), the inductive case is
(forall m : nat, n <=2 m -> P m -> P (S m)) -> forall n0 : nat, n <=2 n0
Note that we need to show P n (S m')
- the induction principle is parametrized on m
.
(This description may be inaccurate.)
2.4. Alternate form of induction principles on propositions
The induction principle on ev
was parametrized on n
. Alternately, it could have been parametrized on the evidence that n
was even.
forall P : (forall n : nat, ev'' n -> Prop), P O ev_0 -> (forall (m : nat) (E : ev'' m), P m E -> P (S (S m)) (ev_SS m E)) -> forall (n : nat) (E : ev'' n), P n E
This is more similar to the structural induction on proof trees (evisceration’sproof trees are called evidence in this book).
Why this is the case (that the induction principle is this way) is subtle - refer to the section starting at line 664.
This alternate form of induction on propositions is more flexible than the induction parametrized on n
, because it is parametrized both on n
and the evidence that n
is even.
2.5. Explicit proof objects for induction
It might be handy to use proof terms instead of tactic-based proofs. Induction principles, as types, can of course be written as programs (proof terms).
Here is an example.
Check nat_ind : forall P : nat -> Prop, P 0 -> (forall n : nat, P n -> P (S n)) -> forall n : nat, P n. Fixpoint build_proof (P : nat -> Prop) (evPO : P 0) (evPS : forall n : nat, P n -> P (S n)) (n : nat) : P n := match n with | 0 => evPO | S k => evPS k (build_proof P evPO evPS k) end.
This proof term inductively builds a proof tree.
It takes evidence that P 0
, evidence that if P(n') then P (S n')
.
It is helpful to focus on what evPS
does, as build_proof
recurses using it.
During the recursive case, evPS
takes a smaller n'
and a proof for P n'
and produces a proof for P (S n')
. That proof P n'
is provided by recursively calling build_proof
on n'
with the same evidences for P 0
and forall n'. P n' -> P (S n')
.
It’s a bit confusing, the book might explain it better.
There is an example provided where standard induction on n
fails to prove a proposition because it lacks information - instead, they do induction where n
decreases by 2 - this is where an explicit proof term allows you to define and use non-standard induction.
Definition nat_ind2 : forall (P : nat -> Prop), P 0 -> P 1 -> (forall n : nat, P n -> P (S(S n))) -> forall n : nat , P n := fun P => fun P0 => fun P1 => fun PSS => fix f (n:nat) := match n with 0 => P0 | 1 => P1 | S (S n') => PSS n' (f n') end.
This induction principle on n
says that if you have proof of P 0
and P 1
(you need P 1
as well, because we are inducting by twos) and P (S S n)
, then you have a proof of P n
, which is built via the proof term:
fun P => fun P0 => fun P1 => fun PSS => fix fun : => (n:nat) := match n with 0 => P0 | 1 => P1 | S (S n') => PSS n' (f n') end.
Using nat_ind2
in this proof:
Lemma even_ev : forall n, even n = true -> ev n. Proof. intros. induction n as [ | |n'] using nat_ind2. ...
gives us the goals at the point of induction:
3 goals (ID 108) H : even 0 = true ============================ ev 0 goal 2 (ID 109) is: ev 1 goal 3 (ID 113) is: ev (S (S n'))
It’s actually pretty clean.
Practice for this technique is given in the exercise t_tree
, where the standard induction principle doesn’t introduce induction hypotheses for the subtrees (Why?).
t_tree_ind : forall (X : Type) (P : t_tree X -> Prop), P t_leaf -> (forall p : t_tree X * X * t_tree X, P (t_branch p)) -> forall t : t_tree X, P t
3. Exercise
3.1. plus_one_r'
2 stars, standard
3.2. rgb
1 star, standard, optional
3.3. booltree_ind
2 stars, standard
3.4. toy_ind
2 stars, standard
3.5. tree
1 star, standard, optional
3.6. mytype
1 star, standard, optional
3.7. foo
1 star, standard, optional
3.8. foo'
1 star, standard, optional
3.9. plus_explicit_prop
1 star, standard, optional
3.10. TODO t_tree
4 stars, standard, optional
It’s a bit hard to do the induction type!
4. Scores
12/16
5. Questions
5.1. TODO Why does the induction principle for t_tree
not introduce induction hypotheses for the subtrees?
See line 990.
6. Metacognition
Some familiar stuff already, but in Coq’s terms. It helps to go through the exercises to understand some subtleties like the order of the quantification.
Some of the sections are hard to understand at first pass - what is important, I think, is to remember that other ways of induction are possible - we can go back to this section when we need to use more nuanced ways of induction.