Cs1321 Fall, AY2002 11/01/01 (that’s 35 16 ) Lecture 20

Preview:

Citation preview

cs1321cs1321Fall, AY2002

11/01/01 (that’s 3516)

Lecture 20

Agenda

1. Tail Recursion

2. Graphs

Tail or Accumulator-Style Functions

Outline• Prerequisites

– Recursion

– Structures

– Graphs

• Objectives

– Need for Accumulation

– Accumulator Style Functions

– Transforming Recursive Functions

• Reference

– HTDP Chapters 31, 32

Background• Pure (augmenting or “head”) recursion follows

the functional paradigm – The recursion you have seen so far– Does not permit memory– Forgets useful intermediate results– Unnecessarily repeats large computations

• We now consider ways to improve the efficiency of recursion– Passing extra parameters to remember useful

details– Basically collecting partial results as we go!!

• Frequently referred to as “Tail Recursion”

A Different View

OK so we noted the cost of recursion can be large, if it’s not designed well.

(define (factorial n) (if (zero? n) 1 (* n (factorial (- n 1)))))

Let’s trace this for 4!Let’s trace this for 4!

fact (4) 4 *

fact (3)

4 *

3 *

fact (2)

4 *

3 *

2 *

fact (1)

4 *

3 *

2 *

1 *

fact (0)

4 *

3 *

2 *

1 *

1

Example(define (factorial n) (if (zero? n) 1 (* n (factorial (- n 1)))))

Let’s trace this for 4!Let’s trace this for 4!

fact (4) 4 *

fact (3)

4 *

3 *

fact (2)

4 *

3 *

2 *

fact (1)

4 *

3 *

2 *

1 *

fact (0)

4 *

3 *

2 *

1 *

1

ExampleEach recursive call creates a new activation frame.

This implied that recursive solutions could potentially take large amounts of memory.

Augmentative RecursionAnalysis: The problem was that in order to find what’s returned from one function call, we had to make a recursive call.

Substitution Model of Evaluation

(factorial 3)(* 3 (factorial 2))(* 3 (* 2 (factorial 1)))(* 3 (* 2 (* 1 (factorial 0))))(* 3 (* 2 (* 1 1)))(* 3 (* 2 1))(* 3 2)6

Each argument is ‘evaluated’ and substituted.

We’ll see later how to halt this evaluation, whenthis becomes useful.

Substitution Model of Evaluation

(factorial 3)(* 3 (factorial 2))(* 3 (* 2 (factorial 1)))(* 3 (* 2 (* 1 (factorial 0))))(* 3 (* 2 (* 1 1)))(* 3 (* 2 1))(* 3 2)6

Each argument is ‘evaluated’ and substituted.

We’ll see later how to halt this evaluation, whenthis becomes useful.

This required us to save frames for each recursive call.

Tail RecursionIf we can “solve” the return result from each level, the computer will not have to save each activation frame.

This approach is know as tail recursion--it’s a technique that allows the computer to optimize recursion so that it takes less memory.

Instead of postponingpostponing multiplication:

3 * fact(2)

… we can instead add extra parametersadd extra parameters so that calculations can be done entirely inside the frame.

Requires recursive call

Tail RecursionWe start with the usual function, but call a helper function:

(define (fact n)(fact-helper 1 n))

(define (fact-helper product n)(cond ((zero? n) product)

(else(fact-helper (* product n)

(- n 1)))))

This is similar to our previous solution, but look at the calculations--each term can be know inside the frame.

Tail Recursion

(define (fact n)(fact-helper 1 n))

(define (fact-helper product n) (cond [ (zero? n) product ] [ else (fact-helper (* product n) (- n 1))]))

We now have all the information needed to calculate the result inside the frame, without saving each recurse.

