Today's topic: structural induction
------------------------------------------------------------------------
Review of induction on natural numbers:

Recall the inductive definition of natural numbers:

  * 0 is a Nat
  * if n is a Nat, then so is n+1
  * (nothing else is a Nat)

Our principle of (weak) induction for natural numbers was
as follows:  If we want to prove all naturals satisfy
some property P, then we're trying to show:  Forall i in Nat.P(i)
is true.  We can prove this by showing two things:

  1. P(0) is true.
  2. P(n) => P(n+1).  

The second condition requires us to show that, assuming
P holds for some natural number n, then it holds for
the successor of n (i.e., n+1).  So, the form of a proof
is always as follows:

  Theorem:  For all n in Nat, P(n) is true.

  Proof:  by induction on n.  
  Base case:  (proof that P(0) is true)
  Inductive case:  Assume P(n) is true.  We show
                   that P(n+1) is true.
  Therefore, for all n in Nat, P(n) is true.

Why does this work?  Well, let's suppose we have a proof
like the one above.  Let's try to show that there is some
natural number i such that P(i) does _not_ hold.  That is,
we'll argue by contradiction:

  Suppose P does not hold for some (non-empty) subset of the natural
  numbers.  Then, there is a least number i such that
  P does not hold.  By the definition of natural numbers, 
  i must be either 0 or the successor of some natural number.  
  But i cannot be 0 because we proved (in the base case) 
  that P(0) is true.  Hence, i = j+1 for some j.  Now,
  since i is the least natural number that does not
  satisfy P, j must satisfy P.  That is, P(j) is true.
  But then the inductive case allows us to conclude that
  P(j+1) is true.  That is, P(i) is true.  This is a 
  contradiction.  Hence, our assumption that P does not
  hold for some (non-empty) subset of the naturals must
  be false.  

Consequently, P must hold for all natural numbers.  
----------------------------------------------------------
Induction on Lists:

Induction is a principle that applies not only to natural
numbers, but to any set that is defined in an inductive
fashion.  For example, (proper) lists of integers are defined
inductively by:

  *  '() (null) is a proper list of integers
  *  if i is an integer, and x is a proper list of integers,
        then (cons i x) is a proper list of integers.
  *  (nothing else is a proper list of integers)

