cyriak: conceptually disruptive recursion… baaa. welcome to ist338… be sure to watch your head!

186
Cyriak: conceptually disruptive recursion… Baaa

Upload: martina-jacobs

Post on 22-Dec-2015

214 views

Category:

Documents


0 download

TRANSCRIPT

Cyriak: conceptually disruptive recursion…

Baaa

Welcome to IST338… Be sure to watch your head!

We're computationally complete!

IST338: now recursing…

putting Python to work!

Hw 2 – due Friday 2/20 ~ as usual

pr1 lab – Turtle!pr2 – Monte Carlo simulation

What's next?

pr0 reading – Watson!

Or re-cursing, depending on your feelings about recursion!

pr3+4 – extra-credit probs!

& adding building-blocks

Recursive design works…

def mylen(s):

""" input: any string, s

output: the number of characters in s

"""

if s == '':

return 0

else:

return 1 + mylen(s[1:])

There's not much len left here!

… by solving a smaller version of the same problem!

mylen('cs5')

Behind the curtain:how recursion works...

def mylen(s):

if s == '':

return 0

else:

return 1 + mylen(s[1:])

1 + mylen('s5')

1 + 1 + mylen('5')

1 + 1 + 1 + mylen('')

1 + 1 + 1 + 0

mymax( [1,4,3,42,-100,7] )

def mymax(L):

if len(L) == 1:

return L[0]

elif L[0] < L[1]:

return mymax( L[1:] )

else:

return mymax( L[0:1]+L[2:] )

mymax( [4,3,42,-100,7] )

mymax( [4,42,-100,7] )

mymax( [42,-100,7] )

mymax( [42,7] )

mymax( [42] )

42

base case

drop 1st

drop 2nd

Picture it!

power(2,5) -> 2*2

power(2,0) -> 1

20== 1

25

== 2*24

2p

== 2*2

4

power(2,p) -> 2*power(…,…)

Do you see the call to power!?

def power(b,p): """ returns b to the p power Use recursion, not ** Inputs: int b, int p: the base and the power"""

What should this be?

power(b,p) ->

Picture it!

power(2,5) -> 2*2

power(2,0) -> 1

20== 1

25

== 2*24

2p

== 2*2

4

power(2,p) -> 2*power(…,…)

Do you see the call to power!?

Try it!

def power(b,p):

Handle negative p values w/elif.

""" returns b to the p power Use recursion, not ** Inputs: int b, int p: the base and the power"""

Want more power?

E.g., power(5,-1) == 0.2

if :Base case test

p == 0

return

else:

return

Base case

Recursive caseWhat should

this be?

power(b,p) ->

power( 2, 5 )

2* power( 2, 4 )

2* 2* power( 2, 3 )

2* 2* 2* power( 2, 2 )

2* 2* 2* 2* power( 2, 1 )

2* 2* 2* 2* 2* power( 2, 0 )

2* 2* 2* 2* 2* 1

32

Picture it!

sajak('') 0

NOT a space – this is no characters at all. This is the empty string – and it has 0 vowels!

def sajak(s): """ returns the number of vowels in the input string, s"""

''

sajak('okay') 1+sajak( )

'okay'

sajak('what') 0+sajak( )

'what'

starts with a vowel – count that vowel and delegate the rest to recursion

starts with a consonant – so skip it and delegate the rest!

Picture it!

sajak('') 0

NOT a space – this is no characters at all. This is the empty string – and it has 0 vowels!

def sajak(s):

What 7-letter English word w maximizes sajak(w) ?

""" returns the number of vowels in the input string, s"""

Want more Pat?

if s == '':

elif

else:

return

return

return

Base case test

''

sajak('okay') 1+sajak( )

'okay'

sajak('what') 0+sajak( )

'what'

starts with a vowel – count that vowel and delegate the rest to recursion

Try it!

starts with a consonant – so skip it and delegate the rest!

sajak( 'eerier' )

1+ sajak( 'erier' )

1+ 1+ sajak( 'rier' )

1+ 1+ 0+ sajak( 'ier' )

1+ 1+ 0+ 1+ sajak( 'er' )

1+ 1+ 0+ 1+ 1+ sajak( 'r' )

1+ 1+ 0+ 1+ 1+ 0+ sajak( '' )

1+ 1+ 0+ 1+ 1+ 0+ 0 4

def power(b,p): """ inputs: base b and power p (an int)

implements: b**p

"""

if p == 0:

return 1.0

elif p < 0:

return ____________________

else:

return b * power(b,p-1)

Recursion is power!

# of vowels

in ssajak(s):

Base case? When there are no letters, there are ZERO vowels

if s[0] is NOT a vowel, the answer is

Rec. step? Look at the initial character.

if s[0] is a vowel, the answer is

D

E

S

I

G

N

sajak( s[1:] )

1 + sajak( s[1:] )

def sajak(s):

if s == '':

return 0

elif s[0]=='a' or s[0]=='e' or…

but how to check for vowels?

Is s[0] a vowel?

Python is… in

>>> 'i' in 'team'False

>>> 'cs' in 'physics'True

>>> 42 in [41,42,43]True

>>> 42 in [[42], '42']False

I guess Python's the in thing

>>> 'i' in 'alien'True >>> 3*'i' in 'alien'

False

def sajak(s):

if len(s) == 0:

return 0

elif s[0] in 'aeiou':

return 1 + sajak(s[1:])

else:

return 0 + sajak(s[1:])

if s[0] is NOT a vowel, the answer is just

the number of vowels in the rest of s

if s[0] IS a vowel, the answer is

1 + the # of vowels in the rest of s

Base Case

Recursive Cases

let's input 'eerier' for s

The key to understanding recursion is, first, to understand recursion.

- a former student

tutors @ LAC all week!

