Better Ways to Control Against Infinite Recursion - python

I am wondering if there is a standard way or a better way to control against infinite recursion than in my code below? I want my recursive function to give up after max attempts. The code below does it by introducing attempt method parameter and incrementing it during the recursive invocation. Is there a better way?
def Rec(attempt=0):
if attempt==10:
return()
else:
print(attempt)
Rec(attempt=attempt+1)
Rec()

There is also this way but is not recommended for what you want to do - I only posted it for reference and is good to use in other cases...
#!/usr/bin/env python
import sys
sys.setrecursionlimit(5)
def Rec(attempt=0):
print attempt
Rec(attempt=attempt+1)
try:
Rec()
except RuntimeError:
print 'maximum recursion depth exceeded'
From sys.setrecursionlimit(limit)
To be even more clear, as said in python docs what sys.setrecursionlimit(limit) does is:
Set the maximum depth of the Python interpreter stack to limit. This
limit prevents infinite recursion from causing an overflow of the C
stack and crashing Python.
The highest possible limit is platform-dependent. A user may need to
set the limit higher when she has a program that requires deep
recursion and a platform that supports a higher limit. This should be
done with care, because a too-high limit can lead to a crash.
So in my opinion is not good to mess with the Python interpreter stack unless you know very well what you are doing.

You could make a decorator, and then you can write your proper recursive function, with its usual exit conditions, but also impose a recursion limit:
def limit_recursion(limit):
def inner(func):
func.count = 0
def wrapper(*args, **kwargs):
func.count += 1
if func.count < limit:
result = func(*args, **kwargs)
else:
result = None
func.count -= 1
return result
return wrapper
return inner
Your code would be (with a limit of 3):
#limit_recursion(limit=3)
def Rec():
print('hi')
Rec()
Running:
>>> Rec()
hi
hi
hi

Yours is already good. That's the way to go. It is good because it is light weight. You basically need an int and a condition branch - that's it.
Alternatively you can try to guarantee to break the loop in the condition without a counter (but that usually is dependent from case to case).

Related

Factorial function in python is being limited

I made a simple factorial program:
import sys
sys.set_int_max_str_digits(0)
sys.setrecursionlimit(1000000)
def factorial(x):
if x == 0 | x == 1:
return 1
elif x > 1:
return x * factorial(x - 1)
i = 0
while 1:
print(factorial(i), '\n')
i += 1
But after a while the program halts. I want to know if there's a way to remove the limit on how big it could get.
Recursion is not meant to be infinite. Eventually your program would fail, even on a system with a huge amount of memory.
Also note that the recursion limit given to setrecursionlimit() is not a guarantee that you'll get that recursion depth. To quote from the sys.setrecursionlimit documentation:
The highest possible limit is platform-dependent. A user may need to set the limit higher when they have a program that requires deep recursion and a platform that supports a higher limit. This should be done with care, because a too-high limit can lead to a crash.
I would suggest either limiting the program to calculating a reasonable sized factorial, or not using recursion. Some tasks are much better suited to recursion versus iteration, but factorials is not one of them.

How to do infinite (or really deep) recursions in Stackless Python?