Our principle of (weak) induction for proper lists of
integers follows the same pattern as for naturals:  To
show property P holds for all proper lists of integers,
we need only show:

  1. P('()) is true.
  2. P(x) => P(cons i x).

The second condition requires us to show that, assuming
P holds for a proper list of integers x, then P holds
for all proper lists of integers of the form (cons i x).

For example, we can prove that the length function (defined
below) always calculates a natural number from a proper
list of integers:

  (define (length <function>)
    (method ((x <list>))
      (if (null? x) 0 (+ 1 (length (tail x))))))

Theorem:  For all proper lists of integers, (length x) returns
a natural number.

Proof:  Let P(x) be the property that (length x) returns a
natural number.  We will show that P(x) is true for all 
x that are proper lists of integers, via structural induction
on x.

Base case: show P('()).  
   (length '()) -> [(method (x) (if (null? x) 0 (+ 1 (length (tail x))))) '()]
                -> (if (null? '()) 0 (+ 1 length (tail '())))
                -> (if #t 0 (+ 1 length (tail '())))
                -> 0
   0 is a natural number by definition.  Therefore, P('()) holds.

Inductive case:  show P(x) => P(cons i x).
  Induction Hypothesis (IH): Assume P(x).  That is, assume (length x) 
  evaluates to a natural number n.

  We will show P(cons i x).  That is, we will show that (length (cons i x))
  evaluates to a natural number using the substitution model.

  (length (cons i x)) 
        -> [(method (x) (if (null? x) 0 (+ 1 (length (tail x))))) (cons i x)]
        -> (if (null? (cons i x)) 0 (+ 1 (length (tail (cons i x)))))) 
        -> (if #f 0 (+ 1 (length (tail (cons i x)))))) 
        -> (+ 1 (length (tail (cons i x)))))) 
        -> (+ 1 (length x))
        -> (+ 1 n)              (by the induction hypothesis)
        -> n+1

   Because n is a natural number, n+1 is a natural number from the
   definition of natural numbers.  Therefore, P(cons i x) holds.

Since P('()) holds and P(x) => P(cons i x), P holds for all proper
lists of integers.

Notice that I explicitly stated the induction hypothesis and where 
I used it to justify the proof that P(cons i x) holds.  

Again, why does the induction scheme work for lists?  Let's assume we
have an arbitary property P, and we've shown that P('()) holds and
P(x) => P(cons i x).  From the definition of what it is to be a proper
list, x must be of the form 
   (cons i1 (cons i2 (cons i3 ... (cons in '())))) for some n >= 0.  

We can prove by natural number induction on n that P(x) holds.  
(You do the proof!)

In essence, we can prove by natural number induction on the 
length of a list that a given property holds for all lists.

As an exercise, try to prove the following property holds for
all proper lists of integers:

  (length (append x1 x2)) = (+ (length x1) (length x2))

where:

  (define (append <function>)
     (method ((x1 <list>) (x2 <list>))
        (if (null? x1) x2 (cons (head x1) (append (tail x1) x2)))))

Your proof should look like this:

Theorem:  For all lists x1 and x2, (length (append x1 x2)) = 
(+ (length x1) (length x2)).

Proof:  by structural induction on x1. 
Base case:  <show (length (append '() x2)) = (+ (length '()) (length x2))>
Inductive case:  <assume (length (append x x2)) = (+ (length x) (length x2).
Show (length (append (cons i x) x2)) = (+ (length (cons i x)) (length x2)).>
----------------------------------------------------------------------
Induction on Trees:

We can also prove properties about other kinds of arbitrarily
sized data structures.  For instance, here is the definition
of a binary tree of integers where the integers are all at the
"leaves" of the tree:

   * if i is an integer, then i is a binary tree of integers
   * if l and r are binary trees of integers, then (pair l r)
        is a binary tree of integers
   * (nothing else is a binary tree of integers)

How would we prove that a property P holds for all binary
trees of integers?  

   1. show P(i) for an integer i.
   2. show P(l) & P(r) => P(pair l r)

The second condition requires that we assume the property
holds for some trees l and r, and under this assumption
prove the property holds for the tree (pair l r).  
----------------------------------------------------------------------
Turning structural induction into natural number induction:

Another way to think about structural induction is to define
a function f mapping your data structure (say lists or trees)
to natural numbers.  For instance, for lists, we might use
length for f and for trees, we might use the "height of the
tree":

   (define (height <function>)
     (method ((t <object>))
       (if (null? t) 0 (max (height (head t)) (height (tail t))))))

In some sense, it doesn't matter what f is as long as
f maps every list/tree to a natural number.

Then we can prove that the P holds for data structures x
such that f(x) = 0, and show that, whenever P holds for
data structures such that f(x) = n, then P holds for
data structures x' such that f(x) = n+1. 

Then we can argue by induction on the natural numbers
that for each n, P holds for data structures x such that
f(x)=n.  Since every data structure maps to some n, we've
just shown that every data structure has the property
we're looking for.
----------------------------------------------------------------------
Weak vs. Strong induction:

The formula for weak induction on natural numbers is:

  1. show P(0)
  2. assume P(n) and show P(n+1).

Sometimes, we need to assume more than just P(n) in order
to show P(n+1).  In particular, sometimes we need to assume
that P holds for all numbers less than or equal to n.

This is known as strong induction on natural numbers:

  1. show P(0)
  2. assume P(i) holds for all i <= n.  Show P(n+1).

Why is strong induction valid?  Intuitively, it's because
once you show P(0), then you can use that to show P(1).
To show P(2), you can use P(0) as well as P(1) because
because you've already shown both.  Similarly, to show
P(3), you can use P(0), P(1), and P(2) because you've
shown that all of these are true.  

Now let's try to make this formal:

Suppose P(0) holds, and whenever P(i) holds for all i <= n,
P(n+1) holds.  Now suppose S is a non-empty set of natural 
numbers such that for each element j of S, P(j) is false.
We will derive a contradiction showing that S must be empty
and hence P holds for all natural numbers.

Since S is non-empty, pick the smallest number in S and
call it j.  Since j is the smallest number such that P
does not hold and since j cannot be 0 (remember, we've
shown P(0)), P holds for all numbers from 0 though j-1.
But we've also shown that when P(0) & P(1) & ... & P(j-1)
holds, then P(j) holds.  Hence, we have a contradiction.
Therefore, S must be the empty set.  Thus, P holds for
all natural numbers.

We'll show you examples later on where you need to use
strong natural number induction instead of weak natural
number induction.  We'll also show you situations where
what seems to be a proof by induction is in fact not!