Factorial in numpy and scipy - python

How can I import factorial function from numpy and scipy separately in order to see which one is faster?
I already imported factorial from python itself by import math. But, it does not work for numpy and scipy.

You can import them like this:
In [7]: import scipy, numpy, math
In [8]: scipy.math.factorial, numpy.math.factorial, math.factorial
Out[8]:
(<function math.factorial>,
<function math.factorial>,
<function math.factorial>)
scipy.math.factorial and numpy.math.factorial seem to simply be aliases/references for/to math.factorial, that is scipy.math.factorial is math.factorial and numpy.math.factorial is math.factorial should both give True.

The answer for Ashwini is great, in pointing out that scipy.math.factorial, numpy.math.factorial, math.factorial are the same functions. However, I'd recommend use the one that Janne mentioned, that scipy.special.factorial is different. The one from scipy can take np.ndarray as an input, while the others can't.
In [12]: import scipy.special
In [13]: temp = np.arange(10) # temp is an np.ndarray
In [14]: math.factorial(temp) # This won't work
---------------------------------------------------------------------------
TypeError Traceback (most recent call last)
<ipython-input-14-039ec0734458> in <module>()
----> 1 math.factorial(temp)
TypeError: only length-1 arrays can be converted to Python scalars
In [15]: scipy.special.factorial(temp) # This works!
Out[15]:
array([ 1.00000000e+00, 1.00000000e+00, 2.00000000e+00,
6.00000000e+00, 2.40000000e+01, 1.20000000e+02,
7.20000000e+02, 5.04000000e+03, 4.03200000e+04,
3.62880000e+05])
So, if you are doing factorial to a np.ndarray, the one from scipy will be easier to code and faster than doing the for-loops.

SciPy has the function scipy.special.factorial (formerly scipy.misc.factorial)
>>> import math
>>> import scipy.special
>>> math.factorial(6)
720
>>> scipy.special.factorial(6)
array(720.0)

from numpy import prod
def factorial(n):
print prod(range(1,n+1))
or with mul from operator:
from operator import mul
def factorial(n):
print reduce(mul,range(1,n+1))
or completely without help:
def factorial(n):
print reduce((lambda x,y: x*y),range(1,n+1))

after running different aforementioned functions for factorial, by different people, turns out that math.factorial is the fastest to calculate the factorial.
find running times for different functions in the attached image

You can save some homemade factorial functions on a separate module, utils.py, and then import them and compare the performance with the predefinite one, in scipy, numpy and math using timeit.
In this case I used as external method the last proposed by Stefan Gruenwald:
import numpy as np
def factorial(n):
return reduce((lambda x,y: x*y),range(1,n+1))
Main code (I used a framework proposed by JoshAdel in another post, look for how-can-i-get-an-array-of-alternating-values-in-python):
from timeit import Timer
from utils import factorial
import scipy
n = 100
# test the time for the factorial function obtained in different ways:
if __name__ == '__main__':
setupstr="""
import scipy, numpy, math
from utils import factorial
n = 100
"""
method1="""
factorial(n)
"""
method2="""
scipy.math.factorial(n) # same algo as numpy.math.factorial, math.factorial
"""
nl = 1000
t1 = Timer(method1, setupstr).timeit(nl)
t2 = Timer(method2, setupstr).timeit(nl)
print 'method1', t1
print 'method2', t2
print factorial(n)
print scipy.math.factorial(n)
Which provides:
method1 0.0195569992065
method2 0.00638914108276
93326215443944152681699238856266700490715968264381621468592963895217599993229915608941463976156518286253697920827223758251185210916864000000000000000000000000
93326215443944152681699238856266700490715968264381621468592963895217599993229915608941463976156518286253697920827223758251185210916864000000000000000000000000
Process finished with exit code 0

Related

conversion of function from Matlab to python