I know standard CPython has a limit on recursion depth, less than 1000 I think, so the below example code will fail with a "maximum recursion depth exceeded" error.
def rec_add(x):
if x == 0:
return x
else:
return x + add(x - 1)
print(rec_add(1000))
I heard Stackless Python supports infinite recursion depth, but if I run the above code with Stackless Python, it still reports a "maximum recursion depth exceeded" error. I think maybe I need to modify the code somehow to enable it to use the infinite recursion depth feature of Stackless Python?
Any idea how to do infinite recursions in Stackless Python? Thanks.
Note: I know how to increase standard CPython's recursion depth limit over 1000, and I know how to convert the above code to a simple iteration, or simply use the Gauss formula to calculate the sum, those are not what I'm looking for, and the above code is purely as an example.
EDIT: Like I already said in the "Note" part above (that I guess no one actually reads), I know how to increase CPython's recursion limit, and I know how to convert the example code into iterations or just a Gauss sum formula of n * (n + 1) / 2, I'm just asking here because I heard one of the great features of Stackless Python is that it enables infinite recursions, and I don't know how may I enable it for the example code.
EDIT2: I'm not sure if I got the idea of "Stackless Python supports infinite recursions" wrong, but here are some sources that says (or alludes to) that Stackless Python supports infinite recursions:
What are the drawbacks of Stackless Python?
https://bitbucket.org/stackless-dev/stackless/issues/96
https://stackless.readthedocs.io/en/3.6-slp/whatsnew/stackless.html
After fumbling around I got the following code based on an official example code from more than a decade ago here
https://bitbucket.org/stackless-dev/stacklessexamples/src/a01959c240e2aeae068e56b86b4c2a84a8d854e0/examples/?at=default
so I modified the recursive addition code to look like this
import stackless
def call_wrapper(f, args, kwargs, result_ch):
result_ch.send(f(*args, **kwargs))
def call(f, *args, **kwargs):
result_ch = stackless.channel()
stackless.tasklet(call_wrapper)(f, args, kwargs, result_ch)
return result_ch.receive()
def rec_add(n):
if n <= 1:
return 1
return n + call(rec_add, n-1)
print(rec_add(1000000))
It works with large number like 1,000,000, I guess it is kind of an indirect recursion since the function calls another function which starts a tasklet that calls the function itself (or something like this).
Now I'm wondering if this is indeed the supposed way to implement an infinite recursion in Stackless Python, or are there more straight-forward/direct ways of doing it? Thanks.

python - assert somehow immediately detects infinite recursion

I wrote a fibonacci function that infinitely recurses, and while python couldn't detect it and threw errors upon hitting the max recursion limit, when I used try and assert to see if fib(30) was equal to some value, it immediately told me it was not. How did it do this? It seems like it didn't even need to run fib(30).
note:
I realize this only works if I do
try:
assert infiniteFib(30) == 832040
except:
print "done immediately"
When I do just the assert, it produces many errors about too many recursions, but with the try it stops at the first error.
What I'm curious is how does python manage to produce an error so quickly about infinite recursion? Wouldn't it need to hit the limit (which takes a long time) to tell whether it was infinite?
EDIT:
Some requested code, but just to be clear, I DON'T want a solution to the errors (I know it's wrong because I deliberately excluded the base case), I want to know how python produces errors so quickly when it should take much longer (if you do fib(30), clearly it takes a while to hit the max recursion limit, but somehow python produces errors way before then):
def fib(n):
return fib(n-1) + fib(n-2)
try: assert(fib(30) == 832040)
except: print "done immediately"
The reason the code you've shown runs quickly is because it catches the exception that is raised by fib when it hits the recursion limit and doesn't print the traceback. Running to the recursion limit doesn't take very long at all, but formatting and printing hundreds of lines of traceback does.
If you inspect the exception you get, you'll see it is the same RuntimeError you get when you run fib normally, not an AssertionError. Try this, to see what is going on better:
try:
assert(fib(30) == 832040)
except Exception as e:
print("Got an Exception: %r" % e)
It's not done immediately. Your code runs until python reaches maximum recursion depth and maximum recursion depth is set to 1000 by default in python to avoid stack overflow errors.
So, actually your code runs till it reaches recursion depth of 1000 and errors out RuntimeError: maximum recursion depth exceeded. You can verify this by modifying your code as below:
i=0
def fib(n):
global i
i = i + 1
print i
return fib(n-1) + fib(n-2)
assert(fib(30) == 832040)
print i
print "done immediately"
In my machine, i am getting the last i value as 984 before errors out.

maximum recursion depth exceeded and how to make script more efficient

