Understanding recursion in Python 2 (Think Python, exercise 5) - python

I'm going through Think Python and I've reached recursion which is turning to be a great pain to understand for me.
There's this exercise, number 5, that shows me this piece of code:
def draw(t, length, n):
if n == 0:
return
angle = 50 #sets angle
fd(t, length*n) #make a turtle() "t" go forward length*n pixels while drawing
lt(t, angle) #makes turtle "t" turn left on itself "angle" (50) degrees
draw(t, length, n-1) #1st call
rt(t, 2*angle) #makes turtle "t" turn right "2*angle" (100) degrees
draw(t, length, n-1) #2nd call
lt(t, angle) #makes turtle "t" turn left "angle" (50) degrees
bk(t, length*n) #makes turtle "t" go backwards length*n pixels
And asks me to think of what it does and then run it. I ran it and I had trouble understanding why it does what it does.
It is a much more complex case of recursion that the ones the books presented for explaining this device and I cannot understand it.
Lets make n for example 2 in order to understand a simple instance of this problem:
What I can make out is that the code calls itself until n=0 up to the first call consecutively, then returns the control to n=1 and makes the remaining lines of code from call 1 to call 2. It makes the second call with n=0 and returns but I cannot understand what instance of the function it returns the control of the program.
I'd be glad if someone could point me in the right direction as how to think this kind of recursive code by myself, how can I make use of it (when a for statement wouldn't quite make it) and a way to schematize the way it works (with some sort of diagram, for example?).
I have this:
function called with n=2
function called with n=1
function called with n=0; returns to:
function called with n=1 makes the 2nd call to the function with n=0
function called with n=0; returns to where?
??????
As you can see it is quite impractical for, let's say, a function call with n = 7.

A function always returns directly to its caller. Your recursive function does some work, calls itself, then when the call returns, does some more work, then calls itself another time, then when that returns, does some final work, before the function ends and itself returns:
work
call
work
call
work
return
That is, unless n == 0 is true, then the function immediately returtns. Every recursive call subtracts 1 from n so as long as n was positive to start with, your recursion ends at some point.
Recursion is simply the act of running the same function again, so you can substitute each call in the above 'diagram' with the same jobs being executed. Lets do this once:
n = 2
work
n = 1
work
call
work
call
work
work
n = 1
work
call
work
call
work
return
work
return
I've added in the value for n, provided we start with n = 2. Of course, once you get down to n = 0, the call immediately returns; we can fill that in too:
n = 2
work
n = 1
work
n = 0
return
work
n = 0
return
work
return
work
n = 1
work
n = 0
return
work
n = 0
return
work
return
work
return
Now we have the full call tree for your recursive function, for n = 2. For higher values of n, just keep indenting and filling in the work - call - work - call - work - return lines anywhere there is a call line for the previous level, and you can build a full call tree for any recursive function.

So I've met the same issue to understand this exercice and i think there is nothing better than a schema or a picture to easily understand it , so here is my explanation for the first iteration of the code (using this same logic you'll understand the rest of the code easily) :

Related

How to apply recursion function in land subdivision?

