CIS 194: Homework 6. Due Wednesday, 4 March. Fibonacci numbers. It s all about being lazy.

Similar documents
CIS 194: Homework 6. Due Monday, February 25. Fibonacci numbers

Lecture 6: Arithmetic and Threshold Circuits

CIS 194: Homework 4. Due Wednesday, February 18, What is a Number?

CS450 - Structure of Higher Level Languages

Lecture 1: Overview

Lecture 4: Higher Order Functions

Programming with Math and Logic

SCHEME 10 COMPUTER SCIENCE 61A. July 26, Warm Up: Conditional Expressions. 1. What does Scheme print? scm> (if (or #t (/ 1 0)) 1 (/ 1 0))

Streams. CS21b: Structure and Interpretation of Computer Programs Spring Term, 2004

#23: Sequences March 28, 2009

CIS 194: Homework 5. Due Friday, October 3, Rings. No template file is provided for this homework. Download the

ECE G205 Fundamentals of Computer Engineering Fall Exercises in Preparation to the Midterm

Programming Languages 3. Definition and Proof by Induction

Math 4242 Fibonacci, Memoization lecture 13

Problem Set 4: Streams and Lazy Evaluation

JVM ByteCode Interpreter

ASYMPTOTIC COMPLEXITY

CSCI-1200 Data Structures Spring 2018 Lecture 7 Order Notation & Basic Recursion

More Complicated Recursion CMPSC 122

CS 360: Programming Languages Lecture 12: More Haskell

Course year Typeclasses and their instances

Functional Programming in Haskell for A level teachers

CIS 194: Homework 6. Due Friday, October 17, Preface. Setup. Generics. No template file is provided for this homework.

Lecture 8: Summary of Haskell course + Type Level Programming

CIS 194: Homework 7. Due Wednesday, 25 March. Preliminaries. Finger exercises

HOMEWORK FILE SOLUTIONS

Excerpt from "Art of Problem Solving Volume 1: the Basics" 2014 AoPS Inc.

CIS 194: Homework 3. Due Wednesday, February 11, Interpreters. Meet SImPL

Functional Programming. Overview. Topics. Definition n-th Fibonacci Number. Graph

# track total function calls using a global variable global fibcallcounter fibcallcounter +=1

CS 360: Programming Languages Lecture 10: Introduction to Haskell

to calculate Fib(N) very quickly 1 Task 1: High-school algebra helps to design your program

/633 Introduction to Algorithms Lecturer: Michael Dinitz Topic: Priority Queues / Heaps Date: 9/27/17

Lecture 19: Signatures, Structures, and Type Abstraction

Streams and Evalutation Strategies

CSCI 270: Introduction to Algorithms and Theory of Computing Fall 2017 Prof: Leonard Adleman Scribe: Joseph Bebel

The University of Nottingham

BOBJ: A Quickstart for Software Engineers

Recursion Chapter 3.5

Chapter Fourteen Bonus Lessons: Algorithms and Efficiency

ASYMPTOTIC COMPLEXITY

CS 3410 Ch 7 Recursion

CS457/557 Functional Languages

APCS-AB: Java. Recursion in Java December 12, week14 1

(Refer Slide Time: 1:27)

n! = 1 * 2 * 3 * 4 * * (n-1) * n

Thoughts on Assignment 4 Haskell: Flow of Control

Midterm solutions. n f 3 (n) = 3

Haskell Overloading (1) LiU-FP2016: Lecture 8 Type Classes. Haskell Overloading (3) Haskell Overloading (2)

CS 4349 Lecture September 13th, 2017

Harvard School of Engineering and Applied Sciences CS 152: Programming Languages

Lecture 5: Lazy Evaluation and Infinite Data Structures

Hanoi, Counting and Sierpinski s triangle Infinite complexity in finite area

} Evaluate the following expressions: 1. int x = 5 / 2 + 2; 2. int x = / 2; 3. int x = 5 / ; 4. double x = 5 / 2.

CS 11 Haskell track: lecture 1

COMP Analysis of Algorithms & Data Structures

Macros & Streams Spring 2018 Discussion 9: April 11, Macros

(Refer Slide Time: 01.26)

1. Find f(1), f(2), f(3), and f(4) if f(n) is defined recursively by f(0) = 1 and for n = 0, 1, 2,

! Addition! Multiplication! Bigger Example - RSA cryptography

Introduction to Algorithms / Algorithms I Lecturer: Michael Dinitz Topic: Approximation algorithms Date: 11/18/14

Introduction to Functional Programming: Lecture 7 2 Functions as innite data structures Ordinary ML data structures are always nite. We can, however,

CISC 181 Lab 2 (100 pts) Due: March 4 at midnight (This is a two-week lab)

Writing Parallel Programs; Cost Model.

Sometimes it s good to be lazy

Induction and Recursion. CMPS/MATH 2170: Discrete Mathematics

COE428 Lecture Notes Week 1 (Week of January 9, 2017)

Functional Programming Languages (FPL)

Questions. 6. Suppose we were to define a hash code on strings s by:

Computer Programming. Basic Control Flow - Loops. Adapted from C++ for Everyone and Big C++ by Cay Horstmann, John Wiley & Sons

/633 Introduction to Algorithms Lecturer: Michael Dinitz Topic: Approximation algorithms Date: 11/27/18

SCHEME AND CALCULATOR 5b

INTRODUCTION TO HASKELL

Solutions to Homework 10

Background Type Classes (1B) Young Won Lim 6/28/18

Notes on Turing s Theorem and Computability

CIS 194: Homework 2. Due Monday January 28. Log file parsing. Something has gone terribly wrong! Files you will need: Log.hs, error.log, sample.

Design and Analysis of Algorithms Prof. Madhavan Mukund Chennai Mathematical Institute. Week 02 Module 06 Lecture - 14 Merge Sort: Analysis

p x i 1 i n x, y, z = 2 x 3 y 5 z

Dynamic Programming Algorithms

Hash Tables. CS 311 Data Structures and Algorithms Lecture Slides. Wednesday, April 22, Glenn G. Chappell

i W E I R D U T O P I A i

(Refer Slide Time: 00:26)

This session. Recursion. Planning the development. Software development. COM1022 Functional Programming and Reasoning

Statistics Case Study 2000 M. J. Clancy and M. C. Linn

Unit #2: Recursion, Induction, and Loop Invariants

Chapter 1. Math review. 1.1 Some sets

Stream Fusion. Wouter Swierstra 30/11/2010

Introduction. two of the most fundamental concepts in computer science are, given an array of values:

4.1 Review - the DPLL procedure

Getting Started with Haskell (10 points)

Logic - CM0845 Introduction to Haskell

Haskell 101. (Version 1 (July 18, 2012)) Juan Pedro Villa Isaza

n n Try tutorial on front page to get started! n spring13/ n Stack Overflow!

Statistical Computing

Algorithm Design and Recursion. Search and Sort Algorithms

1.1 calculator viewing window find roots in your calculator 1.2 functions find domain and range (from a graph) may need to review interval notation

Lecture #5: Higher-Order Functions. A Simple Recursion. Avoiding Recalculation. Redundant Calculation. Tail Recursion and Repetition

Introduction to Computer Science and Programming for Astronomers

Introduction. chapter Functions

Transcription:

CIS 194: Homework 6 Due Wednesday, 4 March It s all about being lazy. Fibonacci numbers The Fibonacci numbers F n are defined as the sequence of integers, beginning with 1 and 1, where every integer in the sequence is the sum of the previous two. That is, F 0 1 F 1 1 F n F n 1 + F n 2 (n 2) For example, the first fifteen Fibonacci numbers are 1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89, 144, 233, 377, 610,... It s quite likely that you ve heard of the Fibonacci numbers before. The reason they re so famous probably has something to do with the simplicity of their definition combined with the astounding variety of ways that they show up in various areas of mathematics as well as art and nature.

cis 194: homework 6 2 Exercise 1 Translate the above definition of Fibonacci numbers directly into a recursive function definition of type fib :: Integer -> Integer so that fib n computes the n th Fibonacci number F n. Now use fib to define the infinite list of all Fibonacci numbers, fibs1 :: [Integer] (Hint: You can write the list of all positive integers as [0..].) Try evaluating fibs1 at the ghci prompt. You will probably get bored watching it after the first 30 or so Fibonacci numbers, because fib is ridiculously slow. Although it is a good way to define the Fibonacci numbers, it is not a very good way to compute them in order to compute F n it essentially ends up adding 1 to itself F n times! For example, shown at right is the tree of recursive calls made by evaluating fib 5. As you can see, it does a lot of repeated work. In the end, fib has running time O(F n ), which (it turns out) is equivalent to O(ϕ n ), where ϕ 1+ 5 2 is the golden ratio. That s right, the running time is exponential in n. What s more, all this work is also repeated from each element of the list fibs1 to the next. Surely we can do better. fib 1 fib 0 fib 2 fib 1 fib 1 fib 0 fib 1 fib 3 fib 2 fib 2 fib 4 fib 5 Exercise 2 When I said we in the previous sentence I actually meant you. Your task for this exercise is to come up with more efficient implementation. Specifically, define the infinite list fib 0 fib 1 fib 3 fibs2 :: [Integer] so that it has the same elements as fibs1, but computing the first n elements of fibs2 requires only (roughly) n addition operations. Hint: You know that the list of Fibonacci numbers starts with 1 and 1, so fibs2 1 : 1 :... is a great start. The thing after the second (:) will have to mention fibs2, of course, because subsequent Fibonacci numbers are built using previous ones. Oh, and zipwith and tail will be helpful, too. (Why is tail here OK?)

cis 194: homework 6 3 Streams We can be more explicit about infinite lists by defining a type Stream representing lists that must be infinite. (The usual list type represents lists that may be infinite but may also have some finite length.) In particular, streams are like lists but with only a cons constructor whereas the list type has two constructors, [] (the empty list) and (:) (cons), there is no such thing as an empty stream. So a stream is simply defined as an element followed by a stream: data Stream a Cons a (Stream a) Exercise 3 Write a function to convert a Stream to an infinite list, streamtolist :: Stream a -> [a] Exercise 4 You may have noticed that the Show instance for Streams has already been defined for you 1. However, there are several other type classes that we may want instances of. Complete the Functor instance by defining the fmap function: 1 Implementing Show for polynomials was enough! fmap :: Functor f > (a -> b) -> f a -> f b Would it make sense to make a Monoid instance for Streams? Why or why not? You do not need to answer this question, but it is a good exercise to think about it. Exercise 5 Let s create some simple tools for working with Streams. a) Write a function srepeat :: a -> Stream a which generates a stream containing infinitely many copies of the given element. b) Write a function siterate :: (a -> a) -> a -> Stream a which generates a Stream from a seed of type a, which is the first element of the stream, and an unfolding rule of type a -> a which specifies how to transform the seed into a new seed, to be used for generating the rest of the stream. Example: siterate ( x :) "o" ["o", "xo", "xxo", "xxxo", "xxxxo",...

cis 194: homework 6 4 c) Write a function sinterleave :: Stream a -> Stream a -> Stream a which interleaves the elements from 2 Streams. You will want sinterleave to be lazy in its second parameter. This means that you should not deconstruct the second Stream in the function. Example: sinterleave (srepeat 0) (srepeat 1) [0, 1, 0, 1, 0, 1,... d) Write a function stake :: Int -> Stream a -> [a] which takes in an Int n and returns a list containing the first n elements in the Stream. Example: stake 3 (srepeat 0) [0, 0, 0] Exercise 6 Now that we have some tools for working with streams, let s create a few: a) Define the stream nats :: Stream Integer which contains the infinite list of natural numbers 0, 1, 2,... b) Define the stream Hint: Write out a sequence of numbers starting at 1 and try to find the pattern ruler :: Stream Integer that ruler follows. Use sinterleave to implement ruler in a clever way that which corresponds to the ruler function does not have to do any divisibility testing. Do you see why you had to make sinterleave lazy in its second 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, 4,... parameter? where the nth element in the stream (assuming the first element corresponds to n 1) is the largest power of 2 which evenly divides n.

