How do I locate the recursion conditions? - python

My code is as follows.
I tried coding out for each case first, so given n = 4, my code looks like this:
a = overlay_frac(0,blank_bb,scale(1/4,rune))
b = overlay_frac(1/4,blank_bb,scale(1/2,rune))
c = overlay_frac(1/2,blank_bb,scale(3/4,rune))
d = overlay_frac(3/4,blank_bb,scale(1,rune))
show (overlay(a,(overlay(b,(overlay(c,d))))))
My understanding is that the recursion pattern is:
a = overlay_frac((1/n)-(1/n),blank_bb,scale(1/n,rune))
b = overlay_frac((2/n)-(1/n),blank_bb,scale(2/n,rune))
c = overlay_frac((3/n)-(1/n),blank_bb,scale(3/n,rune))
d = overlay_frac((4/n)-(1/n),blank_bb,sale(4/n,rune))
Hence, the recursion pattern that I came up with is:
def tree(n,rune):
if n==1:
return rune
else:
for i in range(n+1):
return overlay(overlay_frac(1-(1/n),blank_bb,scale(i/n,rune)),tree(n-1,rune))
When I hardcode this, everything turns out just fine, but I suspect I'm not doing the recursion properly. Where have I gone wrong?

You are in fact trying to do an iteration within a recursive call. In stead of using loop, you can use an inner function to memorize your status. The coefficient you defined is actually changed with both n and i, but for a given n it changed with i only. The status you need to memorize with inner function is then i, which is the same as you looping through i.
You can still achieve your goal by doing so
def f(i, n):
return overlay_frac((i/n)-(1/n),blank_bb,scale(i/n,rune))
# for each iteration, you check if i is equal to n
# if yes, return the result (base case)
# otherwise, you apply next coefficient to the previous result
# you start with i = 0 and increase by one every iteration until i reach to n (base case)
# notice how similar this recursive call looks like a loop
# the only difference is the status are updated within the function call itself
# therefore you will not have the problem of earlier return
def recursion(n):
def iteration(i, out):
if i == n:
return out
else:
return iteration(i+1, overlay(f(n-1, n), out))
return iteration(0, f(n, n))
Here, n is assumed to be the times of overlay you want to apply. When n = 0, no function applied on the last coefficient f(n, n). When n = 1, the output would be overlay applied once on coefficient with i = n - 1 and coefficient with i = n.
This way avoids the earlier return inside your loop.
In fact you can omit the inner function by adding additional argument to your outer function. Then you need to assign the default initial i. The inner function is not really necessary here. The key is to use the function argument to memorize the status (variable i in this case).
def f(i, n):
return overlay_frac((i/n)-(1/n),blank_bb,scale(i/n,rune))
def recursion(n, i=0):
if i == n:
return f(n, n)
else:
return overlay(f(n-1, n), recursion(n, i+1))

Your first two code blocks don't correspond to the same operations. This would be equivalent to your first block (in Python 3).
def overlayer(n, rune):
def layer(k):
# Scale decreases linearly with k
return overlay_frac((1 - (k+1)/n), blank_bb, scale(1-k/n, rune))
result = layer(0)
for i in range(1, n):
# Overlay on top of previous layers
result = overlay(layer(i), result)
return result
show(overlayer(4, rune))

Let's look at your equations again:
a = overlay_frac(0,blank_bb,scale(1/4,rune))
b = overlay_frac(1/4,blank_bb,scale(1/2,rune))
c = overlay_frac(1/2,blank_bb,scale(3/4,rune))
d = overlay_frac(3/4,blank_bb,scale(1,rune))
show (overlay(a,(overlay(b,(overlay(c,d))))))
What you wrote as "recursion" is not a recursion formula. If you compare your formulas for the recursion with the ones you gave us, you can infer n=4 which makes no sense. For a recursion pattern you need to describe your inner variables as a manifestation of the same expression with only a different parameter. That is, you should replace:
f_n = overlay_frac((1/4)*(n-1),blank_bb,sale(n/4,rune))
such that f_1=a, f_2=b etc...
Then your recursion fomula that you want to calculate translates to:
show (overlay(f_1,(overlay(f_2,(overlay(f_3,f_4))))))
You can write the function f_n as f(n) (and maybe other paramters) in your code and then do
def recurse(n):
if n == 4:
return f(4)
else:
return overlay(f(n),recurse(n+1))
then call:
show( recurse (1))
You need to assert that n<5and integer, otherwise you'll end up in an infinity loop.
There may still be some mistake, but it should be along those lines. Once you've actually written it like this however, it (maybe) doesn't really make sense to do a recursion anyways. If you only want to do it for n_max=4, that is. Just call the function in one line by replacing a,b,c,d with f_1,f_2,f_3,f_4