Good luck with Homework #1

It's the eeriest!

Three random asides…

import random

choice( L )

choice(['cmc','scripps','pitzer','pomona'])

chooses 1 element from the sequence L

allows use of dir(random) and help(random)

How could you get a random int from 0 to 99 inclusive?

from random import * all random functions are now available!

choice('mudd')

uniform(low,hi) chooses a random float from low to hi

floats have 16 places of precision Aargh – so close!

range(1,5) [1,2,3,4]

A random function…

print the guesses ?

return the number of guesses ?

from random import *

def guess( hidden ): """ tries to guess our "hidden" # """ compguess = choice( range(100) )

if compguess == hidden: # at last! print 'I got it!'

else: guess( hidden ) Suspicious? I am!

slow down…

investigate expected # of guesses?!??

Remember, this is [0,1,…,99]

Empirical Hypothesis Testing…

a.k.a.

How many guesses do we expect in order to find the

correct number?

from random import *import time

def guess( hidden ): """ guessing game """ compguess = choice( range(100) )

# print 'I choose', compguess # time.sleep(0.05)

if compguess == hidden: # at last! # print 'I got it!'

return 1 else: return 1 + guess( hidden )

Recursive guess-counting

A few random thoughts…

choice( range(1,5)+[4,2,4,2] )

uniform( -20.5, 0.5 )

What are the chances this returns a 2 ?

from random import *

What're the chances of this being > 0?

choice( '1,2,3,4' )

choice( ['1,2,3,4'] )

choice( '[1,2,3,4]' )

choice( [1,2,3,2] )

choice( range(5) )

What's the most likely return value here?

Quiz Name(s):

What's the most likely return value here?

What's the most likely return value here?

What are the chances of this returning a 4 ?

Is this more likely to be even or odd (or same)?

Careful!

Extra!

choice( 0,1,2,3,4 )

choice[ range(5) ]

choice( [range(5)] )

Which two of these are syntax errors? What does the third, "correct" one do?

and how likely are all these?

[ [0,1,2,3,4] ]

choice( range(1,5)+[4,2,4,2] )

uniform( -20.5, 0.5 )

What are the chances this returns a 2 ?

What're the chances of this being > 0?

choice( '1,2,3,4' )

choice( ['1,2,3,4'] )

choice( '[1,2,3,4]' )

choice( [1,2,3,2] )

choice( range(5) )

What's the most likely return value here?

What's the most likely return value here?

What's the most likely return value here?

What are the chances of this returning a 4 ?

Is this more likely to be even or odd (or same)?

1/42

choice( 0,1,2,3,4 )

choice[ range(5) ]

choice( [range(5)] )

and how likely are all these?

2/4 or 50%

3/8

',' 3/7

'1,2,3,4' 1/1

',' 3/9

even 3/5

[0,1,2,3,4]

syntax error

correct: always returns [0,1,2,3,4]

syntax error

1/1 chance

[1,2,3,4,4,2,4,2]

Data is in black. Probabilities are in blue.

The two Monte Carlos

Monte Carlo casino, Monaco

Insights via random trials

Monte Carlo methods, Math/CS

and their denizens…

Insights via random trials

Monte Carlo casino, Monaco

Monte Carlo methods, Math/CS

Stanislaw Ulam (Los Alamos badge)

Bond, James Bond

The two Monte Carlos and their denizens…

Ulam, Stan Ulam

Monte Carlo in action

def countDoubles( N ): """ input: the # of dice rolls to make output: the # of doubles seen """ if N == 0: return 0 # zero rolls, zero doubles… else: d1 = choice( [1,2,3,4,5,6] ) d2 = choice( range(1,7) )

if d1 != d2: return 0+countDoubles( N-1 ) # don't count it else: return 1+countDoubles( N-1 ) # COUNT IT!

two dice from 1-6 inclusive

where and how is the check for doubles?

N is the total number of rolls

How many doubles will you get in N rolls of 2 dice?

Empirical Hypothesis Testing…

a.k.a.

How many guesses do we expect in order to find the

correct number?

Empirical Hypothesis Testing…

a.k.a.

Run it a zillion times!

# this line runs guess(42) 1000 times!LC = [ guess(42) for x in range(1000) ] # Let's look at the first 10 of them:print LC[0:10]

# Let's find the average:print "av. guesses:", sum(LC)*1.0/len(LC)

Hah! Now I see why they told me I'd be making a zillion euros!

Empirical Hypothesis Testing…

a.k.a.

How likely are we to roll doubles on two six-sided dice?

Hah! Now I see why they told me I'd be making a zillion euros!

Zillion-times testing!

# this runs the doubles-counter 600 times…cd( 600 )

# Run _that_ 100 times (60,000 rolls total!)DBLS = [ cd(600) for x in range(100) ] # Look at the first 10 of theseprint DBLS[0:10]

# Let's find the average:print "av. dbls/600:", sum(DBLS)*1.0/len(DBLS)

needed a less continental name…

On balance?

or maybe lighter is better?

Data

Functions

…together

[8,9,10]

sq( )

[64,81,100]

[ sq(x) for x in [8,9,10] ]

List Comprehensions

>>> [ 2*x for x in [0,1,2,3,4,5] ]

What's the syntax saying here?

List Comprehenion

result[0, 2, 4, 6, 8, 10]

List Comprehensions

>>> [ 2*x for x in [0,1,2,3,4,5] ]

[0, 2, 4, 6, 8, 10]output

input

The same as map, only better!

this "runner" variable can have any name...

x takes on each value

and 2*x is output for each one

List Comprehensions

>>> [ 10*x for x in [0,1,2,3,4,5] if x%2==0]

result

>>> [ y*21 for y in range(0,3) ] LC

result

>>> [ s[1] for s in ["hi", "5Cs!"] ]

