Chapter 11 Proof by Induction Induction and Recursion
Chapter 11 Proof by Induction
Induction and Recursion Two sides of the same coin. w Induction usually starts with small things, and then generalizes to the large. n E. g. inductive definition of a list: [] is a list; and if xs is a list, then so is x : xs. w Recursion usually starts with the large thing, working its way back to the small. n E. g. recursion over lists: Start with non-empty list x : xs; do something with x, then recurse on xs. w It is not surprising then, that proof by induction is closely tied to recursion: it is usually needed when proving properties about recursive functions.
Proof by Induction on Lists To prove property P by induction on the length of a list: 1. Prove P([]) -- the base case. 2. Assume P(xs) is true –- the induction hypothesis and prove that P(x: xs) is true -– the induction step
Example 1: A Property About foldr Recall this property about foldr: foldr (: ) [] xs = xs A proof by induction: Base case: xs = [] foldr (: ) [] [] (immediate from the definition of foldr) Induction step: assume foldr (: ) [] xs = xs foldr (: ) [] (x: xs) x : foldr (: ) [] xs -- unfoldr x : xs -- by the induction hypothesis
Example 2: A Property About length w Prove that: length (xs++ys) = length xs + length ys w Question: Over which list (xs or ys) should we perform the induction? w Hint: look at the definitions of length and (++), which recurse over the front of their arguments – thus we should use xs above.
Example 2, cont’d Base case: xs = [] length ([] ++ ys) length ys 0 + length ys length [] + length ys Induction step: assume length (xs++ys) = length xs + length ys length ((x: xs) ++ ys) length (x : (xs ++ ys)) 1 + length (xs ++ ys) 1 + (length xs + length ys) (1 + length xs) + length ys length (x: xs) + length ys
Proving Function Equivalence w Remember the mantra: “get it right first”. w Later, we can improve our programs for efficiency reasons. w But how do we know that the new program is the same as the old? w Answer: by proving them so. w And in the case of recursive functions, we will need induction.
Example 3: Equivalence of reverse Def’ns Recall these three definitions of reverse: reverse 1 [] = [] reverse 1 (x: xs) = reverse 1 xs ++ [x] reverse 2 xs = rev [] xs where rev acc [] = acc rev acc (x: xs) = rev (x: acc) xs reverse 3 = foldl (flip (: )) [] reverse 1 is the obvious, but inefficient version. reverse 2 is the recursive, efficient version. reverse 3 is the non-recursive, efficient version.
Example 3, cont’d Let’s prove that reverse 1 = reverse 3. w Base case: xs = [] reverse 1 [] -- unfold reverse 1 foldl (flip (: )) [] [] -- foldl reverse 3 [] -- fold reverse 3 w Induction step: assume reverse 1 xs = reverse 3 xs reverse 1 (x: xs) reverse 1 xs ++ [x] -- unfold reverse 1 reverse 3 xs ++ [x] -- induction hypothesis foldl (flip (: )) [] xs ++ [x] -- unfold reverse 3 foldl (flip (: )) [] (x: xs) -- LEMMA!!! reverse 3 (x: xs) -- fold reverse 3 w The lemma states: foldl (flip (: )) [] xs ++ [x] = foldl (flip (: )) [] (x: xs) How do we prove this?
Generalizing Lemmas w The lemma: foldl (flip (: )) [] xs ++ [x] = foldl (flip (: )) [] (x: xs) is actually hard to prove directly. w It ‘s easier to prove this generalization: foldl (flip (: )) ys xs ++ [y] = foldl (flip (: )) (ys++[y]) xs from which the first lemma is easy to prove. w Knowing when to introduce a lemma, and when to generalize it, it is a skill in proving theorems in any context. (See text for proofs of lemmas. )
Laws of Lists w There are many useful properties of functions such as (++), map, foldl, and foldr on lists. w These properties can be used as “lemmas” in proving other properties of larger programs that use these functions. w Some of them depend on function “strictness”: A function f is strict if f _|_ = _|_.
Laws of Map map (x->x) = x->x map (f. g) = map f. map g map f. tail = tail. map f. reverse = reverse. map f. concat = concat. map (map f) map f (xs ++ ys) = map f xs ++ map f ys For all strict f: f. head = head. map f
Laws of fold If op is associative, e `op` x = x, and x `op` e = x, then for all finite xs: foldr op e xs = foldl op e xs If the following are true: x `op 1` (y `op 2` z) = (x `op 1` y) `op 2` z x `op 1` e = e `op 2` x then for all finite xs: foldr op 1 e xs = foldl op 2 e xs For all finite xs: foldr op e xs = foldl (flip op) e (reverse xs)
Induction on Other Data Types w Proof by induction is not limited to lists. Indeed, it is usually taught on natural numbers first. w Example: Exponentiation, defined by: (^) : : Integer -> Integer x^0 = 1 x^n = x * x^(n-1) w Suppose we wish to prove that, for all natural numbers m and n: x^(n+m) = x^n * x^m
Example 4: A Property About Exponentiation As before, we proceed by induction. w Base case: n = 0 x^(0+m) x^m 1 * (x^m) x^0 * x^m w Induction step: assume x^(n+m) = x^n * x^m x^((n+1)+m) x * x^(n+m) x * (x^n * x^m) (x * x^n) * x^m x^(n+1) * x^m
Induction Over User-Defined Data Types w Recall the tree data type: data Tree a = Leaf a | Branch (Tree a) w And define these functions on it: flatten : : Tree a -> [a] flatten (Leaf x) = [x] flatten (Branch t 1 t 2) = flatten t 1 ++ flatten t 2 sum. Tree : : Tree Int -> Int sum. Tree (Leaf x) =x sum. Tree (Branch t 1 t 2) = sum. Tree t 1 + sum. Tree t 2 w Further, assume that: sum = foldl (+) 0 w Lemma: sum (xs++ys) = sum xs + sum ys
Example 5: A Property About Trees Theorem: sum. flatten = sum. Tree Proof by induction: w Base case: t = Leaf x sum (flatten (Leaf x)) sum [x] -- unfold flatten foldl (+) 0 (x: []) -- syntax, and unfold sum x + (foldl (+) 0 []) -- unfoldl x+0 -- unfoldl x -- arithmetic sum. Tree (Leaf x)-- fold sum. Tree
Example 5, cont’d w Induction step: assume that n sum (flatten t 1) = sum. Tree t 1 n sum (flatten t 2) = sum. Tree t 2 sum (flatten (Branch t 1 t 2)) sum (flatten t 1 ++ flatten t 2) sum (flatten t 1) + sum (flatten t 2) sum. Tree t 1 + sum. Tree t 2 sum. Tree (Branch t 1 t 2) -- unfold flatten -- lemma -- induction hyp. -- fold sum. Tree
- Slides: 18