Related

Finding the Maximum Pyramidal Number by recursion in Python

I'm given the task to define a function to find the largest pyramidal number. For context, this is what pyramidal numbers are:
1 = 1^2
5 = 1^2 + 2^2
14 = 1^2 + 2^2 + 3^2
And so on.
The first part of the question requires me to find iteratively the largest pyramidal number within the range of argument n. To which, I successfully did:
def largest_square_pyramidal_num(n):
total = 0
i = 0
while total <= n:
total += i**2
i += 1
if total > n:
return total - (i-1)**2
else:
return total
So far, I can catch on.
The next part of the question then requires me to define the same function, but this time recursively. That's where I was instantly stunned. For the usual recursive functions that I have worked on before, I had always operated ON the argument, but had never come across a function where the argument was the condition instead. I struggled for quite a while and ended up with a function I knew clearly would not work. But I simply could not wrap my head around how to "recurse" such function. Here's my obviously-wrong code:
def largest_square_pyramidal_num_rec(n):
m = 0
pyr_number = 0
pyr_number += m**2
def pyr_num(m):
if pyr_number >= n:
return pyr_number
else:
return pyr_num(m+1)
return pyr_number
I know this is erroneous, and I can say why, but I don't know how to correct it. Does anyone have any advice?
Edit: At the kind request of a fellow programmer, here is my logic and what I know is wrong:
Here's my logic: The process that repeats itself is the addition of square numbers to give the pyr num. Hence this is the recursive process. But this isn't what the argument is about, hence I need to redefine the recursive argument. In this case, m, and build up to a pyr num of pyr_number, to which I will compare with the condition of n. I'm used to recursion in decrements, but it doesn't make sense to me (I mean, where to start?) so I attempted to recall the function upwards.
BUT this clearly isn't right. First of all, I'm sceptical of defining the element m and pyr_num outside of the pyr_num subfunction. Next, m isn't pre-defined. Which is wrong. Lastly and most importantly, the calling of pyr_num will always call back pyr_num = 0. But I cannot figure out another way to write this logic out
Here's a recursive function to calculate the pyramid number, based on how many terms you give it.
def pyramid(terms: int) -> int:
if terms <=1:
return 1
return terms * terms + pyramid(terms - 1)
pyramid(3) # 14
If you can understand what the function does and how it works, you should be able to figure out another function that gives you the greatest pyramid less than n.
def base(n):
return rec(n, 0, 0)
def rec(n, i, tot):
if tot > n:
return tot - (i-1)**2
else:
return rec(n, i+1, tot+i**2)
print(base(NUMBER))
this output the same thing of your not-recursive function.

Transforming a divide and conquer recursive algorithm into an iterative version