result

LC

LC

OK – got it. But what about that name?

List Comprehensions?

>>> [ 2*x for x in [0,1,2,3,4,5] ][0, 2, 4, 6, 8, 10]

Is this really the best name Guido Van Rossum could think of?

List Comprehensions?

>>> [ 2*x for x in [0,1,2,3,4,5] ][0, 2, 4, 6, 8, 10]

FunLists!Datafuncs?Google maps?

A list comprehension by any other name would be as sweet…

[ n**2 for n in range(0,5) ]

Quiz!

[ a*(a-1) for a in range(8) if a%2==1 ]

[ -7*b for b in range(-6,6) if abs(b)>4 ]

[ s[1::2] for s in ['aces','451!'] ]

[ 42 for z in [0,1,2] ]

A range of list comprehensions...Write Python's result for each L.C.:

[ z for z in [0,1,2] ]

I wonder if these will be

useful ?!

Name(s): ___________________________

Syntax ?!

a (frustrated!) rendering of an unfamiliar math problem

>>> [ 2*x for x in [0,1,2,3,4,5] ][0, 2, 4, 6, 8, 10]

at first…

a jumble of characters and random other stuff

Syntax ?!

a (frustrated!) rendering of an unfamiliar math problem

>>> [ 2*x for x in [0,1,2,3,4,5] ][0, 2, 4, 6, 8, 10]

at first…

a jumble of characters and random other stuff

Syntax ~ is CS's key resource!

a (frustrated!) rendering of an unfamiliar math problem

which was likely similar to these…

Where'd the change happen?

Syntax vs. Semantics

Plus – you might consider coming to the Career Fair this Friday at HMC's LAC…

Another Monte Carlo Monty… ?

inspiring the “Monty Hall paradox”

Let's make a deal…

'63-'86

inspiring the Monty Hall paradox

Monty

Let's make a deal: XKCD's take…

… but what if you considered the goat the grand prize!?inspiring the Monty Hall paradox

Monty

Monte Carlo Monty HallSuppose you always switch to the other door...What are the chances that you will win the prize ?

Run it (randomly) 300 times and see!

Monte Carlo Monty Hall

def MCMH( init, sors, N ): """ plays the "Let's make a deal" game N times returns the number of times you win the *Spam!* """ if N == 0: return 0 # don't play, can't win przDoor = choice([1,2,3]) # where the spam (prize) is…

if init == przDoor and sors == 'stay': result = 'Spam!' elif init == przDoor and sors == 'switch': result = 'pmfp.' elif init != przDoor and sors == 'switch': result = 'Spam!' else: result = 'pmfp.'

print 'You get the', result if result == 'Spam!': return 1 + MCMH( init, sors, N-1 ) else: return 0 + MCMH( init, sors, N-1 )

Your initial choice!

'switch' or 'stay'

number of times to play

CS for Insight!

a.k.a.

How often do we win if we SWITCH vs. STAY ?

I hope the prize isn't in Euros!

Monte Carlo Monty Hall!

# this runs the game once (staying…)MCMHonce1( 3, 'stay' )

# Run _that_ 3000 times PRIZES = [ MCMH1(3,'stay') for x in range(3000) ] # Look at the first 10 of theseprint PRIZES[0:10]

# Let's find the total number of wins:how to do this… ?!

A

B

C

D

E

F

G

H

0 1 2 3 4 5 6 7 8 9

A

B

C

D

E

F

G

H

0 1 2 3 4 5 6 7 8 9

An example closer to home

......25 26 27 28 502423220

An overworked CGU student (S) leaves Harg. after their "late-night" breakfast. Each moment, they randomly

stumble toward class (W) or their Apartment (E)

ACB Apt(S)(W)

Harg.

Write a program to model and analyze! this scenario...

Once the student arrives at the dorm or classroom, the trip is complete.The program should then print the total number of steps taken.

hw2pr2

rwpos(s,nsteps) rwsteps(s,low,hi)take nsteps random

steps starting at stake random steps starting at s until you reach either low or hi

S

An example closer to home

......25 26 27 28 502423220

An overworked CGU student (S) leaves Harg. after their "late-night" breakfast. Each moment, they randomly

stumble toward class (W) or their Apartment (E)

ACB Apt(S)(W)

Harg.

Write a program to model and analyze! this scenario...

Once the student arrives at the dorm or classroom, the trip is complete.The program should then print the total number of steps taken.

hw2pr2

rwpos(s,nsteps) rwsteps(s,low,hi)take nsteps random

steps starting at stake random steps starting at s until you reach either low or hi

S

How could we create this

as an "ASCII" animation?

Nature prefers recursion, too!

Recursion's challenge?You need to see BOTH the self-similar pieces AND the whole thing simultaneously!

Yes... and no.Are these rules for real?

Dragon's-blood Tree

There still has to be a base case…

or else!

Cyriak: conceptually disruptive recursion…

is the branching, not the single-path variety.

handfingers

Python's Etch-a-Sketchthe turtle's canvas

import timefrom turtle import *

def draw(): shape('turtle') # pause time.sleep(2) # drawing… width(5) left(90) forward(50) right(90) backward(50) down() or up() color('darkgreen') tracer(1) or tracer(0) width(5)

http://docs.python.org/library/turtle.html

degrees!

sets if the pen draws or not

sets if the pen animates or not

(0,0)

win

dow

_hei

ght(

)

window_width()

(42,42)

pixels!

Single-path recursion

def tri(): """ a triangle! """ forward(100) left(120) forward(100) left(120) forward(100) left(120)

Let's tri this with recursion:(1)

How about any regular N-gon?(2)

I don't know about tri, but there sure is NO return … !

def tri( n ): """ draws a triangle """ if n==0: return else: forward(100) # one side left(120) # turn 360/3 tri( n-1 ) # draw rest