I've made a subdivision code that allows division of a polygon by bounding box method. subdivision(coordinates) results in subblockL and subblockR (left and right). If I want to repeat this subdivision code until it reaches the area less than 200, I would need to use recursion method.
ex:
B = subdivision(A)[0], C = subdivision(B)[0], D = subdivision(C)[0]... until it reaches the area close to 200. (in other words,
subdivision(subdivision(subdivision(A)[0])[0])[0]...)
How can I simplify repetition of subdivision? and How can I apply subdivision to every block instead of single block?
while area(subdivision(A)[0]) < 200:
for i in range(A):
subdivision(i)[0]
def sd_recursion(x):
if x == subdivision(A):
return subdivision(A)
else:
return
I'm not sure what function to put in
"What function to put in" is the function itself; that's the definition of recursion.
def sd_recursive(coordinates):
if area(coordinates) < 200:
return [coordinates]
else:
a, b = subdivision(coordinates)
return sd_recursive(a) + sd_recursive(b) # list combination, not arithmetic addition
To paraphrase, if the area is less than 200, simply return the polygon itself. Otherwise, divide the polygon into two parts, and return ... the result of applying the same logic to each part in turn.
Recursive functions are challenging because recursive functions are challenging. Until you have wrapped your head around this apparently circular argument, things will be hard to understand. The crucial design point is to have a "base case" which does not recurse, which in other words escapes the otherwise infinite loop of the function calling itself under some well-defined condition. (There's also indirect recursion, where X calls Y which calls X which calls Y ...)
If you are still having trouble, look at one of the many questions about debugging recursive functions. For example, Understanding recursion in Python
I assumed the function should return a list in every case, but there are multiple ways to arrange this, just so long as all parts of the code obey the same convention. Which way to prefer also depends on how the coordinates are represented and what's convenient for your intended caller.
(In Python, ['a'] + ['b'] returns ['a', 'b'] so this is not arithmetic addition of two lists, it's just a convenient way to return a single list from combining two other lists one after the other.)
Recursion can always be unrolled; the above can be refactored to
def sd_unrolled(coordinates):
result = []
while coordinates:
if area(coordinates[0]) < 200:
result.extend(coordinates[0])
coordinates = coordinates[1:]
a, b = subdivision(coordinates[0])
coordinates = [a, b] + coordinates[1:]
return result
This is tricky in its own right (but could perhaps be simplified by introducing a few temporary variables) and pretty inefficient or at least inelegant as we keep on copying slices of the coordinates list to maintain the tail while we keep manipulating the head (the first element of the list) by splitting it until each piece is small enough.

How to multiply without the * sign using recursion?

so as homework for a programming class on python we're supposed to multiply to integers (n,m) with each other WITHOUT using the * sign (or another multiplication form). We're supposed to use recursion to solve this problem, so i tried just adding n with itself, m number of times. I think my problem is with using recursion itself. I have searched on the internet for recursion usage, no results. Here is my code. Could someone point me in the right direction?
def mult(n,m):
""" mult outputs the product of two integers n and m
input: any numbers
"""
if m > 0:
return n + n
return m - 1
else:
return 1
I don't want to give you the answer to your homework here so instead hopefully I can provide an example of recursion that may help you along :-).
# Here we define a normal function in python
def count_down(val):
# Next we do some logic, in this case print the value
print(val)
# Now we check for some kind of "exit" condition. In our
# case we want the value to be greater than 1. If our value
# is less than one we do nothing, otherwise we call ourself
# with a new, different value.
if val > 1:
count_down(val-1)
count_down(5)
How can you apply this to what you're currently working on? Maybe, instead of printing something you could have it return something instead...
Thanks guys, i figured it out!!!
i had to return 0 instead of 1, otherwise the answer would always be one higher than what we wanted.
and i understand how you have to call upon the function, which is the main thing i missed.
Here's what i did:
def mult(n,m):
""" mult outputs the product of two integers n and m
input: any numbers
"""
if m == 0:
return 0
else:
return n + mult(n, m - 1)
You have the right mechanics, but you haven't internalized the basics you found in your searches. A recursive function usually breaks down to two cases:
Base Case --
How do you know when you're done? What do you want to do at that point?
Here, you've figured out that your base case is when the multiplier is 0. What do you want to return at this point? Remember, you're doing this as an additive process: I believe you want the additive identity element 0, not the multiplicative 1.
Recursion Case --
Do something trivial to simplify the problem, then recur with this simplified version.
Here, you've figured out that you want to enhance the running sum and reduce the multiplier by 1. However, you haven't called your function again. You haven't properly enhanced any sort of accumulative sum; you've doubled the multiplicand. Also, you're getting confused about recursion: return is to go back to whatever called this function. For recursion, you'll want something like
mult(n, m-1)
Now remember that this is a function: it returns a value. Now, what do you need to do with this value? For instance, if you're trying to compute 4*3, the statement above will give you the value of 4*2, What do you do with that, so that you can return the correct value of 4*3 to whatever called this instance? You'll want something like
result = mult(n, m-1)
return [...] result
... where you have to fill in that [...] spot. If you want, you can combine these into a single line of code; I'm just trying to make it easier for you.

How to Break Infinite Loop in Turtle Graphics Python

I wrote the code for an assignment which completes the task required. Which is to draw the shape of a polygon from user input and draw the amount of shapes per side number specified. The only problem is after the shape is drawn the arrow just keeps tracing through in an infinite loop. I tried using break at the end but it did not work.
from turtle import *
def polygon(n, length):
Screen()
shape('turtle')
mode('logo')
n = input ("Enter number of sides ")
print ("you entered ", n)
length = input("Enter the length of sides ")
print ("you entered ", length)
n=int(n)
length=int(length)
for side in range(n):
forward(length)
right(360/n)
while side in range(n):
right(360/n)
for side in range(n):
forward(length)
right(360/n)
What I have so far will technically work for the assignment, however the infinite loop at the end is annoying me.
The main problem is that the while loop goes for an infinite amount of time.
#This is infinite loop because 'side' iterator is ALWAYS in the sequence returned from range function
while side in range(n):
Also, with the current structure
of your code the function does nothing and only wastes space (you probably call it from the shell which is
understandable). There's a few more redundancies that we can get ride of too. Lets design your script so that the turtle's
polygons can be controlled from the function you created. Hopefully you'll see how powerful the turtle module
can be when utilized with recursion and a proper use of functions.
Lets look at the declarion of your polygon function 1st. The reason I feel your script should revolve around your
polygon function aside from the natural convience of functions is because of the parameters you included in the script.
Although they are not needed (here atleast) per the implied design of your script, the inclusion of them implies A: You
intended for this function to control the turtle, or B: You don't quite understand how functions/parameters work. To
offer more of a learning experience we should definitely focus this script around that function in either case.
def polygon(n,length): #<--- get ride of 'n' & 'length' parameters
def polygon(n=None,length=None): #<---These are defualt values if you wish to go with that direction
def polygon(): #<---This is the declaration I'll follow for aiding your script
Get rid of the paramaters for now. We'll bring them back in a nested function later. Next we're going to add the rest
of the script to the polygon function. Because your n and length variable collect input, it renders the parameters
for the polygon function useless. It's not an either or scenerio, with some control flow you can have both if you
wanted. Before we add the script to our polygon function I'd like to point out how you declared the variables twice, the
second time you converted them to integers. Python allows us to nest them in a int() function the 1st time we declare
them.
n = input("Enter num ")
n = int(n) #<---instead of these 1st 2 lines, do the 3rd line below.
n = int(input("Enter num: ")) #<--1 line of code that is equally as readable as 2.
After modifying both the n & length variables, lets add everything into our polygon function (except the while loop,
get rid of everything involved with that). Notice that the Screen,shape, and mode functions have been moved below the
variable declarions. This is so the turtle window does not jump in front of the user while they're inputing information
into the program.
def polygon():
n = int(input("Enter number of sides: "))
print("You entered %d sides.\n"%(n))
length = int(input("Enter length of sides: "))
print("Your sides are %d pixels long.\n"%(length))
Screen()
shape('turtle')
mode('logo')
Now that we have a clean and readable function lets handle our business with creating polygons. For this we'll use
a nested function that utilizes both recursion and parameters. We'll call it 'looper'. The reason being is that your
assignment is to make an equal amount of polygons that there are sides (in otherwords, num of polygons == n). looper will
achieve that for us. 1st it will take in the variables established in polygon as parameters. Then we'll use your previous
for loop inside.
def looper(n,length,loops=n): #notice the 'loops=n' default parameter, this allows to keep track of it recursively
if (loops > 0): #As long as loops is greater than zero this functin will repeat itself as many times as 'n'
for side in range(n):
forward(length)
right(360/n)
penup()
#penup after the forloop so that the turtle will not draw while searching for next polygon space
setposition(xcor()+length,ycor()+length) #xcor() and ycor() return the current position of the turtle
#notice that we add it to the length of of our sides, this is how the turtle will space out the polys.
#I would even experiment with things like setposition(xcor()+(length*2),ycor()+(length*2))
pendown() #after turtle find the position we we use pendown() to prepare to draw again
loops -= 1 #this decrements the loops parameter so that the functin will not call itself infinitely
#(stack overflow)
looper(n,length,loops) #recursively call our looper function again
return #I personally always return the end of recursive functions to be safe, this may be redundant
Essentially recursion is when a function calls itself within itself repeatedly to perform a task. To make sure that it
eventually ends we tell the program: "Only draw polygons if there are any loops" furthermore after the functions performs
it's duties we tell it "subtract loops by 1" to make sure that the loops will eventually be zero. This and the return
statement (a rough equivalent to what you were referring to as 'break') will assure us that we do not perfom tasks
an infinite amount of times. The last step in this code is to make sure that you actually call the polygon function
so your code will run AND to also call looper(n,length) and the end of your polygon function for the same reason.
Your code should look something like this:
from turtle import *
def polygon():
n = int(input("Enter number of sides: "))
print("You entered %d sides.\n"%(n))
length = int(input("Enter length of sides: "))
print("Your sides are %d pixels long.\n"%(length))
Screen()
shape('turtle')
mode('logo')
def looper(n,length,loops=n):
if (loops > 0):
for side in range(n):
forward(length)
right(360/n)
penup()
setposition(xcor()+length,ycor()+length)
pendown()
loops -= 1
looper(n,length,loops)
return
looper(n,length)
polygon()
I pretty much did the assignment for you, but if you learned a thing or two then my goal is achieved. I hope I helped any!

Recursion not breaking

I am trying to solve Euler problem 18 where I am required to find out the maximum total from top to bottom. I am trying to use recursion, but am stuck with this.
I guess I didn't state my problem earlier. What I am trying to achieve by recursion is to find the sum of the maximum number path. I start from the top of the triangle, and then check the condition is 7 + findsum() bigger or 4 + findsum() bigger. findsum() is supposed to find the sum of numbers beneath it. I am storing the sum in variable 'result'
The problem is I don't know the breaking case of this recursion function. I know it should break when it has reached the child elements, but I don't know how to write this logic in the program.
pyramid=[[0,0,0,3,0,0,0,],
[0,0,7,0,4,0,0],
[0,2,0,4,0,6,0],
[8,0,5,0,9,0,3]]
pos=[0,3]
def downleft(pyramid,pos):#returns down left child
try:
return(pyramid[pos[0]+1][pos[1]-1])
except:return(0)
def downright(pyramid,pos):#returns down right child
try:
return(pyramid[pos[0]+1][pos[1]+1])
except:
return(0)
result=0
def find_max(pyramid,pos):
global result
if downleft(pyramid,pos)+find_max(pyramid,[pos[0]+1,pos[1]-1]) > downright(pyramid,pos)+find_max(pyramid,[pos[0]+1,pos[1]+1]):
new_pos=[pos[0]+1,pos[1]-1]
result+=downleft(pyramid,pos)+find_max(pyramid,[pos[0]+1,pos[1]-1])
elif downright(pyramid,pos)+find_max(pyramid,[pos[0]+1,pos[1]+1]) > downleft(pyramid,pos)+find_max(pyramid,[pos[0]+1,pos[1]-1]):
new_pos=[pos[0]+1,pos[1]+1]
result+=downright(pyramid,pos)+find_max(pyramid,[pos[0]+1,pos[1]+1])
else :
return(result)
find_max(pyramid,pos)
A big part of your problem is that you're recursing a lot more than you need to. You should really only ever call find_max twice recursively, and you need some base-case logic to stop after the last row.
Try this code:
def find_max(pyramid, x, y):
if y >= len(pyramid): # base case, we're off the bottom of the pyramid
return 0 # so, return 0 immediately, without recursing
left_value = find_max(pyramid, x - 1, y + 1) # first recursive call
right_value = find_max(pyramid, x + 1, y + 1) # second recursive call
if left_value > right_value:
return left_value + pyramid[y][x]
else:
return right_value + pyramid[y][x]
I changed the call signature to have separate values for the coordinates rather than using a tuple, as this made the indexing much easier to write. Call it with find_max(pyramid, 3, 0), and get rid of the global pos list. I also got rid of the result global (the function returns the result).
This algorithm could benefit greatly from memoization, as on bigger pyramids you'll calculate the values of the lower-middle areas many times. Without memoization, the code may be impractically slow for large pyramid sizes.
Edit: I see that you are having trouble with the logic of the code. So let's have a look at that.
At each position in the tree you want to make a choice of selecting
the path from this point on that has the highest value. So what
you do is, you calculate the score of the left path and the score of
the right path. I see this is something you try in your current code,
only there are some inefficiencies. You calculate everything
twice (first in the if, then in the elif), which is very expensive. You should only calculate the values of the children once.
You ask for the stopping condition. Well, if you reach the bottom of the tree, what is the score of the path starting at this point? It's just the value in the tree. And that is what you should return at that point.
So the structure should look something like this:
function getScoreAt(x, y):
if at the end: return valueInTree(x, y)
valueLeft = getScoreAt(x - 1, y + 1)
valueRight = getScoreAt(x + 1, y + 1)
valueHere = min(valueLeft, valueRight) + valueInTree(x, y)
return valueHere
Extra hint:
Are you aware that in Python negative indices wrap around to the back of the array? So if you do pyramid[pos[0]+1][pos[1]-1] you may actually get to elements like pyramid[1][-1], which is at the other side of the row of the pyramid. What you probably expect is that this raises an error, but it does not.
To fix your problem, you should add explicit bound checks and not rely on try blocks (try blocks for this is also not a nice programming style).

Fermat's little Theorem python

i am trying to implement Ferment's little Theorem via python. The value that returns does not give me a prime however. Any help is appreciated.
Apologies, the theorem states that in which for a random number of of times if a number is prime then any number generated less then it would give pow(a,value,x) == 1. The code below is an implementation of it.
The purpose of the code would be for function generate bit to create a 16 bit integer and run it via the theorem to prove if its a prime or not, if its a prime,return the value, if not call the function generatebit() again. Thank you for your time taken
import random
def generatebit():
x = random.getrandbits(16)
x = int(x)
if little(x):
return x
def little(x):
value = x -1
for i in xrange(50000):
# check for a total of 50000 times to reduce chances
a = random.getrandbits(15)
if pow(a,value,x) != 1:
generatebit()
break
return True
a=generatebit()
print a
Not knowing what the theorem is (see my comment), I can still tell you that there are some issues in your code.
you first call generatebits, which generates a random number. then if little(x), you return that value. Since however little(x) is always true, what this code does is create a random value and return it
Whatever happens within you for loop is totally without effect. all you do is assign a value to a variable a that never gets read, and call a function that returns a value you don't read

Categories

Resources