I try to apply Numba to my code to improve the speed. But I get an error " IndexError: list index out of range" and warnings. How can I make it works?
I run the code as below:
import numpy as np
from numpy import linalg as LA
from numba import guvectorize, int64, float64, vectorize
@guvectorize([(float64[:], int64)], '(n),()->(n)')
def func(main, n):
nprime = n-1
off = np.random.normal(size=(nprime, nprime))
tril = np.tril(off, -1)
W_n = tril tril.T
np.fill_diagonal(W_n, main)
eigenvalues = LA.eigvals(W_n)
w = np.flip(np.sort(eigenvalues))
# GOE_L12_dist[:,i] = w[0:2]
return w
main = np.sqrt(2) * np.random.normal(size=(3-1))
func(main, 3)
Then I get error as
---------------------------------------------------------------------------
IndexError Traceback (most recent call last)
Input In [16], in <cell line: 1>()
1 @guvectorize([(float64[:], int64)], '(n),()->(n)')
----> 2 def func(main, n):
3 nprime = n-1
4 off = np.random.normal(size=(nprime, nprime))
File /opt/anaconda3/lib/python3.9/site-packages/numba/np/ufunc/decorators.py:197, in guvectorize.<locals>.wrap(func)
195 if len(ftylist) > 0:
196 guvec.disable_compile()
--> 197 return guvec.build_ufunc()
File /opt/anaconda3/lib/python3.9/site-packages/numba/np/ufunc/gufunc.py:66, in GUFunc.build_ufunc(self)
65 def build_ufunc(self):
---> 66 self.ufunc = self.gufunc_builder.build_ufunc()
67 return self
File /opt/anaconda3/lib/python3.9/site-packages/numba/core/compiler_lock.py:35, in _CompilerLock.__call__.<locals>._acquire_compile_lock(*args, **kwargs)
32 @functools.wraps(func)
33 def _acquire_compile_lock(*args, **kwargs):
34 with self:
---> 35 return func(*args, **kwargs)
File /opt/anaconda3/lib/python3.9/site-packages/numba/np/ufunc/ufuncbuilder.py:363, in GUFuncBuilder.build_ufunc(self)
360 nout = len(self.sout)
362 # Pass envs to fromfuncsig to bind to the lifetime of the ufunc object
--> 363 ufunc = _internal.fromfunc(
364 self.py_func.__name__, self.py_func.__doc__,
365 func_list, type_list, nin, nout, datalist,
366 keepalive, self.identity, self.signature,
367 )
368 return ufunc
IndexError: list index out of range
And the warning shows
/var/folders/9_/y3v35tk14nl7_b9ks8h4l79c0000gn/T/ipykernel_4300/1986471478.py:1: NumbaWarning:
Compilation is falling back to object mode WITHOUT looplifting enabled because Function "func" failed type inference due to: No implementation of function Function(<built-in method normal of numpy.random.mtrand.RandomState object at 0x7f7c4ed6cc40>) found for signature:
>>> normal(size=UniTuple(int64 x 2))
There are 4 candidate implementations:
- Of which 4 did not match due to:
Overload in function '_OverloadWrapper._build.<locals>.ol_generated': File: numba/core/overload_glue.py: Line 131.
With argument(s): '(size=UniTuple(int64 x 2))':
Rejected as the implementation raised a specific error:
TypingError: Failed in nopython mode pipeline (step: nopython frontend)
No implementation of function Function(<intrinsic stub>) found for signature:
>>> stub(UniTuple(int64 x 2))
There are 2 candidate implementations:
- Of which 2 did not match due to:
Intrinsic in function 'stub': File: numba/core/overload_glue.py: Line 35.
With argument(s): '(UniTuple(int64 x 2))':
Rejected as the implementation raised a specific error:
TypingError: unsupported call signature
raised from /opt/anaconda3/lib/python3.9/site-packages/numba/core/typing/templates.py:439
During: resolving callee type: Function(<intrinsic stub>)
During: typing of call at <string> (3)
File "<string>", line 3:
<source missing, REPL/exec in use?>
raised from /opt/anaconda3/lib/python3.9/site-packages/numba/core/typeinfer.py:1086
During: resolving callee type: Function(<built-in method normal of numpy.random.mtrand.RandomState object at 0x7f7c4ed6cc40>)
During: typing of call at /var/folders/9_/y3v35tk14nl7_b9ks8h4l79c0000gn/T/ipykernel_4300/1986471478.py (4)
File "../../../../../../../../var/folders/9_/y3v35tk14nl7_b9ks8h4l79c0000gn/T/ipykernel_4300/1986471478.py", line 4:
<source missing, REPL/exec in use?>
@guvectorize([(float64[:], int64)], '(n),()->(n)')
/opt/anaconda3/lib/python3.9/site-packages/numba/core/object_mode_passes.py:151: NumbaWarning: Function "func" was compiled in object mode without forceobj=True.
File "../../../../../../../../var/folders/9_/y3v35tk14nl7_b9ks8h4l79c0000gn/T/ipykernel_4300/1986471478.py", line 1:
<source missing, REPL/exec in use?>
warnings.warn(errors.NumbaWarning(warn_msg,
/opt/anaconda3/lib/python3.9/site-packages/numba/core/object_mode_passes.py:161: NumbaDeprecationWarning:
Fall-back from the nopython compilation path to the object mode compilation path has been detected, this is deprecated behaviour.
For more information visit https://numba.readthedocs.io/en/stable/reference/deprecation.html#deprecation-of-object-mode-fall-back-behaviour-when-using-jit
File "../../../../../../../../var/folders/9_/y3v35tk14nl7_b9ks8h4l79c0000gn/T/ipykernel_4300/1986471478.py", line 1:
<source missing, REPL/exec in use?>
warnings.warn(errors.NumbaDeprecationWarning(msg,
But when I write my code as below, it works with warning. But the input is repeated so there is no use of main_2.
@guvectorize([(float64[:], int64, float64[:])], '(n),()->(n)')
def func(main, n, main_2):
nprime = n-1
off = np.random.normal(size=(nprime, nprime))
tril = np.tril(off, -1)
W_n = tril tril.T
np.fill_diagonal(W_n, main)
eigenvalues = LA.eigvals(W_n)
w = np.flip(np.sort(eigenvalues))
# GOE_L12_dist[:,i] = w[0:2]
return w
main = np.sqrt(2) * np.random.normal(size=(3-1))
func(main, 3, main)
CodePudding user response:
@guvectorize
expects no return
in the function definition.
From the @guvectorize documentation
Contrary to vectorize() functions, guvectorize() functions don’t return their result value: they take it as an array argument, which must be filled in by the function
The last argument does not have to be included in the function call. np.random.normal
doesn't cause a warning if all arguments are provided.
import numpy as np
from numpy import linalg as LA
from numba import guvectorize, int64, float64 # tested with numba 0.55.2
@guvectorize([(float64[:], int64, float64[:])], '(n),()->(n)')
def func(main, n, res):
nprime = n-1
off = np.random.normal(0., 1., (nprime, nprime)) # all arguments provided
tril = np.tril(off, -1)
W_n = tril tril.T
np.fill_diagonal(W_n, main)
eigenvalues = LA.eigvals(W_n)
res = np.flip(np.sort(eigenvalues)) # res filled with the result
# return removed
main = np.sqrt(2) * np.random.normal(size=(3-1))
func(main, 3) # call without last argument
Output
array([-1.60235493, 0.95716831])
If the function only depends on n (please note that this implementation mimics the decision to expect n to be off-by-one) and does not need to generalize to more than two dimensions, @guvectorize
is not needed.
from numba import njit
@njit
def func(n):
nprime = n-1
main = np.sqrt(2.) * np.random.normal(0., 1., (nprime))
off = np.random.normal(0., 1., (nprime, nprime))
tril = np.tril(off, -1)
W_n = tril tril.T
np.fill_diagonal(W_n, main)
eigenvalues = LA.eigvals(W_n)
return np.flip(np.sort(eigenvalues))
func(3)
Output
array([ 1.06510406, -3.08375554])