Prime number factorization with numba - python-3.x

I'm trying to make a prime number factorization algorithm working with numba but I can't get a satisfying result.
Here's my code:
from timeit import default_timer as timer
from numba import jit
def DumbPrimeFactors(n):
result_list = list()
prime = 2
remaining = n
while remaining > 1:
if remaining % prime == 0:
result_list.append(prime)
remaining /= prime
prime -= 1
prime +=1
return result_list
start = timer()
print(DumbPrimeFactors(500000000008))
print(f"time: {timer() - start}")
start = timer()
SmartPrimeFactors = jit(DumbPrimeFactors)
print(SmartPrimeFactors(500000000008))
print(f"time: {timer() - start}")
When I'm executing it the numba function seems slower, so I guess it's not working the way it's suppose to work.

If you run jit(DumbPrimeFactors, nopython=True), you'll see an error showing you that numba is jitting the function in object mode because it doesn't know how to translate everything to machine code, which will not give you optimal performance. The fix is to change the line:
result_list = list()
to:
result_list = []
It appears as if the numba code that translates python to the IR (intermediate representation) doesn't know about the list() syntax. Then on my machine, the numba jitted version is about 7x faster than the un-jitted version. Also note that when you time numba code, the first time you run it, the time you see is the runtime + compilation time. All subsequent runs will use a cached version of the jitted code, so you'll see just the actual execution time.

Related

Unable to calculate fibonnaci numbers using python

import math
import sys
sys.setrecursionlimit(8000000)
f = {1:2,2:3,3:5}
def fib(n):
if n in f:
return f[n]
if n == 1:
return 2
if n == 2:
return 3
if n == 3:
return 5
val = fib(n-1) + fib(n-2)
if n not in f:
f[n] = val
return f[n]%1000000007
print(fib(4000))
This code fails to complete / command prompt crashes. How can I make this better?
Is there any setting that I need to enable to make this program complete?
Implementing the Fibonacci sequence directly from the mathematical definition is an exercise that illustrates problems with recursive solutions. It leads to an exponential explosion of recursive function calls that even modern computers cannot handle. The biggest problem is that for large values of n, you will calculate fib(1) an exponential number of times.
There are several solutions to this problem:
Use memoization to store values that have already been calculated. Then you look up the calculated value and return it immediately without doing any further calculations. This is a good exercise to learn how memoization works. However, it is still inefficient because you still unnecessarily execute recursive function calls.
Implement an iterative solution. I'm not going to get into the details here. I suggest you do some research to find the iterative solution that will implement fib(n) in linear time instead of exponential time.
Implement the closed formula. Mathematicians have already solved fib(n) as a closed formula. This solution will take constant time no matter how large of an n you use.
use automatic memorization of old vales so that it won't go into infinity loop.use lru_cache as a decorator on your function.
import sys
from functools import lru_cache
sys.setrecursionlimit(8000000)
f = {1:2,2:3,3:5}
#lru_cache(maxsize=None)
def fib(n):
if n in f:
return f[n]
if n == 1:
return 2
if n == 2:
return 3
if n == 3:
return 5
val = fib(n-1) + fib(n-2)
if n not in f:
f[n] = val
return f[n]%1000000007
print(fib(4000))

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

Non-recursive Most Efficient Big-O Permutation Alghoritm Python3 (non-built-in)

Hi Guys For my Data Structure assignment I have to find the most efficient way (big-o wise) to calculate permutations of a list of objects.
I found recursive examples on the web but this doesn't seem to be the most efficient way; I tried my own code but then I realized that when I count the number of possible permutations I'm actually making my algorithm O(!n). Any suggestions? .-.
from random import sample
import time
start = time.time()
testList = list(x for x in range(7))
print('list lenght: %i objects' % len(testList))
nOfPerms = 1
for i in range(1,len(testList)+1):
nOfPerms *= i
print('number of permutations:', nOfPerms)
listOfPerms = []
n = 1
while n <= nOfPerms:
perm = tuple(sample(testList, len(testList)))
listOfPerms.append(perm)
permutations = set(listOfPerms)
if len(permutations) == len(listOfPerms):
n += 1
else:
del(listOfPerms[-1])
end = time.time() - start
print('time elapsed:', end)
OUTPUT:
list lenght: 7 objects
number of permutations: 5040
time elapsed: 13.142292976379395
If instead of 7 I put 8 or 9, or 10, those are the number of permutations (I won't show the time cause it's taking too long):
list lenght: 8 objects
number of permutations: 40320
list lenght: 9 objects
number of permutations: 362880
list lenght: 10 objects
number of permutations: 3628800
I believe this will be the best you can do. Generating the number of permutations of a list generates n! permutations. As you need to generate them all this is also how much time it will take (O(n!)). What you could try to do is to make it a python generator function so you will always only generate exactly as many as you need instead of precalculating them all and storing them in memory. If you want an example of this i could give you one.
Im sorry this might be a quite negative answer. It's a good question but im pretty sure this is about the best that you can do, asymptotically. You could optimize the code itself a bit to use less instructions but in the end that wont help too much.
Edit:
This is a python implementation of Heap's algorithm which i promised
(https://en.wikipedia.org/wiki/Heap%27s_algorithm) generating N! permutations where the generation of every one permutation takes amortized O(1) time and which uses O(n) space complexity (by alteri
def permute(lst, k=None):
if k == None:
k = len(lst)
if k == 1:
yield lst
else:
yield from permute(lst, k-1)
for i in range(k-1):
if i % 2 == 0:
#even
lst[i], lst[k-1] = lst[k-1], lst[i]
else:
#odd
lst[0], lst[k-1] = lst[k-1], lst[0]
yield from permute(lst, k-1)
for i in permute([1, 2, 3, 4]):
print(i)

"Maximum recursion depth exceeded" when using lru_cache

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

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

Resources