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!