def poly(n, N): """ draws a triangle """ if n==0: return else: forward(100) # one side left(360.0/N) # turn 360/N poly(n-1, N) # draw rest

def chai(size): """ mystery! """ forward(size) left(90) forward(size/2.0) right(90)

right(90) forward(size) left(90)

left(90) forward(size/2.0) right(90) backward(size)

What does chai(100) draw?(1)

Be the turtle ! Finish rwalk so it draws a "stock-market" path: N steps of 10 pixels each. Use recursion.(2)

from random import *

def rwalk(N): """ make N 10-pixel steps, NE or SE """

if N == 0: return

elif choice(['left','right']) == 'left':

else: # this handles 'right'

Extra! How could you make it a bull (or a bear) market?

one possible result of rwalk(20)

left(45)forward(10)

What if you called chai(size/2) betw. the right(90) & left(90) calls?

?

?

Extra!

def chai(size): """ mystery! """ if size<9: return

forward(size) left(90) forward(size/2.0) right(90)

right(90) forward(size) left(90)

left(90) forward(size/2.0) right(90) backward(size)

How could you add more to each T-tip? Why are there two identical commands in a row ~ twice!?

(1) What does chai(100) do?

from random import *

def rwalk(N): """ make N 10-px steps, NE or SE """ if N == 0: return

elif choice(['left','right'])=='left': left(45) forward(10) right(45) rwalk( N-1 )

else: # 'right' right(45) forward(10) left(45) rwalk( N-1 )

What if we didn't turn back to face east each time?

(2) rwalk is a random stock market walk...

Extra: Creating a bull (or a bear) market?

hw2pr1

100

81

spiral( initLength, angle, multiplier )

spiral(100,90,0.9)

90

fractal art!

svtree( trunkLength, levels )

svtree( 100, 5 )

levels == 5

levels == 2

levels == 0(no drawing)levels == 1

levels == 3

levels == 4

svtree( trunkLength, levels )

svtree( 100, 5 )

levels == 5

levels == 2

levels == 0(no drawing)levels == 1

svtree( 75, 4 )

What steps does the turtle need to take before

recursing?

levels == 3

levels == 4

svtree( trunkLength, levels )

levels == 5

levels == 4

levels == 3

levels == 2

levels == 0(no drawing)

Be sure the turtle always returns to its starting

position! levels == 1

svtree( 100, 5 )

step #1: go forward…

step #2: turn a bit…

step #3: draw a smaller svtree!

step #4: turn to another heading

step #5: draw another smaller svtree!

step #6: get back to the start by

turning and moving!

svtree( trunkLength, levels )

svtree( 100, 5 )

levels == 5

levels == 2

levels == 0(no drawing)levels == 1

svtree( 75, 4 )

Be sure the turtle always returns to its starting

position!

that means it will finish the recursive

call right here!levels == 3

levels == 4

The Koch curve

snowflake(100, 0) snowflake(100, 1) snowflake(100, 2)

snowflake(100, 3) snowflake(100, 4) snowflake(100, 5)

Recursive art? Create your own… hw2pr4

Happy turtling!

What? Way too happy to be art… My recursive compositions burninate even Cyriak's brain!

seven-cornered confetti

A

B

C

D

E

F

G

H

0 1 2 3 4 5 6 7 8 9

Data

Functions

[13,14,15]

sum( )

[3,4,5,6,7,8,9]

sum range

def sum(L):

""" input: L, a list of #s

output: L's sum

"""

if len(L) == 0:

return 0.0

else:

return L[0] + sum(L[1:])

Base Case

Recursive Case

def range(low,hi ):

""" input: ints low and hi

output: int list from low to hi

"""

if low >= hi:

return []

else:

return

what's cookin' here?

excluding hi

sum range

step?

>>> sum(range(1,101))

?

sum and range

I'd bet you have a 50/50 chance on this one…- Ben. L '14

1784

>>> sum(range(1,101))

?

sum and range

I'd bet you have a 50/50 chance on this one…- Ben. L '14

1784

and 100 more…http://www.americanscientist.org/template/AssetDetail/assetid/50686

Gauss's storied story…

sum and range

Looks sort of scruffy for a 7-year old… !

and 100 more…http://www.americanscientist.org/template/AssetDetail/assetid/50686

1784

>>> sum(range(1,101))

5050

Gauss's storied story…

Welcome to CS 5! Be sure to watch your head…

Designing with LCs

>>> [ _______ for x in range(4) ]

[0, 14, 28, 42]

>>> [ _____________ for c in 'igetthis' ]

[True, False, False, False, False, False, True, False][ 1, 0, 0, 0, 0, 0, 1, 0 ]

output

output

input

input

And what if we wanted these values in red…?

[0,1,2,3]

LC = [1 for x in L]return sum( LC )

myst1(L):def

[7,8,9]

But one-liners are my specialty…

Sweet!Using LCs

LC = [letScore(c) for c in S]return sum( LC )

myst2(S):def

'twelve'lots of ifs…return score

letScore(c):def

LC = [1 for x in L]return sum( LC )

len(L):def

[7,8,9]

But one-liners are my specialty…

Sweet!Using LCs

LC = [letScore(c) for c in S]return sum( LC )

scrabbleScore(S):def

'twelve'lots of ifs…return score

letScore(c):def

stuff to get score…return score

letScore(c):

scrScore(s):

LC = [ letScore(c) for c in s]

return sum( LC )

def

defscrabble score!

'twelve'

Using LCs

LC = [1 for x in L]return sum( LC )

len(L):def

But in one-line … ?

'cs5'

len(L):def

return sum([1 for x in L]) Maybe too terse!

Sweet!

"One-line" LCs

count(e,L):LC = [ 1 for x in L if ] return sum( LC )