I'm creating a script using this library: https://github.com/oczkers/fut14
However, after some time, I get the error "maximum recursion depth exceeded." Afterwards I did some research and saw that I could increase this, however I would like to know a better way of avoiding this error and making my script more efficient.
def search():
items = fut.searchAuctions('player', level='gold', max_buy=250, start=0, page_size=15)
print (items)
if items == 1:
print (buy_now_price)
print (trade_id)
fut.bid(items[0]['trade_id'], 'buy_now_price')
elif items == 0:
search()
Most python installation only allow you to recurse 1000 levels (Python's self-imposed artificial limit).
A new "recursion level" happens every time your function search calls itself and involves saving some information of each function call on top of the stack. Once this stack has "grown" tall enough, you receive a "maximum recursion depth exceeded." also known as a stack overflow :).
You can modify your recursive algorithm to an iterative one instead to avoid this.
See this question here for an algorithmic way to convert from a recursive function to an iterative one. It involves using a list to simulate a stack (a list can grow much larger than Python's stack).
Recursive to iterative example
Although using the algorithmic way to convert a recursive to iterative function works, it's not the best approach since you are still using a growing list to represent your stack. Sometimes you can analyze your algorithm and find a way rewrite your algorithm without simulating any stack.
In your example, it seems that you simply want a function that will run forever until it finds something. You can rewrite it iteratively as follows
def search():
while True:
items = fut.searchAuctions('player', level='gold', max_buy=250, start=0, page_size=15
print (items)
if items == 1:
break
print (buy_now_price)
print (trade_id)
fut.bid(items[0]['trade_id'], 'buy_now_price')

min max algorithm in python

In the minmax algorithm,How to determine when your function reaches the end of the tree and break the recursive calls.
I have made a max function in which I am calling the min function. In the min function , what shud I do?? For max function, I am just returning the bestscore.
def maxAgent(gameState, depth):
if (gameState.isWin()):
return gameState.getScore()
actions = gameState.getLegalActions(0);
bestScore = -99999
bestAction = Directions.STOP
for action in actions:
if (action != Directions.STOP):
score = minAgent(gameState.generateSuccessor(0, action), depth, 1)
if (score > bestScore):
bestScore = score
bestAction = action
return bestScore
def minvalue(gameState,depth,agentIndex):
if (gameState.isLose()):
return gameState.getScore()
else:
finalstage = False
number = gameState.getNumAgents()
if (agentIndex == number-1):
finalstage = True
bestScore = 9999
for action in gameState.getLegalActions(agentIndex):
if(action != Directions.STOP
I could not understand how to proceed now?I not allowed to set the limit of depth of tree. it has to be arbitrary.
Usually you want to search until a certain recursion depth (e.g. n moves in advance, when playing chess). Therefore, you should pass the current recursion depth as a parameter. You may abort earlier when your results do not improve, if you can determine that with little effort.
In the minmax algorithm,How to
determine when your function reaches
the end of the tree and break the
recursive calls.
Basically, you're asking when you've reached a leaf node.
A leaf node occurs when you've reached the maximum depth for the search, or a terminal node (i.e. a position that ends the game).
I completely agree with relet. But you might want to consider this also:
There are times when you might also think that the current branch that you are exploring is worth exploring a little deeper. This will call for some further heuristics to be applied. I don't know how advanced the solution for your problem is required to be. This is because I don't know where the problem is coming from.
As suggested by Amber, try posting some code so we know how complex you want the solution to be. Further, if you explained how much you know/can_do, then we might be able to suggest more useful options - things that you might be able to realistically implement, rather than just amazing ideas that you may not know how to or have the time to implement
This site has post of minimax, even though it is based on IronPython:
http://blogs.microsoft.co.il/blogs/dhelper/archive/2009/07/13/getting-started-with-ironpython-part-4-minimax-algorithm.aspx
It says:
The Minimax algorithm is recursive by nature, and as such it requires a stop condition, in our case either the game has ended (no more moves) or the desired depth has been reached (lines 3-8).
You can avoid having two different functions by using Negamax http://en.wikipedia.org/wiki/Negamax

Categories

Resources