I would like to transform a recursive algorithm on an array into an iterative function. It is not a tail recursive algorithm and has two recursive calls followed by some operation.
The algorithm is a divide-and-conquer algorithm where at each step the array is split into two subarrays and some function f is applied to the two previous outcomes. In practice f is complicated, so the iterative algorithm should use the function f, for a minimal working example I have used a simple addition.
Below is a minimal working example of the recursive program in python.
import numpy as np
def f(left,right):
#In practice some complicated function of left and right
value=left+right
return value
def recursive(w,i,j):
if i==j:
#termination condition when the subarray has size 1
return w[i]
else:
k=(j-i)//2+i
#split the array into two subarrays between indices i,k and k+1,j
left=recursive(w,i,k)
right=recursive(w,k+1,j)
return f(left,right)
a=np.random.rand(10)
print(recursive(a,0,a.shape[0]-1))
Now if I want to write this iteratively I realize that I need a stack to store intermediate results, and that at each step I need to apply f to the two elements on the top of the stack. I am just not sure how to construct the order in which I put elements in the stack without recursion. Here is an attempt at a solution which is certainly not optimal since it seems there should be a way to remove the first loop and use only one stack:
def iterative(w):
stack=[]
stack2=[]
stack3=[]
i=0
j=w.shape[0]-1
stack.append((i,j))
while (i,j)!=(w.shape[0]-1,w.shape[0]-1):
(i,j)=stack.pop()
stack2.append((i,j))
if i==j:
pass
else:
k=int(np.floor((j-i)/2)+i)
stack.append((k+1,j))
stack.append((i,k))
while len(stack2)>0:
(i,j)=stack2.pop()
if i==j:
stack3.append(w[i])
else:
right=stack3.pop()
left=stack3.pop()
stack3.append(f(left,right))
return stack3.pop()
Edit : The real problem I am interested in has as input an array of tensors of different sizes, and the operation f solves a linear program involving these tensors and outputs a new tensor. I cannot iterate simply over the initial array since the size of the output of f grows exponentially in this case. This is why I use this divide and conquer approach, which reduces this size. The recursive program works fine, but slows down dramatically for large size, possibly due to the frames that python opens and keeps track of.
Below I transformed the program to use a continuation (then) and a trampoline (run/recur). It evolves a linear iterative process and it will not overflow the stack. If you're not running into a stack overflow issue, this won't do much to help your specific problem, but it can teach you how to flatten branching computations.
This process of converting a normal function to continuation passing style can be a mechanical one. If you squint your eyes a little bit, you'll see how the program has most of the same elements as yours. Inline comments show code side-by-side -
import numpy as np
def identity (x):
return x
def recur (*values):
return (recur, values)
def run (f):
acc = f ()
while type (acc) is tuple and acc [0] is recur:
acc = f (*acc [1])
return acc
def myfunc (a):
# def recursive(w,i,j)
def loop (w = a, i = 0, j = len(a)-1, then = identity):
if i == j: # same
return then (w[i]) # wrap in `then`
else: # same
k = (j - i) // 2 + i # same
return recur \ # left=recursive(w,i,k)
( w
, i
, k
, lambda left:
recur # right=recursive(w,k+1,j)
( w
, k + 1
, j
, lambda right:
then # wrap in `then`
(f (left, right)) # same
)
)
return run (loop)
def f (a, b):
return a + b # same
a = np.random.rand(10) # same
print(a, myfunc(a)) # recursive(a, 0, a.shape[0]-1)
# [0.5732646 0.88264091 0.37519826 0.3530782 0.83281033 0.50063843 0.59621896 0.50165139 0.05551734 0.53719382]
# 5.208212213881435

Adding through iteration

I want to take user input and add each number up to 0. For example user inputs 9 I want to add 9+8+7+6.... +1 and output the total. My code
def main(*args):
sum = 0
for i in args:
sum = i + (i - 1)
return sum
result = main(9)
print(result)
comes close, but I can't get it to iterate through until 0. I've tried adding ranges in a few ways but no luck there. I'm stuck.
Let's say the user input is assigned to x, then the most simplistic answer is:
sum(range(int(x)+1))
Note that range() will generate a list (actually, an immutable sequence type in Python 3) of numbers up to, but not including, x, hence the +1.
In terms of your original code, there are a few issues. First, you should avoid naming variables the same as Python built-ins, such as sum. Second, you are attempting to iterate through a tuple of input arguments (e.g. args = (9,) in your case), which will perform 9 + (9-1), or otherwise 17 and then return that sum as an output.
Instead, you could do something like:
def main(*args):
mysum = 0
for i in range(args[0]+1):
mysum = mysum + i
return mysum
result = main(9)
print(result)
Both solutions here will return 45.
Nth triangle number. No iteration needed.
def calculate_nth_triangle_number(value):
return value * (value + 1) / 2
Your code misuses a relatively advanced feature of Python, that is argument packing, where all the arguments supplied to a function are packed in a tuple.
What happens when you call main(9)? the loop is entered once (because calling the function with a single argument is equivalent to args = (9, ) in the body of the function) i takes only one value, i = 9 and you have sum = 9+8 = 17.
For your case I don't like a for loop, can you use a while loop? with a while your function follows exactly the definition of your task!
def my_sum(n):
result = 0
while n>0:
result = result + n
n = n - 1
return result
Note that the order of summation and decrease is paramount to a correct result... note also that sum is the name of a built-in function and it is considered bad taste to overload a built-in name with an expression of yours.

