# Laboratory: Analyzing Procedures

*Summary:* In this laboratory, you will explore the running time for a few algorithm variants.

## Preparation

a. Make a copy of `analysis-lab.rkt`

, which contains most of the procedures you will need for this lab.

b. Review the file to see what procedures are included. You may find it easiest to look at the list provided by the (define …) menu.

## Exercises

### Exercise 1: Analyzing Reverse

a. Add counters for `list-append`

, `list-reverse-1`

, `list-reverse-2`

and any other things you think will be useful to count as we analyze the various versions of `list-reverse`

. For example,

```
(define list-append-counter (counter-new "list-append"))
```

b. Annotate each of those procedures so that it increments the appropriate counter. For example,

```
(define list-append
(lambda (front back)
(counter-count! list-append-counter)
...))
```

c. Find out how many times `list-append`

is called in reversing a list of seven elements by entering the following commands in the interactions pane.

```
> (counter-reset! list-append-counter)
> (list-reverse-1 (iota 7))
> (counter-print! list-append-counter)
```

d. Did you get the same answer as in self-check 3(c)? If not, why do you think you got a different result?

e. Find out how many times `kernel`

is called in reversing a list of seven elements.

f. Did you get the same answer as in self-check 3(e)? If not, what difference do you see?

### Exercise 2: Additional Calls

What if we care about calls to `car`

, `cdr`

, and such? We’ll need to create our own versions of those procedures, along with counters. As a start, we might write:

```
(define car-counter (counter-new "car"))
(define cdr-counter (counter-new "cdr"))
(define cons-counter (counter-new "cons"))
(define null?-counter (counter-new "null?"))
(define list-counters (list car-counter cdr-counter cons-counter null?-counter))
(define $car
(lambda (lst)
(counter-count! car-counter)
(car lst)))
(define $cdr
(lambda (lst)
(counter-count! cdr-counter)
(cdr lst)))
(define $cons
(lambda (val lst)
(counter-count! cons-counter)
(cons val lst)))
(define $null?
(lambda (val)
(counter-count! null?-counter)
(null? val)))
```

We then have to update all of our calls to `car`

to use `$car`

instead. For example, here’s an updated definition of `list-reverse-1`

.

```
(define list-reverse-1
(lambda (lst)
(if ($null? lst)
null
(list-append (list-reverse-1 ($cdr lst)) (list ($car lst))))))
```

You will need to make similar changes to the definition of `list-append`

.

Unfortunately, we can’t quite do that for `list`

, because `list`

takes a variable number of parameters. So, we might rewrite the procedure to more explicitly use `cons`

.

```
(define list-reverse-1
(lambda (lst)
(if ($null? lst)
null
(list-append (list-reverse-1 ($cdr lst))
($cons ($car lst) null)))))
```

a. Find out how many total procedure calls are done in reversing a list of length seven, using `list-reverse-1`

, with the following.

```
> (for-each counter-reset! list-counters)
> (list-reverse-1 (iota 7))
> (for-each counter-print! list-counters)
```

b. How does the total number of calls seem to relate to the number of calls to `list-append`

?

c. Update `list-reverse-2`

and find out how many total procedure calls (including calls to `kernel`

) when we use that procedure to reverse a list of length seven.

d. How does that number of calls seem to relate to the number of calls to `kernel`

?

### Exercise 3: Predicting Calls

a. Fill in the following chart to the best of your ability.

List Length | rev1: Calls to `list-append` |
rev1: Total function calls | rev2: Calls to `kernel` |
rev2: Total function calls |
---|---|---|---|---|

2 | ||||

4 | ||||

8 | ||||

16 |

```
; rev-1 rev-1 rev-2 rev-2
; length l-a total kernel total
; 2
; 4
; 8
; 16
```

b. Predict what the entries will be for a list size of 32.

c. Check your results experimentally.

d. Write a formula for the columns, to the best of your ability.

### Exercise 4: The Brightest Color, Revisited

Here is a third version of `irgb-brightest`

, which should already be in your definitions.

```
(define irgb-brightest-3
(lambda (colors)
(let kernel ([brightest-so-far (car colors)]
[remaining-colors (cdr colors)])
(if (null? remaining-colors)
brightest-so-far
(kernel (irgb-brighter brightest-so-far (car remaining-colors))
(cdr remaining-colors))))))
```

a. Find out how many steps this procedure takes on lists of length 2, 4, 8, and 16 in which the elements are arranged from lightest to darkest.

b. Find out how many steps this procedure takes on lists of length 2, 4, 8, and 16 in which the elements are arranged from darkest to lightest. (You can reverse the lists from the previous step to create these lists.)

c. Find out how many steps this procedure takes on lists of length 2, 4, 8, and 16 in which the elements are in no particular order.

d. Predict the number of steps this procedure will take on each kind of list, where the length is 32.

## For Those with Extra Time

### Extra 1: The Effects of Preconditions

Consider `irgb-brightest-4`

, a variant of an efficient version of `irgb-brightest`

that has additional error checking added.

```
(define irgb-brightest-4
(lambda (colors)
(when (not (all-irgb? colors))
(error "irgb-brightest: expects a list irgb of colors; received" colors))
(if (null? (cdr colors))
(car colors)
(irgb-brighter (car colors)
(irgb-brightest-4 (cdr colors))))))
```

a. Predict the number of calls to `irgb-brightest-4`

in finding the brightest in a list of eight colors.

b. Check your hypothesis.

c. Predict the number of calls to `all-irgb?`

in finding the brightest in a list of eight colors.

d. Check your hypothesis.

### Extra 2: Precondition Checking, Revisited

Rewrite `irgb-brightest-4`

so that it continues to check preconditions, but precondition checking does not exact such a heavy penalty.