(* n (factorial (- n 1)) (fact-helper (* product n)(- n 1))

Augmentative/HeadAugmentative/Head Tail RecursiveTail Recursive

All-in-oneAll-in-oneRequires recursive callRequires recursive call

Tail RecursionWe can see the memory use of this approach by tracing

(fact 3)

(fact-helper 1 3)(fact-helper 3 2)(fact-helper 6 1)(fact-helper 6 0)

==>6

Each frame completed, andis not necessary to save.

Tail Recursion

(fact 3)

(fact-helper 1 3)(fact-helper 3 2)(fact-helper 6 1)(fact-helper 6 0)

==>6 (fact 3)

(fact-helper 1 3)

(fact-helper 3 2)

(fact-helper 6 1)

(fact-helper 6 0)

Potentially, the activation stack could grow just as we saw with augmentative recursion. But the Scheme interpreter (and many compilers) can optimize tail recursive expressions to constant memory use. (In fact, Scheme interpreters are required to optimize tail recursion.)

Tail RecursionSo tail recursion is nothing very different from what you’ve seen before, except that:

It’s written with an awareness of memory use

Each calculation is independent of subsequent recursive calls

Extra parameters (usually) are used to eliminate dependence on calculations made in subsequent recursive calls.In plain English, they hold partial results!!

33

22

11

HintsCan’t write it tail recursively? Just try this:

Write the function recursively.

Identify which calculations cannot be madeentirely within a single frame

Add sufficient extra parameters to eliminate the need to save information in a stack

11

22

33

ExampleRecently, we considered a function that would multiply numbers by adding repeatedly.

Reworked, we get:

(define mult a b)(mult-iterative 0 a b))

(define (mult-iterative result num1 num2)(if (= num2 0)

result(mult-iterative (+ result num1)

num1(- num2 1))))

Example(define mult a b)

(mult-iterative 0 a b))

(define (mult-iterative result num1 num2)(if (= num2 0)

result(mult-iterative (+ result num1)

num1(- num2 1))))

(mult 3 4)(mult-it 0 3 4)(mult-it 3 3 3)(mult-it 6 3 2)(mult-it 9 3 1)(mult-it 12 3 0)

A trace confirms the reduceduse of memory. None of the ‘mult-it’ calls need to be kept on the activation stack; they do not depend on each other.

Notes On Terminology

The following questions are presented to suggest further reading:

What’s a recursive process? What’s a recursive procedure? What’s the difference?

See http://mitpress.mit.edu/sicp/full-text/book-Z-H-11.html

Footnote

• To solve problems using tail recursion, we normally develop at least two different functions.

• In the integration example, these were (integrate lst) and (integrate-2 lst accum)

• Leaving these “lying around” separate is a little tacky.

• We use the idea of (local …) functions to clean this up.

Recall (local …)

• The syntax for a function using (local …) is as follows:(define (use-local …)

(local ((<definition-1>)

(<definition-2>)

(<definition-n>))

<expression> ))

• Where the definition list is encapsulated, and when the function is invoked by evaluating

(use-local … ) it actually evaluates the body <expression> which then uses the encapsulated definitions.

For example:

(define (integrate lst) (local ( (define (integrate-2 lst accum) (cond [(empty? lst) empty] [else (cons (+ (first lst) accum) (integrate-2 (rest lst) (+ accum (first lst))))]))) (integrate-2 lst 0)))

(define (integrate-2 lst accum) (cond [(empty? lst) empty] [else (cons (+ (first lst) accum) (integrate-2 (rest lst) (+ accum (first lst))))]))(define (integrate lst) (integrate-2 lst 0)) Unchanged (integrate-2 …)

“absorbed” into its wrapper, (integrate …), and called by it

Generalized template

• Deciding that a function will benefit from an accumulator requires experience borne of much practice.

• When you decide this is probably the case, (local … ) provides an excellent template.(define (<old-fn> <params>) (local ( (define (<aux-fn> <params> <accum>) (cond [(<end?> <params>) … ] [else … <params> … <accum> … (<aux-fn> <params> … <accum> …))]))) (<aux-fn> <params> <initial-acc>)))

Dissecting this Template

(define (<old-fn> <params>) (local ( (define (<aux-fn> <params> <accum>) (cond [(<end?> <params>) … ] [else … <params> … <accum> … (<aux-fn> <params> … <accum> …))]))) (<aux-fn> <params> <initial-acc>)))