Hash multiple iterations of a value over itself

I am trying to write a function which calculates multiple iteration hashes of a specific value (and output each iteration in the meantime).
However, I can't get my head over how to perform, for instance, md5 hash function on itself multiple times. For instance:
a = hashlib.md5('fun').hexdigest()
b = hashlib.md5(a).hexdigest()
c = hashlib.md5(b).hexdigest()
d = hashlib.md5(c).hexdigest()
.......
I think the recursion is the solution, but I just can't seem to implement it properly. This is the general factorial recursion example, but how do I adapt it to hashes:
def factorial(n):
if n == 0:
return 1
else:
return n * factorial(n - 1)
This is a classic application of generators. Python allows a maximum of 500 recursions due to its unusually heavy stack. For anything which might be executed anywhere near that many times, iteration will often be faster. Using a generator allows you to break after any desired number of executions and allows flat usage of the desired logic in your code. The following example prints the output of 10 such executions.
from itertools import islice
def hashes(n):
while True:
n = hashlib.md5(n).hexdigest()
yield n
for h in islice(hashes('fun'), 10):
print(h)
In general, you are looking for a loop like
while True:
x = f(x)
where you repeatedly replace the input with the result of the most recent application.
For your specific example,
def iterated_hash(x):
while True:
x = hashlib.md5(x).hexdigest()
return x
However, since you don't really want to do this an infinite number of times, you need to supply a count:
def iterated_hash(x, n):
while True:
if n == 0:
return x
x = hashlib.md5(x).hexdigest()
or with a for loop,
def iterated_hash(x, n):
for _ in range(n):
x = hashlib.md5(x).hexdigest()
return x
(Practically speaking, you want to use the for loop, but it's nice to see how the for loop is just a finite special case of the more general infinite loop.)
Just iterate as many times as needed:
def make_hash(text, iterations):
a = hashlib.md5(text).hexdigest()
for _ in range(iterations):
a = hashlib.md5(a).hexdigest()
return a
a = make_hash('fun', 5) # 5 iterations

Avoid variable recomputation?

I have a line code like this -
while someMethod(n) < length and List[someMethod(n)] == 0:
# do something
n += 1
where someMethod(arg) does some computation on the number n. The problem with this code is that I'm doing the same computation twice, which is something I need to avoid.
One option is to do this -
x = someMethod(n)
while x < length and List[x] == 0:
# do something
x = someMethod(n + 1)
I am storing the value of someMethod(n) in a variable x and then using it later. However, the problem with this approach is that the code is inside a recursive method which is called multiple times. As a result, a lot of excess instances of variables x are being created which slows the code down.
Here's the snipped of the code -
def recursion(x, n, i):
while someMethod(n) < length and List[someMethod(n)] == 0:
# do something
n += 1
# some condition
recursion(x - 1, n, someList(i + 1))
and this recursion method is called many times throughout the code and the recursion is quite deep.
Is there some alternative available to deal with a problem like this?
Please try to be language independent if possible.
You can use memoization with decorators technique:
def memoize(f):
memo = dict()
def wrapper(x):
if x not in memo:
memo[x] = f(x)
return memo[x]
return wrapper
#memoize
def someMethod(x):
return <your computations with x>
As i understand your code correctly you are looking for some sort of memorization.
https://en.wikipedia.org/wiki/Memoization
it means that on every recursive call you have to save as mush as possible past calculations to use it in current calculation.

Categories