CS 110 Fall 2010 

Lab 10: Recursion and Performance

Due: Wednesday, November 17th by class time

 

Today, we'll practice recursive problem solving and compare to iterative solutions.  Then we’ll start thinking about our final projects. 

Part 1 - Timing of Recursive versus Iterative Solutions

You may, if you wish, work in the "pairs programming" style for Part 1 of this assignment. If you do, then make sure that both of you get approximately equal time in the driving versus over-the-shoulder coaching type roles.

The goal of this part is to write functions for solving each of the following problems and then to test these functions on problems of increasing size. In order to test the functions, we need to have functions for getting the time just before the test and then getting the time just after the test. We can then subtract and see how long the test takes.

We first need a way to create a list of random numbers, where the size of the list is given by one of the parameters.  We can use an external library/module called random and use the following:

import random

def genlist(numelements, maxvalue):
    alist = []
    while numelements > 0:
        val = random.randint(0, maxvalue)
        alist.append(val)
        numelements -= 1
    return alist

We can also use an external module called time to retrieve the current time.  When we invoke the time() function in this module, we are given a float value whose units are the number of seconds elapsed since some reference point in the past.  So if we call this function both before and after we perform some computation, we can take the difference of the 'after' time from the 'before' time to get the number of seconds the computation took.  Since computers execute at very fast speeds, these numbers will be very small, and well well be displayed in scientific notation, but their values are significant.

Suppose, for example, that I have a function called empty(n) that simply executes a for loop with a useless assignment statement in its body for n iterations:

def empty(n):
    for i in range(n):
        x = 10 * i

I could then use the following code to determine and print the time it takes to execute empty for different values of n:

def main():
    start1 = time.time()
    empty(10000)
    end1 = time.time()
    delta1 = end1 - start1
    print ('Execution of empty(10000) took', delta1, 'sec.')

    start2 = time.time()
    empty(100000)
    end2 = time.time()
    delta2 = end2 - start2
    print ('Execution of empty(100000) took', delta2, 'sec.')

main()

This lab will investigate the following four algorithmic objectives and the performance of different algorithms to obtain the same result as we change the "size" of the problem.  Part of the deliverables will be comparison graphs in which the size of the problem is plotted on the x-axis and the execution time is plotted on the y-axis for different algorithms used to compute the same objective result. You will need one or more additional functions that allow you to retrieve requested input sizes and user selectable function to execute in order to carry out the necessary experimentation. (Think of these as generalization to the functionality I am carrying out in the example main() given above.) Be sure and include good documentation of all of your functions.

A. Find the minimum value in a list.

Given randomly generated lists of integers, the goal is to to find the minimum value in the given list.  We will define three different functions to find the min:

def min1(alist):  This function should use a loop to find the smallest element in the list.  The function returns the found minimum value from the list.

def min2(alist):  This function should use recursion and list slicing to find the smallest element in the list.  The function returns the found minimum value from the list.

def min3(alist, start):  This function should use recursion to find the smallest element in the list. However, recursive calls should always pass the original list, and the start parameter should be used to determine the starting position in the sublist being considered by the recursive call. The function returns the found minimum value from the list.

For this objective, the "size" of the problem is really the length of the list.  Additional questions to answer (in Analysis.rtf):

  1. How large a problem can min2() solve?
  2. How large a problem can min3() solve?
  3. Can we determine a limit on the size problem solved by min1()?
  4. Why do you suppose the answers to questions 1 to 3 are what they are?
  5. Compare the performance (execution time) of min1() versus min2() in a graph as the size of the problem grows.  Explain any differences you see.
  6. Compare the performance (execution time) of min2() versus min3() in a graph as the size of the problem grows.  Explain any differences you see.

B. Search for a specific value in a list.

Given randomly generated lists of integers, the goal is to to find a specific given value in the given list.  Analagous to min(), we will define three different functions to find a value:

def find1(alist, key): This function should use a loop to attempt to find key in alist.  The function should return the index of the list where key is found, or return -1 if key is not found in the list.

def find2(alist, key): This function should use recursion and list slicing to search for key in alist.  The function returns key if key is found and returns None if key is not found.

def find3(alist, key, start): This function should use recursion to find key in alist, and as above, recursive calls should pass the original list, and only change the start position defining the sublist under consideration by the recursive call.  The function should return the index in the original alist where key is found, or return -1 if key is not found in the list.

Again for this objective, the "size" of the problem is the length of the list.  Before you start the experimentation phase, hypothesize whether any of the answers to questions 1-6 from above will change for this objective.  Then experiment and answer the same questions.

C. Compute the factorial function.

Given an input integer, n, compute n factorial, returning the computed value.  We will define two versions of this function:

def fact1(n): This function should use a loop to compute n!, returning the computed value.

def fact2(n): This function should use recursion to compute n!, returning the computed value.

Answer the following questions through experimentation:

  1. How large a problem can the recursive versus iterative algorithms for factorial support?
  2. Compare the performance of fact1() and fact2() as we increase n.
  3. Explain any differences in performance seen.

D. Compute the Fibonacci function.

Given an input integer, n, compute Fibonacci(n), returning the computed value.  We will define two versions of this function:

def fib1(n): This function should use a loop to compute Fib(n), returning the computed value.

def fib2(n): This function should use recursion to compute Fib(n), returning the computed value.

Answer the following questions through experimentation:

  1. How large a problem can the recursive versus iterative algorithms for Fibonacci support?  ... be careful here, as the results may be different than what you have seen before.
  2. Compare the performance of fib1() and fib2().
  3. Explain both the differences between the two ways of computing Fibonacci as well as any differences between your answers here and the answers in previous problems.

Part 2 - Final Project Proposal

The final project for this course is a program of your own design.  This project should demonstrate a wide range of programming constructs and concepts from the course, including good commenting and design (through structure and appropriate function definitions).  In addition to these features, your project will be graded for its complexity.  However, be sure to build your programs incrementally, since a program must work to receive a good grade.  The creativity and artistry of your final product will also be evaluated in the determination of your final grade.

 

Please submit a detailed proposal for your final project.  This should be at least a few paragraphs.  You may want to use some high level pseudocode for how your main method will work, and specify other methods you intend to create and what they do.  This proposal should be saved in a file called Proposal.rtf. 

 

Projects may be worked on individually or in groups of two.  Proposals for pairs must be substantially more ambitious than individual projects, and should clearly specify how the workload will be divided among both students. 

 

Make sure you include your name(s) on the project proposal, and give your project a name. 

 

Possible projects:

 

Composite Photo Generator

 

  This program would take a base image and create a new image that is composed of many smaller images, arranged so as to give the appearance of the original base image.  One good example of this is at the end of the other hall in Olin, the Mona-Lisa generated from dice.  You may have seen other images that are similar to this: a picture of earth created with hundreds of small pictures of animals, a picture of Einstein created with numerous small black and white photos of scientists, etc.  Here, you would make a program that would take in a base photo and a set of smaller images, and use those to create a composite representation of the base photo using the smaller images as building blocks. 

 

Animation

 

  As some of you have discovered, you can make a simple animation by repeatedly displaying many Image/GraphWin objects (or with a single such object that gets modified between displays).  Use techniques from class to create a detailed image as in the first project, with animation.  For example, you might create a cityscape, in which the sun moves through an arc in the sky, the sky brightens and then darkens as the sun rises and sets, lights turn on in windows at various times in the evening, and clouds sail across the sky, billowing, expanding, and contracting smoothly.  Alternatively you might animate a plant that grows organically and eventually flowers.  Or an elaborate dog-fight between monkey pirates in space ships. 

 

Games

 

  A number of games where players take turns and are not timed can be created using the tools and techniques we have been working with.  For example, you might create a battleship game.  Or Connect-Four.  Or Mastermind.  Or a game you made up.  For any of these games, you should display the board graphically after each move. 

 

  You can also make games that are not turn based.  If you choose to do so, you’ll need to use the system clock (not too hard, I can help with that).

 

  Regardless, any game you create should use methods that recognize keyboard or mouse input.  The documentation should help you here, and I can also give you pointers on this if you’re stuck.

 

Kaleidoscope

 

  A kaleidoscope program would take one or more images, and automatically use them to create a geometric collage of the sort often seen when looking through a kaleidoscope.  That is, random fragments of each image would be thrown together in a highly symmetric way to form a composite image which would be itself highly symmetric, and yet be composed of many small components, each of which would come from one of the original images.

 

Paint Program

 

  Create a program that allows the user to draw on a canvas with the mouse.  You might want to allow the user to select colors from a palette, draw lines and shapes, fill regions with color, and apply filters like the ones you’ve created already.  As with games, if you choose to do this you should use methods from the Picture class to recognize mouse input so that the user can, for example, simply click on a color, and drag a circle on the screen.   

 

Others

 

  You are welcome to also propose other ideas; fractal generators, a more complex biological simulator, physical simulations, or anything else you can think of.  However, the complexity and depth of your project must be comparable those described above. 

 

Note: While we haven’t done so in class, it is not difficult to have the computer choose random values in a given range.  This gives you additional flexibility in terms of what your programs can do, so feel free to include randomness in your proposals.   

 

 

 

Part 3 - Uploading your lab

Lab10 should contain:

  • Analysis.rtf
  • Performance.py
  • Proposal.rtf