cis 194: homework 6 5 Random numbers The next section will require a pseudo-random list of numbers. The exercises in this section will help you generate them. Computers are determinstic machines. That is, a computer will blindly follow the sequence of instructions given to it, and there is no way a computer does anything without a sequence of instructions. Yet, sometimes, we humans like spontaneity. We want our computers to produce random numbers except that determinism tells us this is impossible. Of course, there is no such thing as a random number. For example, is 194 random? No, it s the course number for this class! But, there can be such a thing as a random sequence of numbers, which is a sequence such that the next number can not be predicted by knowing what numbers have come before. Computers can only approximate generating random sequences. They do so by following a hard-to-predict, yet completely deterministic process. That s why we say computers produce pseudo-random sequences. (Pseudo- is a Greek prefix meaning fake ). 2 Further complicating matters from an implementation standpoint (but rather clarifying them from a theoretical one), Haskell s purity means that we cannot have a function rand :: Int that produces numbers from a random sequence. Instead, we need a notion of a random number generator. You will implement a random number generator as a Stream of random numbers. In C, if you do not initialize the random number generator, then it is defaulted to a linear congruential generator with hard coded parameters 3. Given an initial seed R 0, the formula for the generator is: R n (1103515245 R n 1 + 12345) mod 2147483648 (n 1) 2 In fact, it is not even proven that Pseudo-random generators exist! The existance of cryptographically secure Pseudo-random generators would imply that P NP! 3 This is not good enough for cryptographic applications such as generating RSA keys, but it is good enough for us! Exercise 7 Write a function rand :: Int -> Stream Int that produces a Stream of pseudo-random numbers using the formula above given an initial seed. Profiling It s wonderful to be lazy, but laziness occasionally gets in the way of productive work. Say I want to calculate both the maximum and minimum values of a list of Ints:

cis 194: homework 6 6 minmaxslow :: [Int] -> Maybe (Int, Int) minmaxslow [] Nothing -- no min or max if there are no elements minmaxslow xs Just (minimum xs, maximum xs) Exercise 8 Use minmaxslow to find the minimum and maximum of See the week 6 lecture notes for more details about profiling. a pseudo-random sequence of 1, 000, 000 Ints. The code to do this is provided for you in the main action. Now, compile your program, enabling RTS options (ghc HW06.hs -rtsopts -main-is HW06), 4 and run your program to see how much memory it takes. (./HW06 +RTS -s or HW06.exe +RTS -s on Windows) It should be a lot. Record the total memory in use figure in a comment in your source file. Then, run your program to see its heap profile, like this: >./HW06 +RTS -h -i0.001 > hp2ps -c HW06.hp (or, for Windows users running at the Windows command prompt cmd.exe: > HW06.exe +RTS -h -i0.001 > hp2ps -c HW06.hp This will create a HW06.ps file, which can be viewed by most modern PDF readers. Check it out! 4 GHC normally requires that your main action be in a module named Main. However, this would cause havoc with our autograde system, and so we re asking that your homework be in a module named HW06. To tell GHC to run the main function from the HW06 module not the Main module you say -main-is HW06. Exercise 9 As written, minmaxslow does not take advantage of Haskell s laziness, because it calculates the maximum of xs and the minimum of xs separately. The running program must remember all of xs between these calculations. But, with a rewrite, minmax can calculate both the minimum and maximum on the fly, and your program will never need to store the whole list. Implement this better version, run with +RTS -s, and include the improved memory footprint (the total memory in use is the one that matters!) in a comment. Fibonacci numbers via matrices (Optional Challenge Problem) It turns out that it is possible to compute the nth Fibonacci number with only O(log n) (arbitrary-precision) arithmetic operations. This section explains one way to do it. Consider the 2 2 matrix F defined by [ ] 1 1 F. 1 0

cis 194: homework 6 7 Notice what happens when we take successive powers of F (see http://en.wikipedia.org/wiki/matrix_multiplication if you forget how matrix multiplication works): [ ] [ ] [ ] [ F 2 1 1 1 1 1 1 + 1 1 1 1 + 1 0 1 0 1 0 1 1 + 0 1 1 1 + 0 0 [ ] [ ] [ ] F 3 2 1 1 1 3 2 1 1 1 0 2 1 [ ] [ ] [ ] F 4 3 2 1 1 5 3 2 1 1 0 3 2 [ ] [ ] [ ] F 5 5 3 1 1 8 5 3 2 1 0 5 3 2 1 1 1 ] Curious! At this point we might well conjecture that Fibonacci numbers are involved, namely, that [ ] F n F n+1 F n F n F n 1 for all n 1. Indeed, this is not hard to prove by induction on n. The point is that exponentiation can be implemented in logarithmic time using a binary exponentiation algorithm. The idea is that to compute x n, instead of iteratively doing n multiplications of x, we compute x n (x n/2 ) 2 n even x (x (n 1)/2 ) 2 n odd where x n/2 and x (n 1)/2 are recursively computed by the same method. Since we approximately divide n in half at every iteration, this method requires only O(log n) multiplications. The punchline is that Haskell s exponentiation operator (^) already uses this algorithm, so we don t even have to code it ourselves! Exercise 10 (Optional) Create a type Matrix which represents 2 2 matrices of Integers. Make an instance of the Num type class for Matrix. In fact, you only have to implement the (*) method, since that is the only one we will use. (If you want to play around with matrix operations a bit more, you can implement frominteger, negate, and (+) as well.) We now get fast (logarithmic time) matrix exponentiation for free, since (^) is implemented using a binary exponentiation algorithm in terms of (*). Write a function Don t worry about the warnings telling you that you have not implemented the other methods. (If you want to disable the warnings you can add {-# OPTIONS_GHC -fno-warn-missing-methods #-} to the top of your file.)

cis 194: homework 6 8 fastfib :: Integer -> Integer which computes the nth Fibonacci number by raising F to the nth power and projecting out F n (you will also need a special case for zero). Try computing the one millionth or even ten millionth Fibonacci number. On my computer the millionth Fibonacci number takes only 0.32 seconds to compute but more than four seconds to print on the screen after all, it has just over two hundred thousand digits.