"Maximum recursion depth exceeded" when using lru_cache - python-3.x

I wanted to calculate a recursive function using lru_cache. Here is a simplified version of it:
from functools import lru_cache
#lru_cache(maxsize=None)
def f(n:int)->int:
if (n==0): return 1
return n+f(n-1)
### MAIN ###
print(f(1000))
It works well when I run f(100), but with f(1000) I get:
RecursionError: maximum recursion depth exceeded in comparison
One solution is to calculate a table of values for f myself. Is there a solution that does not require me to manually create a table of values?

Note that you can use your function as-is, but you need to ensure each fresh call doesn't have to recurse more than several hundred levels before it hits a cached value or recursive base case; e.g.,
>>> f(400)
80201
>>> f(800) # will stop recursing at 400
320401
>>> f(1000) # will stop recursing at 800
500501
I've resorted to that at times ;-) More generally, you could write a wrapper function that repeatedly tries f(n), catches RecursionError, and backs off to calling it with ever-smaller values of n. For example,
def superf(n, step=400):
pending = []
while True:
pending.append(n)
try:
f(n)
break
except RecursionError:
n = max(n - step, 0)
while pending:
x = f(pending.pop())
return x
Then
>>> superf(100000)
5000050001

Related

maximum recursion depth reached in python

I have developed a code for finding max and min using recursion. But as soon as I make a list greater then 6 elements it throws a runtime error.
RecursionError: maximum recursion depth exceeded in comparison
Here is the below code:
def maxmin(a,i,j):
if(i==j):
return(a[i],a[j])
elif(i==j-1):
if(a[i]>a[j]):
return(a[i],a[j])
else:
return(a[j],a[i])
else:
mid =int(i+j/2)
value1 =maxmin(a,i,mid)
value2 =maxmin(a,mid+1,j)
if(value1[0]>value2[0]):
max=value1[0]
else:
max=value2[0]
if(value1[1]<value2[1]):
min = value1[1]
else:
min=value2[1]
return(max,min)
import sys
sys.setrecursionlimit(1000)
a =[2,3,90,0,-9,3]
maxmin(a,0,len(a)-1)
I have also increased the limit for recursion but still not working.
I tried another small code by recursion with a stack size of 1000 and its working fine. I think there is some issue in the code. The stack space occupied by the above program is not even 100.
import sys
sys.setrecursionlimit(1000)
def fib(n, sum):
if n < 1:
return sum
else:
return fib(n-1, sum+n)
c = 900
print(fib(c, 0))
The second program is working fine while the first is throwing errors.
I wouldn't use recursion:
print(min(a))
print(max(a))

Python List Creation Difference

I am trying to create a recursive function to sort the list from low to high.
Following code doesn't work
less = []
greater = []
def quicksort(array):
if len(array)<2:
return array
else:
pivot = array[0]
for i in array[1:]:
if i <= pivot:
less.append(i)
else:
greater.append(i)
return quicksort(less)+[pivot]+quicksort(greater)
print(quicksort([1,3,2,7,8]))
but I use a book code , it works. Would you advise me why?
def quicksort(array):
if len(array)<2:
return array
else:
pivot = array[0]
less = [i for i in array[1:] if i <= pivot]
greater = [i for i in array[1:] if i > pivot]
return quicksort(less)+[pivot]+quicksort(greater)
print(quicksort([1,3,2,7,8]))
You're using global less and greater lists, so you're going to end up building up the lists bigger and bigger and bigger, repeating your inputs many times (roughly proportional to the number of times you recursively call quicksort). less and greater keep growing until you blow the stack depth limit or run out of memory and Python dies to protect you from yourself.
Worse, you preserve state across calls, so the second and subsequent things you quicksort ends up including garbage from the prior sort operations, even if they're on inputs so short you could "sort" them trivially. Your code would work if you made less/greater local, initializing them afresh in each call:
def quicksort(array):
if len(array)<2:
return array
else:
pivot = array[0]
less = [] # Local!
greater = [] # Local!
for i in array[1:]:
if i <= pivot:
less.append(i)
else:
greater.append(i)
return quicksort(less)+[pivot]+quicksort(greater)

Python generator that returns group of items