What you really want What you need to do the job efficiently

Call the new function with initial accumulator value

Use parameters and accumulator as required

Update accumulator value in the recursive call

Commentary on the Design Process

1. First, draw a picture of the problem

2. Write a normal recursive solution or focus on what your partial result at each stage will be

3. If you notice opportunities to avoid loss of useful information,a) Start with the (local …) version of the template

b) Visualize how the accumulator computation will work

c) Figure out how to initialize the accumulation

d) Figure out how this affects the termination condition

e) Figure out how to update the accumulator for the recursive call

ExampleWrite a function to add all numbers from 0 to N.

Write this using augmentative recursion and tail recursion.

tail.scm

Questions?

Summary

• You should now know…

– Need for Accumulation

– Accumulator Style Functions

– Transforming Recursive Functions

Intro to Graphs

Outline

• Prerequisites

– List manipulation

• Objectives

– Basic Graph Terminology

– Depth-First Search

• Reference

– HTDP Section 28.1

Graphs

• Have nothing to do with plotting data (i.e. a graph of the function y = sin(x).

• Are widely used to solve a large number of totally unrelated problems in CS, Engineering, Math, Business, etc.

• Are studied in Graph Theory• So what do we mean by a graph?

Graph Terminology

What is a graph?

We can think of a graph as a combination of two things: a setset of points (verticesvertices) possibly in a plane and a set of line segments (edgesedges).

Sometimes, a graph is formally defined as:

G = (V, E)

where ‘G’, ‘V’ and ‘E’ represent Graph, Vertices (or points) and Edges (the line segments).

Graph TerminologyA graph may be directeddirected, meaning that the line segments join points only in one direction.

A B

C

DE

F

Can’t travel from E to D directly, only from D to Eon this edge.

Graph TerminologyA graph also might be undirectedundirected, meaning that line segments join points from either direction.

A B

C

DE

F

An undirected or bidirectional graph

Graph TerminologyA graph also might be undirected, meaning that line segments join points from either direction.

A B

C

DE

F

When you see edges with no arrows, you may presume the graph is undirected, or bidirectional

Graph TerminologyWhen an edge connects two vertices or nodes, we say that they are ‘adjacent’adjacent’.

A B

C

DE

F

E is adjacent to F, A, B, and D, but not C. Sure, you can still get to C from E, but not directly.

Graph TerminologyUnlike trees, which are special types of graphs, general graphs may have cyclescycles, meaning that children can be the parents of their ‘ancestor nodes’.

A B

C

DE

F

Put another way, it’s possible to walk in circles through a graph, if you don’t keep track of where you’ve been.

A

B

C

E

Graph TerminologyA collection of individual points (or edges) in a graph may represent a path.

A B

C

DE

F

A path is just a way of getting from a start node to another node.

Graph TerminologyIn the wacky world of graphs, a node may be connected even to itself.

A B

C

DE

F

It seems odd, but since a graph is made of edges and vertices, an edge just might connect a node to itself.

Note

Graph TerminologyWe can also assign ‘weights’ or values to edges.

A B

C

DE

F

In such a case, we have a weighted graphweighted graph. The weights can represent cost, distance, opportunity costs--anything.

5

7

12

25

12

8

9

3

Graph TerminologyIn the beginning, we will mainly concern ourselves with unweighted graphs.

A B

C

DE

F

We’ll just be interested in establishing if there’s a connection or relationship between nodes. We can later add weights to provide a richer graph data set.

Quick QuizSo far, we’ve worked with trees. Are trees really just graphs? Consider the definition of a graph...

Graph TerminologyGraph Terminology

What is a graph?

We can think of a graph as a combination of two things:a set of points in a plane and a set of line segments.

Sometimes, a graph is formally defined as:

G = (V, E)

where ‘G’, ‘V’ and ‘E’ represent Graph, Vertices (orpoints) and Edges (the line segments).

Graph TerminologyGraph Terminology

What is a graph?

We can think of a graph as a combination of two things:a set of points in a plane and a set of line segments.

Sometimes, a graph is formally defined as:

G = (V, E)

where ‘G’, ‘V’ and ‘E’ represent Graph, Vertices (orpoints) and Edges (the line segments).

Do trees have vertices and edges?

Yup.

Are they graphs?

Of course.

Graph Examples

Map of Distilleries in Scotland.

Is this a graph? (What is a graph?)

Does this provide useful information?

What’s missing?

(Nothing; We’re only missing NSF Funding for research on this graph.)

• Graphs can also track the flows and movements of individuals in society.

• E.g., Krempel’s map of Duisburg zoo visitors. The width of the lines indicates the number of visitors taking an edge.

Graph/Network Uses

(Note: the Autobahn divides the zoo in half. Can you see evidence of this in the graph?)

Summary Graphs (cont’d)

Graphs are also useful for modeling hierarchy networks.

A good example is the internet, with various ‘tiers’ of providers that link portions of the net together.

A graph can be used to model the network relationship between computers.

More Examples

Visit: www.theyrule.net

Representing Graphs

A B

C

DE

F

Let’s take a simple graph, and try to draw a Scheme-like list that represents its data.

Representing Graphs

A B

C

DE

F

(define graph'((A (B E F)) (B (A C D E)) (C (B D)) (D (B C E)) (E (A B D F)) (F (A E))))

A

B E

D E F

F

C A A E

Caution: Think ofthis is a flowchartand not a graph.

Uses for GraphsWhat practical use is such a data structure?

(define tech-graph'((Skiles (S-C Library DMS)) (S-C (Skiles CoC Rich Library )) (CoC (S-C Rich )) (Rich (S-C CoC Library )) (Library (Skiles S-C Rich DMS)) (DMS (Skiles Library ))))

A B

C

DE

F

Skiles

DMSmith

Library Rich

StudentCenter

CoCWe could use it to modelmap relationships, find efficient paths, etc.

More on this later...

Searching GraphsWhat good is a graph if you can’t search it?

Our tree traversals proved useful, so can we ‘walk’ a graph using similar techniques?

Problem:Problem: What if a node has more than one child?

Our previous algorithms just considered three items: node, left and right.

Problem:Problem: What if we cycle? A B

C

DE

FLet’s learn more about searching first.

Searching GraphsWe need to keep these problems in mind...

Searching GraphsSearching GraphsWhat good is a graph if you can’t search it?

Our tree traversals proved useful, so can we ‘walk’ agraph using similar techniques?

Problem:Problem: What if a node has more than one child?

Our previous algorithms just considered threeitems: node, left and right.

Problem:Problem: What if we cycle? A B

C

DE

FLet’s learn more about searching first.

Searching GraphsSearching GraphsWhat good is a graph if you can’t search it?

Our tree traversals proved useful, so can we ‘walk’ agraph using similar techniques?

Problem:Problem: What if a node has more than one child?

Our previous algorithms just considered threeitems: node, left and right.

Problem:Problem: What if we cycle? A B

C

DE

FLet’s learn more about searching first.

For now, however, let’s consider searches that are simple and don’t have this problem.

Hierarchical search

We can also arrange knowledge into hierarchies. Perhaps the most familiar is the zoological hierarchy of kingdoms, phylum, genus, etc.

Lepidoptera

Moth Butterfly

MourningCloak

Monarch

Hierarchical search

Hierarchies allow us to make statements about items in the collection. For example, we can say that a monarch “is a” butterfly, and a butterfly “is a” lepidoptera.

Lepidoptera

Moth Butterfly

MourningCloak

Monarch

Hierarchical search

Since most people are unfamiliar with insects families, we’ll instead switch to a more familiar hierarchy: the Flintstones.

Chip Roxy

PebblesBamm-Bamm

Wilma Fred

Barney Betty

Hierarchical search

We’ll also give attributes to this hierarchy:

Chip Roxy

PebblesBamm-Bamm

Wilma Fred Barney Betty

Has dad

Has dadHas dad

Has mom

Has mom

Has mom

Hierarchical searchThis allows us to do important research, like asking “who is Chip’s mother?” Or “who is Chip’s grandfather on his mother’s side?”

Chip Roxy

PebblesBamm-Bamm

Wilma Fred BarneyBetty

Has dad

Has dad

Has dadHas mom

Has mom

Has mom

Depth First SearchThe simplest form of search in a hierarchical or network structure is called "depth-first search". We can write an algorithm for a depth-first search on a binary tree:

DFS (depth first search):

1. Look at the root 2. If it's what you're looking for, then return success 3. If the root has no descendants, then return failure 4. Call df-search on the subtree whose root is the leftmost descendant and return success if that search is successful 5. Call df-search on the subtree whose root is the rightmost descendant and return success if that search is successful

Depth First SearchIf this seems familiar, it’s because DFS is a variation of one tree search we saw recently:

preorder

1.visit the root 2.call preorder on the left subtree 3.call preorder on the right subtree

Comparison

preorder

1.visit the root 2.call preorder on the left subtree 3.call preorder on the right subtree

DFS (depth first search):

1. Look at the root 2. If it's what you're looking for, then return success 3. If the root has no descendants, then return failure 4. Call df-search on the subtree whose root is the leftmost descendant and return success if that search is successful 5. Call df-search on the subtree whose root is the rightmost descendant and return success if that search is successful

Comparison

preorder

1.visit the root 2.call preorder on the left subtree 3.call preorder on the right subtree

DFS (depth first search):

1. Look at the root 2. If it's what you're looking for, then return success 3. If the root has no descendants, then return failure 4. Call df-search on the subtree whose root is the leftmost descendant and return success if that search is successful 5. Call df-search on the subtree whose root is the rightmost descendant and return success if that search is successful

Comparison

preorder

1.visit the root 2.call preorder on the left subtree 3.call preorder on the right subtree

DFS (depth first search):

1. Look at the root 2. If it's what you're looking for, then return success 3. If the root has no descendants, then return failure 4. Call df-search on the subtree whose root is the leftmost descendant and return success if that search is successful 5. Call df-search on the subtree whose root is the rightmost descendant and return success if that search is successful

What’s different?What’s different?

DFS - Preorder Differences

The big differences between the preorder algorithm and the depth-first search algorithm are these:

depth-first search stops before searching the whole tree, if it finds what it's looking for; preorder traversal always examines the entire tree

with depth-first search, searching the right subtree occurs only if the search of the left subtree failed to find what was being looked for; with preorder traversal, the right subtree is always explored (this is sort of a corollary to the first difference listed just above)

11

22

Implementing Depth-First Search

Let’s first note how we might represent the trees in Scheme:

(define-struct node ( name mother father ) )

(define harriet (make-node 'harriet false false))(define ozzie (make-node 'ozzie false false))(define betty (make-node 'betty false false))(define barney (make-node 'barney false false))(define fred (make-node 'fred false false))(define wilma (make-node 'wilma false false)) … Chip Roxy

PebblesBamm-Bamm

Wilma Fred Barney Betty

Implementing Depth-First Search

(define (dfs target here) (cond [(not here) false] [(symbol=? target (node-name here)) true] [else (or (dfs target (node-father here)) (dfs targer (node-mother here)))]))

We start with a function called dfs:

Improving DFSNow, just telling us true or false is not entirely useful. Weactually want to use a hierarchical search to produce a list that shows the relationship between items.

We’ll use tail recursion . . .

Improving DFS(define (dfs-list who here) (local ( (define (dfs-aux who here answer) (cond [(not here) empty] [(symbol=? who (node-name here)) (cons (node-name here) answer)] [else (local ((define mother-list (dfs-aux who (node-mother here) (cons (node-name here) answer)))) (if (empty? mother-list) (dfs-aux who (node-father here) (cons (node-name here) answer)) mother-list))]))) (dfs-aux who here empty)))

dfs.scm

Questions?

Summary

• You Should Now Know

– Basic Graph Terminology

– Depth-First Search

Recommended