def

sajak(s):LC = [ for c in s]return sum( LC )

# of vowelsRemember True == 1 and False == 0

def

'sequoia'

count(e,L):# of times e is in L

LC = [ for x in L ] return sum( LC )

def

[3,42,5,7,42]42

using if instead…

Go!Write each of these functions using list comprehensions…

def nodds(L):

def lotto(Y,W):

input: L, any list of #soutput: the # of odd #s in L example: nodds( [3,4,5,7,42] ) == 3

inputs: Y and W, two lists of "lottery" numbers (ints)output: the # of matches between Y & W example: lotto( [5,7,42,47] , [3,5,7,44,47] ) == 3

Y are your #s W are the winning #s

def ndivs(N):

input: N, an int >= 2output: the # of positive divisors of Nexample: numdivs(12) == 6 (1,2,3,4,6,12)

LC = [ for x in L ]return sum(LC)

def primesUpTo(P):

input: P, an int >= 2output: the list of prime #s up to + incl. Pexample: primesUpTo(12) == [2,3,5,7,11] Extra!

LC = [

LC = [

output: the # of odd #s in L

def nodds(L):

inputs: L, any list of #s

example: nodds( [3,4,5,7,42] ) == 3

LC = [ for x in L ]return sum(LC)

def nodds(L): LC = [ 1 for x in L ]return sum(LC)

def lotto(Y,W): LC = [ for w in W ]

return sum(LC)

def lotto(Y,W): LC = [ 1 for w in W ]

return sum(LC)

inputs: Y and W, two lists of "lottery" numbers (ints)

output: the # of matches between Y & W example: lotto( [5,7,42,47] , [3,5,7,44,47] ) == 3

Y are your #s W are the winning #s

… could adapt to "y in Y", too.

def ndivs(N):

LC = [ for n in range(1,N+1)]

return sum(LC)

input: N, an int >= 2output: the # of positive divisors of Nexample: numdivs(12) == 6 (1,2,3,4,6,12)

def primesUpto( P ):Extra! A list of all primes up to P…

Turtle happiness?

remember you can run

done()

after turtle drawing!

This releases control of the turtle window to the computer (the operating system).

To be honest, it seems that not every machine needs this…

We're computationally complete!

CS 5: now recursing…

putting Python to work!

Hw 2 – due Sunday evening ~ usual time

pr1 lab – Turtle!pr2, pr3 - Python probs…

What's next?

pr0 reading – Watson!Or re-cursing, depending on your feelings about recursion!

pr4 – extra-credit turtle… !

& adding building-blocks

Recursive Art ~ hw2pr4

Submit things that work …

… and even things that don't!

septagonal confetti

Cyriak's pet snake…

On-campus tutoring hours… !

CMC:

Scripps:

Pitzer!

Pomona:

Beckett Lounge, Mon 6-8 (Melody S)CSMath CR, Adams Hall, Sun 8-10 (Rachel L &

Justin A)

Edmunds, Sun 8-10 (Kim R)

Scripps Student Union, Sun 6-8 (Kate F)

Phillips Lounge, Sun 3-5 (Michael I)Beckett Lounge, Sat + Sun 1-3 (Melody S)

Motley, Thu 8-10 (Kate F)

Picture it!

Try it!

def power(b,p):

Handle negative values of p in an elif.

""" returns b to the p power Use recursion, not ** Inputs: int b, int p: the base and the power"""

Want more power?

power(2,5) -> 2*2

For example, power(5,-1) == 0.2

if :Base case test

p == 0

return

else:

return

Base case

Recursive case

power(2,0) -> 1

20== 1

25

== 2*24

2p

== 2*2

4

power(2,p) -> 2*power(…)

Do you see the call to power!?

Using a Euro, Yuan the deadline comes next time I'll try to make the Mark. I'm Pounding it into my brain, but I have to Peso much attention to other deadlines in the classes I Currency have - but

if this keeps up, my grade will be demolished into Rubles.

hw0 highlightsand thoughts…

Eric Nguyen

Ashraf Mathkour

Martha Parker !

11:59 !?

Using a Euro, Yuan the deadline comes next time I'll try to make the Mark. I'm Pounding it into my brain, but I have to Peso much attention to other deadlines in the classes I Currency have - but

if this keeps up, my grade will be demolished into Rubles.

hw0 highlightsand thoughts…

Eric Nguyen

Ashraf Mathkour

Martha Parker !

11:59 !?

on-campus

tutoring!(details Wed. …)

Run inside Sublime!?

not required + not universal -- but you may want to try it…

Python interpreter

Python source

instructions are at the start of this week's Lab…

Try it!

def power(b,p):

Handle negative values of p in an elif.

""" returns b to the p power Use recursion, not ** Inputs: int b, int p: the base and the power"""

Want more power?

power(2,5) == 32.0

For example, power(5,-1) == 0.2

def sajak(s):

sajak('wheel of fortune') == 6

What 7-letter English word w maximizes sajak(w) ?

What about y? You decide…

""" returns the number of vowels in the input string, s"""

Want more Pat?

if :if s == '':

Base case test

elif

else:

p == 0

return

else:

return

return

return

return

Base case test

elif

in general:

Picture it!def mylen(s):

""" returns the number of characters in s input: s, a string"""

mylen('') 0

NOT a space – this is no characters at all. This is the empty string – and it has length of 0!

s = ''

mylen('hi') 1+mylen( )

mylen('recursion') 1+mylen( )

s = 'recursion'

starts with a vowel – count that vowel and delegate the rest to recursion

wow!

s = 'hi'

if :Base case test

p == 0

return

else:

return

Base case

Recursive case

Design #2

def mymax(L):

""" input: a NONEMPTY list, L

output: L's maximum element

"""

if :

elif :

base case test!

another case…

len(L)==1

[1,4,3,42,-100,7]

return

return

return

else:

def mymax(L):

""" input: a NONEMPTY list, L

output: L's maximum element

"""

if len(L) == 1:

return L[0]

elif L[0] < L[1]:

return mymax( L[1:] )

else:

return mymax( L[0:1] + L[2:] )

Hey - do I get a slice?!

Design #2

Computation's Dual Identity

name: xtype: intLOC: 300

41

memory location 300

Computation Data Storage

name: ytype: intLOC: 304

42

memory location 304

Last time

variables ~ boxes

But what does all this stuff look like ?

Giving names to data

def flipside(s): """ flipside(s): swaps s's sides! input s: a string """ x = len(s)/2 return s[x:] + s[:x]

This idea is the key to your happiness!

Hey - I'm happy about this, too!

Why would computers "prefer" the top version, too?

def flipside(s): x = len(s)/2 return s[x:] + s[:x]

def flipside(s): return s[len(s)/2:] + s[:len(s)/2]

Use variables!

Avoid this approach…

control-b in Sublime

Test!def flipside(s): """ flipside(s): swaps s's sides! input s: a string """ x = len(s)/2 return s[x:] + s[:x]

## Tests!#print "flipside('carpets') ~", flipside('carpets')print "flipside('carpets') ~", flipside('carpets') print "flipside('carpets') ~", flipside('carpets') print "flipside('carpets') ~", flipside('carpets') print "flipside('carpets') ~", flipside('carpets')

(1) function definition

(2) function tests

We provide these tests (for now…)

but don't test like this!

def convertFromSeconds(s): # total seconds """ convertFromSeconds(s): Converts an integer # of seconds into a list of [days, hours, minutes, seconds] input s: an int """ seconds = s % 60 # leftover seconds m = s / 60 # total minutes minutes = m % 60 # leftover minutes h = m / 60 # total hours hours = h % 24 # leftover hours days = h / 24 # total days return [days, hours, minutes, seconds]

This program uses variables

constantly!Using variables…

def convertFromSeconds(s): # total seconds """ convertFromSectons(s): Converts an integer # of seconds into a list of [days, hours, minutes, seconds] input s: an int """ seconds = s % 60 # leftover seconds m = (s / 60) # total minutes minutes = m % 60 # leftover minutes h = m / 60 # total hours hours = h % 24 # leftover hours days = h / 24 # total days return [days, hours, minutes, seconds]

How functions look…

docstring

comments –these are mostly optional in CS 5

code block

return statement

name input(s)

Computation's Dual Identity

name: xtype: intLOC: 300

41

memory location 300

Computation Data Storage

name: ytype: intLOC: 304

42

memory location 304

variables ~ boxes

accessed through functions…

Functions!

It's no coincidence this starts with fun!

Functioning across disciplines

def g(x): return x**100 g(x) = x

100

CS's googolizer Math's googolizerdefined by what it does defined by what it is

+ how efficiently it works

procedure structure

How functions work…

def f(x): return 11*g(x) + g(x/2)

What is demo(-4) ?

def demo(x): return x + f(x)

def g(x): return -1 * x

I might have a guess…

Quiz First and last name(s):

-4

How functions work…

def f(x): return 11*g(x) + g(x/2)

>>> demo(-4) ?

def demo(x): return x + f(x)

demox = -4

return -4 + f(-4)

def g(x): return -1 * x

Hey! This must be a stack-frame frame!

stack frame

def f(x): return 11*g(x) + g(x/2)

def demo(x): return x + f(x)

demox = -4

return -4 + f(-4)

fx = -4

return 11*g(x) + g(x/2)def g(x): return -1 * x

>>> demo(-4) ?

How functions work…

stack frame

stack frame

def f(x): return 11*g(x) + g(x/2)

def demo(x): return x + f(x)

demox = -4

return -4 + f(-4)

fx = -4

return 11*g(x) + g(x/2)def g(x): return -1 * x

>>> demo(-4) ?

How functions work…

These are distinct memory locations both holding x's.

stack frame

stack frame

def f(x): return 11*g(x) + g(x/2)

def demo(x): return x + f(x)

demox = -4

return -4 + f(-4)

f

g

x = -4

return 11*g(-4) + g(-4/2)

x = -4

return -1.0 * x

def g(x): return -1 * x

>>> demo(-4) ?

How functions work…

stack frame

stack frame

stack frame

def f(x): return 11*g(x) + g(x/2)

def g(x): return -1 * x

def demo(x): return x + f(x)

demox = -4

return -4 + f(-4)

f

g

x = -4

return 11* 4 + g(-4/2)

x = -4

return -1 * -4 4>>> demo(-4) ?

How functions work…

done!

stack frame

stack frame

def f(x): return 11*g(x) + g(x/2)

def g(x): return -1 * x

def demo(x): return x + f(x)

demox = -4

return -4 + f(-4)

fx = -4

return 11* 4 + g(-4/2)

>>> demo(-4) ?

How functions work…

the "return value"

stack frame

stack frame

def f(x): return 11*g(x) + g(x/2)

def g(x): return -1 * x

def demo(x): return x + f(x)

demox = -4

return -4 + f(-4)

f

g

x = -4

return 11* 4 + g(-4/2)

x = -2

return -1 * -2 2>>> demo(-4) ?

How functions work…

These are distinct memory locations both holding x's – and now they also have different values!!

stack frame

stack frame

def f(x): return 11*g(x) + g(x/2)

def g(x): return -1 * x

def demo(x): return x + f(x)

demox = -4

return -4 + f(-4)

fx = -4

return 11* 4 + 2

>>> demo(-4) ?

How functions work…

the "return value"

stack frame

stack frame

def f(x): return 11*g(x) + g(x/2)

def g(x): return -1 * x

def demo(x): return x + f(x)

demox = -4

return -4 + f(-4)

fx = -4

return 11* 4 + 2 46

>>> demo(-4) ?

How functions work…

stack frame

def f(x): return 11*g(x) + g(x/2)

def g(x): return -1 * x

def demo(x): return x + f(x)

demox = -4

return -4 + 46

42>>> demo(-4) 42

How functions work…

stack frame

Function stacking

def f(x): return 11*g(x) + g(x/2)

def g(x): return -1 * x

def demo(x): return x + f(x)

demox = -4

return -4 + f(-4)

f

g

x = -4

return 11* 4 + g(-4/2)

x = -2

return -1 * -2 2

(1) keeps separate variables for each function call…

(2) remembers where to send results back to…

"The stack"is a memory area that

the stack

stack frame

return > print

>>> ans = dbl(21)

def dbl(x): """ dbls x? """ return 2*x

def dblPR(x): """ dbls x? """ print 2*x

>>> ans = dblPR(21)

>>> ans = dbl(21)

def dbl(x): """ dbls x? """ return 2*x

def dblPR(x): """ dbls x? """ print 2*x

>>> ans = dblPR(21)

return yields the function call's value …

print just prints stuff to the screen...… which the

shell then prints!

return > print

Function design

Thinking sequentially

5 ! = 5 * 4 * 3 * 2 * 1

N ! = N * (N-1) * (N-2) * … * 3 * 2 * 1

factorial

5 ! = 120

factorial

5 ! = 5 * 4 * 3 * 2 * 1

N ! = N * (N-1) * (N-2) * … * 3 * 2 * 1

5 ! = 120

March + beyond…

Thinking sequentially

Recursion == self-reference!

5 ! =

N ! =

Thinking recursively

5 ! = 5 * 4 * 3 * 2 * 1

N ! = N * (N-1) * (N-2) * … * 3 * 2 * 1

factorial

5 ! = 120

Warning: this is legal!

def fac(N): return N * fac(N-1)

I wonder how this code will STACK up!?

def fac(N): return N * fac(N-1)

The calls to fac will never stop: there's no BASE CASE!

Make sure you have a base case, then worry about the recursion...

legal != recommended

def fac(N): return fac(N)

Roadsigns and recursionexamples of self-fulfilling danger

This runs ~ but does not help!

Recursion's advantage: It handles arbitrary structural depth – all

at once!

As a hat, I'm recursive, too!

The dizzying dangers of having no base case!

def fac(N):

if N <= 1: return 1

Thinking recursively

Base case

def fac(N):

if N <= 1: return 1

Thinking recursively

Base case

"How could I use the factorial of anything smaller than N?" Then do!Ask yourself:

def fac(N):

if N <= 1: return 1

else: return N*fac(N-1)

Recursive case

(shorter)

Human: Base case and 1 step Computer: Everything else

Base case

Thinking recursively

def fac(N):

if N <= 1: return 1

else: rest = fac(N-1) return rest * N

Recursive case

(clearer, for some)

Human: Base case and 1 step Computer: Everything else

Base case

Thinking recursively

Behind the curtain…

fac(5)

def fac(N):

if N <= 1: return 1

else: return N * fac(N-1)

fac(5)

5 * fac(4)

Behind the curtain…

def fac(N):

if N <= 1: return 1

else: return N * fac(N-1)

fac(5)

5 * fac(4)

4 * fac(3)

Behind the curtain…

def fac(N):

if N <= 1: return 1

else: return N * fac(N-1)

5 *

Operation waiting …

fac(5)

5 * fac(4)

4 * fac(3)

3 * fac(2)

Behind the curtain…

def fac(N):

if N <= 1: return 1

else: return N * fac(N-1)

5 *

5 * 4 *

More operations waiting…

fac(5)

5 * fac(4)

4 * fac(3)

3 * fac(2)

2 * fac(1)

Behind the curtain…

def fac(N):

if N <= 1: return 1

else: return N * fac(N-1)

5 *

5 * 4 *

5 * 4 * 3 *

fac(5)

5 * fac(4)

4 * fac(3)

3 * fac(2)

2 * fac(1)

1

"The Stack"

Stack frames hold all of the

individual calls to fac

Behind the curtain…

def fac(N):

if N <= 1: return 1

else: return N * fac(N-1)

N=5

N=4

N=3

N=2

N=1

5 different N's are

living in memory…

5 *

5 * 4 *

5 * 4 * 3 *

5 * 4 * 3 * 2 *

fac(5)

5 * fac(4)

4 * fac(3)

3 * fac(2)

2 * 1

Behind the curtain…

def fac(N):

if N <= 1: return 1

else: return N * fac(N-1)

5 *

5 * 4 *

5 * 4 * 3 *

fac(5)

5 * fac(4)

4 * fac(3)

3 * 2

Behind the curtain…

def fac(N):

if N <= 1: return 1

else: return N * fac(N-1)

5 *

5 * 4 *

fac(5)

5 * fac(4)

4 * 6

Behind the curtain…

def fac(N):

if N <= 1: return 1

else: return N * fac(N-1)

5 *

fac(5)

5 * 24

Behind the curtain…

def fac(N):

if N <= 1: return 1

else: return N * fac(N-1)

fac(5)

Result: 120

0 x*** -> N 0

0 N*** -> X 1Look familiar?

Recursive step

Base case

show facWPR …

Behind the curtain…

def fac(N):

if N <= 1: return 1

else: return N * fac(N-1)

Thinking recursively…

What will print when facWPR(5) is called?

def fac(N): if N <= 1: return 1 else: rest = fac(N-1) return rest * N

You handle the base case – the easiest case!

Recursion does almost all of the rest of the problem!

You specify one step at the end

Let recursion do the work for you.

Exploit self-similarity

Produce short, elegant codeLess work !

But you do need to do one step yourself…

def fac(N):

if N <= 1: return 1 else: return fac(N)

This will not work !

Nature prefers recursion, too!

Recursion's challenge?You need to see BOTH the self-similar pieces AND the whole thing simultaneously!

Yes... and no.Are these rules for real?

Dragon's-blood Tree

There still has to be a base case…

or else!

Recursive design…

(2) Find the self-similarity.

(1) Program the base case.

(3) Do one step!

(4) Delegate the rest to recursion…

fun! easy!?

cool!

Aha!

indexing and slicing

One step? …is easy to do with Python

s = 'aliens'How do we get at the initial character of s?

L = [ 42, 21 ]

How do we get at ALL THE REST of s?

s[0]

L[0]

s[ ]

L[ ]How do we get at the initial element of L?

How do we get at ALL THE REST of L?

'liens'

[ 21 ]

Recursive design #1

def mylen(s):

""" input: any string, s

output: the number of characters in s

"""

if :

else:base case test!

'cs5'

"How could I make use of the length of something smaller than s?" Then do!

Ask yourself:

return

return

… complete

def mylen(s):

""" input: any string, s

output: the number of characters in s

"""

if s == '':

return 0

else:

return 1 + mylen(s[1:])

There's not much len left here!

mylen('cs5')

Behind the curtain:how recursion works...

def mylen(s):

if s == '':

return 0

else:

return 1 + mylen(s[1:])

1 + mylen('s5')

1 + 1 + mylen('5')

1 + 1 + 1 + mylen('')

1 + 1 + 1 + 0

Looking behind the curtain…

http://www.pythontutor.com/visualize.html

Design #2

def mymax(L):

""" input: a NONEMPTY list, L

output: L's maximum element

"""

if :

elif :base case test!

another case…

len(L)==1

[1,4,3,42,-100,7]

return

return

return

else:

def mymax(L):

""" input: a NONEMPTY list, L

output: L's maximum element

"""

if len(L) == 1:

return L[0]

elif L[0] < L[1]:

return mymax( L[1:] )

else:

return mymax( L[0:1] + L[2:] )

Hey - do I get a slice?!

Design #2

mymax( [1,4,3,42,-100,7] )

def mymax(L):

if len(L) == 1:

return L[0]

elif L[0] < L[1]:

return mymax( L[1:] )

else:

return mymax( L[0:1]+L[2:] )

mymax( [4,3,42,-100,7] )

mymax( [4,42,-100,7] )

mymax( [42,-100,7] )

mymax( [42,7] )

mymax( [42] )

42

base case

drop 1st

drop 2nd

Try it!

def power(b,p):

Handle negative values of p in an elif.

""" returns b to the p power Use recursion, not ** Inputs: int b, int p: the base and the power"""

Want more power?

power(2,5) == 32.0

For example, power(5,-1) == 0.2

def sajak(s):

sajak('wheel of fortune') == 6

What 7-letter English word w maximizes sajak(w) ?

What about y? You decide…

""" returns the number of vowels in the input string, s"""

Want more Pat?

if :

if s == '':Base

case test

elif

else:

p == 0

return

else:

return

return

return

return

Base case test

elif

in general:

power( 2, 5 )

2* power( 2, 4 )

2* 2* power( 2, 3 )

2* 2* 2* power( 2, 2 )

2* 2* 2* 2* power( 2, 1 )

2* 2* 2* 2* 2* power( 2, 0 )

2* 2* 2* 2* 2* 1

32

sajak( 'eerier' )

1+ sajak( 'erier' )

1+ 1+ sajak( 'rier' )

1+ 1+ 0+ sajak( 'ier' )

1+ 1+ 0+ 1+ sajak( 'er' )

1+ 1+ 0+ 1+ 1+ sajak( 'r' )

1+ 1+ 0+ 1+ 1+ 0+ sajak( '' )

1+ 1+ 0+ 1+ 1+ 0+ 0 4

def power(b,p): """ inputs: base b and power p (an int)

implements: b**p

"""

if p == 0:

return 1.0

elif p < 0:

return ____________________

else:

return b * power(b,p-1)

Recursion is power!

# of vowels

in ssajak(s):

Base case? When there are no letters, there are ZERO vowels

if s[0] is NOT a vowel, the answer is

Rec. step? Look at the initial character.

if s[0] is a vowel, the answer is

D

E

S

I

G

N

sajak( s[1:] )

1 + sajak( s[1:] )

def sajak(s):

if s == '':

return 0

elif s[0]=='a' or s[0]=='e' or…

but how to check for vowels?

Is s[0] a vowel?

Python is… in

>>> 'i' in 'team'False

>>> 'cs' in 'physics'True

>>> 42 in [41,42,43]True

>>> 42 in [[42], '42']False

I guess Python's the in thing

>>> 'i' in 'alien'True >>> 3*'i' in 'alien'

False

def sajak(s):

if len(s) == 0:

return 0

elif s[0] in 'aeiou':

return 1 + sajak(s[1:])

else:

return 0 + sajak(s[1:])

if s[0] is NOT a vowel, the answer is just

the number of vowels in the rest of s

if s[0] IS a vowel, the answer is

1 + the # of vowels in the rest of s

Base Case

Recursive Cases

let's input 'eerier' for s

The key to understanding recursion is, first, to understand recursion.

- a former CS 5 student

tutors @ LAC W/Th/F/Sa/Su

Good luck with

Homework #1

It's the eeriest!

Nature prefers recursion, too!

Recursion's challenge?You need to see BOTH the self-similar pieces AND the whole thing simultaneously!

Yes... and no.Are these rules for real?

Dragon's-blood Tree

There still has to be a base case…

or else!