I am trying to make a generator that can return a number of consecutive items in a list which "moves" only by one index. Something similar to a moving average filter in DSP. For instance if I have list:
l = [1,2,3,4,5,6,7,8,9]
I would expect this output:
[(1,2,3),(2,3,4),(3,4,5),(4,5,6),(5,6,7),(6,7,8),(7,8,9)]
I have made code but it does not work with filters and generators etc. I am afraid it will also break due to memory if I need to provide a large list of words.
Function gen:
def gen(enumobj, n):
for idx,val in enumerate(enumobj):
try:
yield tuple(enumobj[i] for i in range(idx, idx + n))
except:
break
and the example code:
words = ['aaa','bb','c','dddddd','eeee','ff','g','h','iiiii','jjj','kk','lll','m','m','ooo']
w = filter(lambda x: len(x) > 1, words)
# It's working with list
print('\nList:')
g = gen(words, 4)
for i in g: print(i)
# It's not working with filetrs / generators etc.
print('\nFilter:')
g = gen(w, 4)
for i in g: print(i)
The list for does not produce anything. The code should break because it is not possible to index a filter object. Of course one of the answers is forcing a list: list(w). However, I am looking for better code for the function. How can I change it so that function can accept filters as well etc. I am worried about memory to a huge number of data in a list.
Thanks
With iterators you need to keep track of values that have already been read. An n sized list does the trick. Append the next value to the list and discard the top item after each yield.
import itertools
def gen(enumobj, n):
# we need an iterator for the `next` call below. this creates
# an iterator from an iterable such as a list, but leaves
# iterators alone.
enumobj = iter(enumobj)
# cache the first n objects (fewer if iterator is exhausted)
cache = list(itertools.islice(enumobj, n))
# while we still have something in the cache...
while cache:
yield cache
# drop stale item
cache.pop(0)
# try to get one new item, stopping when iterator is done
try:
cache.append(next(enumobj))
except StopIteration:
# pass to emit progressively smaller units
#pass
# break to stop when fewer than `n` items remain
break
words = ['aaa','bb','c','dddddd','eeee','ff','g','h','iiiii','jjj','kk','lll','m','m','ooo']
w = filter(lambda x: len(x) > 1, words)
# It's working with list
print('\nList:')
g = gen(words, 4)
for i in g: print(i)
# now it works with iterators
print('\nFilter:')
g = gen(w, 4)
for i in g: print(i)

Runtime Error on Factorial recursive method Python

def recursive_factorial(n):
if n == 1: #base case
return 1
else:
return n * recursive_factorial(n-1) #recursive call
pls help I am getting a runtime error:RuntimeError('maximum recursion depth exceeded'
So, you have reached your recursion limit. This can be reset by importing sys and setting but:
Seriously don't use setrecursionlimit
You definitely try to iterate before using recursion. Please try this, which should work if you cannot set recursion limits:
re(n):
g=n
while n>1:
g*=(n-1)
n-=1
return g
If you really, really want to set your recursion limit, make sure that you do so only temporarily. Otherwise other, heavier, functions may create issues if too recursive:
import sys
def thing_i_want_to_recurse(n)
c_limit = sys.getrecursionlimit()
sys.setrecurionlimit(n)
yield
sys.setrecurionlimit(c_limit)
Again iteration is best:
[in]: sys.setrecursionlimit(3)
[in]: recursive_factorial(5)
[out]:Error: maximum recusion depth exceeded
[in]: re(5) #no problem
[out]: 120

Python 3 exercise: generating permutation

I am trying to write a generator function for permutation for practice. But it does not return anything.
But if I replace
´´yield new[k]´´ with ´´lis.append(new[k])´´, then I get the correct list of permutations. Am I doing something wrong with yield?
tup=(1,2,3) # tup can be any sequence
new=[[]]*(len(tup)+1) # memory; new[0]=[], new[1] will be length 1 permutation, etc.
lis=[] # the list of permutations
def repeat(k): # recursion
for i in tup:
if i in new[k-1]:
continue # permutation can't repeat
else: new[k]=new[k-1]+[i]
if k==len(tup):
yield new[k]
else:
repeat(k+1)
gen=repeat(1)
for i in gen:
print(i)
This is a recursive function, but you don't pass on the value from the recursion, which is why it doesn't return anything.
You need to change the call to
repeat(k+1)
to
for x in repeat(k+1):
yield x
The resulting function is then:
tup=(1,2,3) # tup can be any sequence
new=[[]]*(len(tup)+1) # memory; new[0]=[], new[1] will be length 1 permutation, etc.
lis=[] # the list of permutations
def repeat(k): # recursion
for i in tup:
if i in new[k-1]:
continue # permutation can't repeat
else: new[k]=new[k-1]+[i]
if k==len(tup):
yield new[k]
else:
for x in repeat(k+1):
yield x
for i in repeat(1):
print(i)
Which works.
The next step is then to get rid of the global variables.
I think you are trying to write an algorithm for generating permutations of multiple lengths using generators for practice.
Try this question on for size:
How to generate all permutations of a list in Python
You'll need to translate to python3, which shouldn't be that big an issue.
Unfortunately, I think your problem lies in your algorithm, rather than your use of yield, which looks okay to me.

Resources