Presentation on theme: "Chapter 11 Proof by Induction. Induction and Recursion Two sides of the same coin. Induction usually starts with small things, and then generalizes."— Presentation transcript:
Induction and Recursion Two sides of the same coin. Induction usually starts with small things, and then generalizes to the large. E.g. inductive definition of a list:  is a list; and if xs is a list, then so is x : xs. Recursion usually starts with the large thing, working its way back to the small. E.g. recursion over lists: Start with non-empty list x : xs; do something with x, then recurse on xs. 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-- unfold foldr x : xs-- by the induction hypothesis
Example 2: A Property About length Prove that: length (xs++ys) = length xs + length ys Question: Over which list (xs or ys) should we perform the induction? Hint: look at the definitions of length and (++), which recurse over the front of their arguments – thus we should use xs above.
Proving Function Equivalence Remember the mantra: “get it right first”. Later, we can improve our programs for efficiency reasons. But how do we know that the new program is the same as the old? Answer: by proving them so. And in the case of recursive functions, we will need induction.
Example 3: Equivalence of reverse Def’ns Recall these three definitions of reverse: reverse1  =  reverse1 (x:xs) = reverse1 xs ++ [x] reverse2 xs = rev  xs where rev acc  = acc rev acc (x:xs) = rev (x:acc) xs reverse3 = foldl (flip (:))  reverse1 is the obvious, but inefficient version. reverse2 is the recursive, efficient version. reverse3 is the non-recursive, efficient version.
Generalizing Lemmas The lemma: foldl (flip (:))  xs ++ [x] = foldl (flip (:))  (x:xs) is actually hard to prove directly. 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. 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 There are many useful properties of functions such as (++), map, foldl, and foldr on lists. These properties can be used as “lemmas” in proving other properties of larger programs that use these functions. 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 map f. reverse = reverse. map f 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 `op1` (y `op2` z) = (x `op1` y) `op2` z x `op1` e = e `op2` x then for all finite xs: foldr op1 e xs = foldl op2 e xs For all finite xs: foldr op e xs = foldl (flip op) e (reverse xs)
Induction on Other Data Types Proof by induction is not limited to lists. Indeed, it is usually taught on natural numbers first. Example: Exponentiation, defined by: (^) :: Integer -> Integer -> Integer x^0 = 1 x^n = x * x^(n-1) 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. Base case: n = 0 x^(0+m) x^m 1 * (x^m) x^0 * x^m 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 Recall the tree data type: data Tree a = Leaf a | Branch (Tree a) (Tree a) And define these functions on it: flatten :: Tree a -> [a] flatten (Leaf x) = [x] flatten (Branch t1 t2) = flatten t1 ++ flatten t2 sumTree :: Tree Int -> Int sumTree (Leaf x) = x sumTree (Branch t1 t2) = sumTree t1 + sumTree t2 Further, assume that: sum = foldl (+) 0 Lemma: sum (xs++ys) = sum xs + sum ys
Example 5: A Property About Trees Theorem: sum. flatten = sumTree Proof by induction: Base case: t = Leaf x sum (flatten (Leaf x)) sum [x]-- unfold flatten foldl (+) 0 (x:)-- syntax, and unfold sum x + (foldl (+) 0 )-- unfold foldl x + 0-- unfold foldl x-- arithmetic sumTree (Leaf x)-- fold sumTree
Example 5, cont’d Induction step: assume that sum (flatten t1) = sumTree t1 sum (flatten t2) = sumTree t2 sum (flatten (Branch t1 t2)) sum (flatten t1 ++ flatten t2)-- unfold flatten sum (flatten t1) + sum (flatten t2)-- lemma sumTree t1 + sumTree t2-- induction hyp. sumTree (Branch t1 t2)-- fold sumTree