I have a MATLAB function :
Bits=30
NBits= ceil(fzero(#(x)2^(x) - x -1 - Bits, max(log2(Bits),1)))
I want to convert it to python, I wrote something like this so far:
from numpy import log, log2
from scipy.optimize import root_scalar
def func(x,Bits):
return ((x)2^(x)-x-1-Bits, max(log2(Bits)))
However it says that it need to be (x)*2^
Does anybody know first, if the conversion from Matlab to python is correct? and second if * has to be added?
Upon suggestion I wrote this lambda function:
lambda x: (2^(x) -x -1 -Bits) , max(log2(Bits))
but I get this error:
TypeError: 'numpy.float64' object is not iterable
I don't have numpy or scipy on this computer so here is my best attempt at an answer.
def YourFunc(Bits):
return math.ceil(root_scalar(lambda x: (2**x)-x-1-Bits, x0 = max(log2(Bits),1)))
Bits = 30
NBits = YourFunc(30)
print(NBits)
I used this function for log2 rather than the one from numpy. Try it
def log2(x):
return math.log(x,2)

while loop strange and unstable behavior in a jitted function

I found that when the index of a numpy array will go out of bound inside a while-loop in a njit decorated function, the way the function handles the while loop can quite weird, and I am not sure why it happens.
from numba import njit
import numpy as np
def func1(v):
i= 0
K= v[-1]+1
while v[i] < K:
i+=1
return i
#njit
def func2(v):
i= 0
K= v[-1]+1
while v[i] < K:
i+=1
return i
x= np.arange(2)
result2 = func2(x)
result1 = func1(x)
Here is a short summary of the results:
1) func2 won't raise IndexError
2) func2 returns different results(like sometimes it is 4; sometimes 5,9,12, etc, basically unstable output) every time we run the file in the console (I am using ipython version 7.8.0)
I am not sure why and how this happens(could be due to numba or spyder or ipython issues or it could be that my cpu is broken beyond repair) which is why I am asking for help here.
Note: I am using:
Anaconda's distribution of python, python version 3.7.4,
spyder version 3.3.6,
ipython version 7.8.0,
numba version 0.45.1
OS windows 10 64-bit
Numba does not do bounds checking on Numpy arrays for performance reasons. There is currently work to turn it on optionally (https://github.com/numba/numba/pull/4432). When you go outside of the bounds of the array you will get whatever is in memory at the location or possibly seg fault.
I've heard of Numba before, but never used it myself.
Here are the results of some messing around with it (version 0.45.1) just now.
from numba import njit
import numpy as np
x = np.arange(2)
#njit
def func2(v):
i = 0
k = v[-1]+1
while v[i] < k:
i += 1
return i
#njit
def func3(x):
return x[2]
func2(x) # returns 2, but no error raised
func3(x) # returns 32, no error raised
func3(np.array([0])) # returns 32, no error raised
func2([0, 1]) # IndexError raised
func3([0, 1]) # IndexError raised
So to me, the bug looks to be the result of some sort of interaction between Numba's jit and Numpy arrays, since normal Python lists behave as expected.

sympy lambdify with numexpr and sqrt

I'm trying to speed up some numeric code generated by lambdify using numexpr. Unfortunately, the numexpr-based function breaks when using the sqrt function, even though it's one of the supported functions.
This reproduces the issue for me:
import sympy
import numpy as np
import numexpr
from sympy.utilities.lambdify import lambdify
expr = sympy.S('b*sqrt(a) - a**2')
a, b = sorted(expr.free_symbols, key=lambda s: s.name)
func_numpy = lambdify((a,b), expr, modules=[np], dummify=False)
func_numexpr = lambdify((a,b), expr, modules=[numexpr], dummify=False)
foo, bar = np.random.random((2, 4))
print sympy.__version__
print func_numpy(foo, bar)
print func_numexpr(foo, bar)
When I run this, the output is:
0.7.6
[-0.02062061 0.08648306 -0.57868128 0.27598245]
Traceback (most recent call last):
File "sympy_test.py", line 17, in <module>
print func_numexpr(foo, bar)
File "<string>", line 1, in <lambda>
NameError: global name 'sqrt' is not defined
As a sanity check, I also tried calling numexpr directly:
numexpr.evaluate('b*sqrt(a) - a**2', local_dict=dict(a=foo, b=bar))
which works as expected, producing the same result as func_numpy.
EDIT: It works when I use the line:
func_numexpr = lambdify((a,b), expr, modules=['numexpr'], dummify=False)
Is this a sympy bug?
you can change np.sqrt(9) to numexpr.evaluate('9**0.5')

numpy measure time - syntax error

I want to measure the time through numpy but I am not sure if I have the right arguments.
import numpy as np
import timeit
def svdsolve(a,b):
u,s,v = np.linalg.svd(a)
c = np.dot(u.T,b)
w = np.linalg.solve(np.diag(s),c)
x = np.dot(v.T,w)
return x
A_=np.fromfile('dataA.bin',count=-1,dtype=np.float32)
B_=np.fromfile('dataB.bin',count=-1,dtype=np.float32)
s='svdsolve({0},{1})'.format(A,B)
mytime= timeit.Timer(stmt=s,setup='import numpy').timeit(100)
print mytime
Right now it gives me :
File "/usr/lib64/python2.7/timeit.py", line 136, in init
code = compile(src, dummy_src_name, "exec") File "", line 6
svdsolve([[ 1.86248358e+09 1.54404045e+09]
^ SyntaxError: invalid syntax
Also , I didn' understand (neither have I found a reference) on what arguments to pass at timer.
And I am not sure how to use the repetition timeit(100)
Neither the str nor repr of a NumPy array is guaranteed to produce an output that can be used to reconstruct the original array. (format uses str, but repr wouldn't help.) Instead, import the arrays into the timed code's namespace. Assuming this code is being run as a script, that would be
mytime = timeit.Timer(stmt='svdsolve(A, B)',
setup='from __main__ import A, B, svdsolve'
).timeit(100)

How do you do natural logs (e.g. "ln()") with numpy in Python?

Using numpy, how can I do the following:
ln(x)
Is it equivalent to:
np.log(x)
I apologise for such a seemingly trivial question, but my understanding of the difference between log and ln is that ln is logspace e?
np.log is ln, whereas np.log10 is your standard base 10 log.
Correct, np.log(x) is the Natural Log (base e log) of x.
For other bases, remember this law of logs: log-b(x) = log-k(x) / log-k(b) where log-b is the log in some arbitrary base b, and log-k is the log in base k, e.g.
here k = e
l = np.log(x) / np.log(100)
and l is the log-base-100 of x
I usually do like this:
from numpy import log as ln
Perhaps this can make you more comfortable.
Numpy seems to take a cue from MATLAB/Octave and uses log to be "log base e" or ln. Also like MATLAB/Octave, Numpy does not offer a logarithmic function for an arbitrary base.
If you find log confusing you can create your own object ln that refers to the numpy.log function:
>>> import numpy as np
>>> from math import e
>>> ln = np.log # assign the numpy log function to a new function called ln
>>> ln(e)
1.0
from numpy.lib.scimath import logn
from math import e
#using: x - var
logn(e, x)
You could simple just do the reverse by making the base of log to e.
import math
e = 2.718281
math.log(e, 10) = 2.302585093
ln(10) = 2.30258093

Categories