How to do infinite (or really deep) recursions in Stackless Python? - 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.

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.

Better Ways to Control Against Infinite Recursion

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).

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')

Is it a sin to use infinite recursion for infinite loops in Python?

This question is more about curiosity than utility. If I'm writing a function that's supposed to run for ever, for instance a daemon, how would Python handle it if I called the function again from the end of the function?
def daemonLoop():
# Declare locals
# Do stuff
daemonLoop()
I'm fairly sure that doing this in C would result in a stack overflow, but given the level of abstraction from C to Python I'm guessing stuff is handled differently.
Would I go to hell for this?
In almost all Python interpreters that will cause a stack overflow, as it would in C. The higher-level feature that would permit this is called Tail Call Optimization or Tail Recursion Elimination, and the benevolent dictator of Python opposes adding this to the language.
This style is considered to be non-idiomatic for Python, and a simple while True: loop is preferred.
The maximum recursion depth can be retrieved with sys.getrecursionlimit() and set with sys.setrecursionlimit().
Would I go to hell for this?
Yes. CPython has no Tail Recursion Elimination / Last Call Optimization.
def recurse():
recurse()
recurse()
Error:
# 1000 or so lines of this:
File "", line 2, in recurse
RuntimeError: maximum recursion depth exceeded
The C version of the Python interpreter (which is probably what you're using) will raise an error eventually if you never return from daemonLoop. I'm not sure about other versions.
I don't know why you'd think about doing something like that when you could simply have an infinite while loop. Anyway for your question about whether it will work:
...
File "test.py", line 7, in daemonLoop
daemonLoop()
File "test.py", line 7, in daemonLoop
daemonLoop()
RuntimeError: maximum recursion depth exceeded
So yeah, hell it is.
Probably not a good idea....
def forever(): forever()
forever()
RuntimeError: maximum recursion depth exceeded
http://paulbarry.com/articles/2009/09/02/infinite-recursion
(define forever (lambda () (forever)))
This kind of recursion is what Lisp dialects like Scheme are made for!

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