Numba jit unknown error during python function - numpy

I made this function, but numba always give me error. Both chr_pos and pos are 1D arrays. What can be the problem?
#nb.njit
def create_needed_pos(chr_pos, pos):
needed_pos=[]
needed_pos=np.array(needed_pos,dtype=np.float64)
for i in range(len(chr_pos)):
for k in range(len(pos)):
if chr_pos[i] == pos[k]:
if i==1 and k==1:
needed_pos=pos[k]
else:
a=pos[k]
needed_pos=np.append(needed_pos,[a])
return needed_pos
needed_pos=create_needed_pos(chr_pos, pos)
The errors:
warnings.warn(errors.NumbaDeprecationWarning(msg,
<input>:1: NumbaWarning:
Compilation is falling back to object mode WITHOUT looplifting enabled because Function "create_needed_pos" failed type inference due to: Cannot unify array(float64, 1d, C) and int32 for 'needed_pos.1', defined at <input> (5)
File "<input>", line 5:
<source missing, REPL/exec in use?>
During: typing of intrinsic-call at <input> (9)
File "<input>", line 9:
<source missing, REPL/exec in use?>

The message
Cannot unify array(float64, 1d, C) and int32 for 'needed_pos.1'
is telling you that you are trying to assign an integer variable to an array. That happens in this line:
needed_pos=pos[k]
You can do that in normal Python, but Numba requires static types. You must assign an array of floats to an array of floats. For example, replacing the line by
needed_pos = pos[k:k+1]
The same error message says you are trying to assign an int, and this indicates that pos receives an array of ints. You must pass an array of floats instead.
After those changes, Numba still complains here:
needed_pos = []
needed_pos = np.array(needed_pos, dtype=np.float64)
with the message
numba.core.errors.TypingError: Failed in nopython mode pipeline (step: nopython frontend)
Cannot infer the type of variable 'needed_pos', have imprecise type: list(undefined)<iv=None>.
because it doesn't know the type of the elements that needed_pos will contain.
You can replace those two lines with one that creates an array of size zero with a known type:
needed_pos = np.array((0,), dtype=np.float64)
Now the program compiles and produces the same result with or without Numba.
But a problem remains. Numpy arrays work best when they have a fixed size. If you are continuously adding elements you'd better use lists (Numba lists in this case). This way for example:
#nb.njit
def create_needed_pos(chr_pos, pos):
needed_pos = nb.typed.List.empty_list(nb.float64)
for i in range(len(chr_pos)):
for k in range(len(pos)):
if chr_pos[i] == pos[k]:
if i == k == 1:
needed_pos = nb.typed.List([pos[k]])
else:
needed_pos.append(pos[k])
return needed_pos

Related

Numpy's hstack troubles with Numba

I am having trouble compiling a simple function in no-Python mode with Numba:
#njit
def fun(x,y):
points = np.hstack((x,y))
return points
a = 5
b = 2
res = fun(a,b)
While this very simple script works without the #njit decorator, if run with it throws the error:
TypingError: Failed in nopython mode pipeline (step: nopython frontend)
No implementation of function Function(<function hstack at 0x7f491475fe50>) found for signature:
>>> hstack(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 129.
With argument(s): '(UniTuple(int64 x 2))':
Rejected as the implementation raised a specific error:
TypeError: np.hstack(): expecting a non-empty tuple of arrays, got UniTuple(int64 x 2)
raised from /usr/local/lib/python3.8/dist-packages/numba/core/typing/npydecl.py:748
During: resolving callee type: Function(<function hstack at 0x7f491475fe50>)
During: typing of call at <ipython-input-41-7a0a3bcd4b1a> (28)
File "<ipython-input-41-7a0a3bcd4b1a>", line 28:
def fun(x, y):
points = np.hstack((x, y))
^
If I try to stack one scalar and one array (which it might be the case in the original function from which this problem arised), the behavior doesn't change:
b = np.ones(3)
res = fun(a,b)
TypingError: Failed in nopython mode pipeline (step: nopython frontend)
No implementation of function Function(<function hstack at 0x7f491475fe50>) found for signature:
>>> hstack(Tuple(int64, array(float64, 1d, C)))
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 129.
With argument(s): '(Tuple(int64, array(float64, 1d, C)))':
Rejected as the implementation raised a specific error:
TypeError: np.hstack(): expecting a non-empty tuple of arrays, got Tuple(int64, array(float64, 1d, C))
raised from /usr/local/lib/python3.8/dist-packages/numba/core/typing/npydecl.py:748
During: resolving callee type: Function(<function hstack at 0x7f491475fe50>)
During: typing of call at <ipython-input-42-39bffd13df71> (28)
File "<ipython-input-42-39bffd13df71>", line 28:
def fun(x, y):
points = np.hstack((x, y))
This is very puzzling to me. I am using Numba 0.56.4—which should be the last stable release.
A very similar behavior happens with np.concatenate, too.
Any suggestion would much appreciated.
Thank you!

Numpy function round throws error using numba jitclass

I want to use the numpy.round_ ina method of a class.
Any calculation done by methods of this class I want to accelerate by using numba.
In general, it works fine. But I somehow do not get numpy.round_ running.
When using numpy.round_ numba throws an error.
Here is my code of a reduced example:
from numba import types
from numba.experimental import jitclass
import numpy as np
spec = [
('arr', types.Array(types.uint8, 1, 'C')),
('quot', types.Array(types.float64, 1, 'C')),
]
#jitclass(spec)
class test:
def __init__(self):
self.arr = np.array((130,190,130),dtype=np.uint8)
def rnd_(self):
quot = np.zeros(3, dtype=np.float64)
val = self.arr
quot = np.round(val/3.0)
return quot
t = test()
a = t.rnd_()
It throws the following error:
TypingError: - Resolution failure for literal arguments:
Failed in nopython mode pipeline (step: nopython frontend)
No implementation of function Function(<function round_ at 0x0000021B3500D870>) found for signature:
round_(array(float64, 1d, C))
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): '(array(float64, 1d, C))':
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(array(float64, 1d, C))
There are 2 candidate implementations:
- Of which 2 did not match due to:
Intrinsic of function 'stub': File: numba\core\overload_glue.py: Line 35.
With argument(s): '(array(float64, 1d, C))':
No match.
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 C:\ProgramData\Anaconda3\envs\mybase_conda\lib\site-packages\numba\core\typeinfer.py:1086
During: resolving callee type: Function(<function round_ at 0x0000021B3500D870>)
During: typing of call at .......\python\playground\tmp.py (27)
File "tmp.py", line 27:
def rnd_(self):
<source elided>
val = self.arr
quot = np.round(val/3.0)
^
- Resolution failure for non-literal arguments:
None
During: resolving callee type: BoundFunction((<class 'numba.core.types.misc.ClassInstanceType'>, 'rnd_') for instance.jitclass.test#21b3c031930<arr:array(uint8, 1d, C),quot:array(float64, 1d, C)>)
During: typing of call at <string> (3)
What am I doing wrong?
Seems like you need to pass round's optional arguments as well. I could reproduce the error with an even smaller example:
#nb.jit(nopython=True)
def foo(x):
return np.round(x)
The fix to this is something like:
#nb.jit(nopython=True)
def foo(x):
out = np.empty_like(x)
np.round(x, 0, out)
return out
So for your case, it should be:
def rnd_(self):
quot = np.zeros(3, dtype=np.float64)
np.round(self.arr / 3.0, 0, quot)
return quot

How to subset a 1-d array using a boolean 1-d array in numba decorated function?

I gotta say, numba seems to be usable only in extremely simplistic use cases carefully designed to be presented in talks
I can run the following code just fine:
def rt(hi):
for i in hi:
hi_ = i == hi
t = hi[hi_]
return None
rt(np.array(['a','b','c','d'],dtype='U'))
But, when i decorate the above code with njit:
#njit
def rt(hi):
for i in hi:
hi_ = i == hi
t = hi[hi_]
return None
rt(np.array(['a','b','c','d'],dtype='U'))
I get the following error:
---------------------------------------------------------------------------
TypingError Traceback (most recent call last)
<ipython-input-34-eadef1d0ecee> in <module>
5 t = hi[hi_]
6 return None
----> 7 rt(np.array(['a','b','c','d'],dtype='U'))
~/miniconda/envs/IndusInd_credit_cards_collections_scorecard_/lib/python3.8/site-packages/numba/core/dispatcher.py in _compile_for_args(self, *args, **kws)
418 e.patch_message(msg)
419
--> 420 error_rewrite(e, 'typing')
421 except errors.UnsupportedError as e:
422 # Something unsupported is present in the user code, add help info
~/miniconda/envs/IndusInd_credit_cards_collections_scorecard_/lib/python3.8/site-packages/numba/core/dispatcher.py in error_rewrite(e, issue_type)
359 raise e
360 else:
--> 361 raise e.with_traceback(None)
362
363 argtypes = []
TypingError: Failed in nopython mode pipeline (step: nopython frontend)
No implementation of function Function(<built-in function getitem>) found for signature:
>>> getitem(array([unichr x 1], 1d, C), Literal[bool](False))
There are 22 candidate implementations:
- Of which 20 did not match due to:
Overload of function 'getitem': File: <numerous>: Line N/A.
With argument(s): '(array([unichr x 1], 1d, C), bool)':
No match.
- Of which 1 did not match due to:
Overload in function 'GetItemBuffer.generic': File: numba/core/typing/arraydecl.py: Line 162.
With argument(s): '(array([unichr x 1], 1d, C), bool)':
Rejected as the implementation raised a specific error:
TypeError: unsupported array index type bool in [bool]
raised from /home/sarthak/miniconda/envs/IndusInd_credit_cards_collections_scorecard_/lib/python3.8/site-packages/numba/core/typing/arraydecl.py:68
- Of which 1 did not match due to:
Overload in function 'GetItemBuffer.generic': File: numba/core/typing/arraydecl.py: Line 162.
With argument(s): '(array([unichr x 1], 1d, C), Literal[bool](False))':
Rejected as the implementation raised a specific error:
TypeError: unsupported array index type Literal[bool](False) in [Literal[bool](False)]
raised from /home/sarthak/miniconda/envs/IndusInd_credit_cards_collections_scorecard_/lib/python3.8/site-packages/numba/core/typing/arraydecl.py:68
During: typing of intrinsic-call at <ipython-input-34-eadef1d0ecee> (5)
File "<ipython-input-34-eadef1d0ecee>", line 5:
def rt(hi):
<source elided>
hi_ = i == hi
t = hi[hi_]
^
How to subset a 1-d array using a boolean 1-d array in numba decorated function?

Optimization (scipy.optimize) L-BFGS-B wrapper args treating array elements as one variable

I am unable to understand the source of this error:
line 327, in function_wrapper
return function(*(wrapper_args + args))
TypeError: SSVOptionPriceObjFunc() missing 1 required positional argument: 'marketVolSurface'
The relevant code is below:
x0 = [1.0, 0.0] # (lambda0, rho)
x0 = np.asarray(x0)
args = (spot, 0.01*r, daysInYear, mktPrices, volSurface)
# constraints: lambd0 >0, -1<= rho <=1
boundsHere = ((0, None), (-1, 1))
res = minimize(SSVOptionPriceObjFunc, x0, args, method='L-BFGS-B', jac=None,
bounds=boundsHere,options={'xtol': 1e-8, 'disp': True})
The function to be minimized is below. The first two arguments are the free variables, while the other five are fixed as parameters.
def SSVOptionPriceObjFunc(lambda0, rho, spot, spotInterestRate, daysInYear, marketPrices,
marketVolSurface):
My intention is to find (lambd0, rho) giving a minimum. From the debugger, it seems that my initial guess x0 is interpreted as a single variable, not as a vector, giving the error about a missing positional argument. I have tried passing x0 as a list, tuple, and ndarray; all fail. Can someone spot an error, or suggest a workaround? Thank you in advance.
Update: I have found a solution: use a wrapper function from the functools package to set the parameters.
import functools as ft
SSVOptionPriceObjFuncWrapper = ft.partial(SSVOptionPriceObjFunc, spot=spot,
spotInterestRate=0.01 * r, daysInYear=daysInYear, marketPrices=mktPrices,
marketVolSurface=volSurface)
Then pass SSVOptionPriceObjFuncWrapper to the minimizer with args = None
Thank you for the replies.
Take the documented minimize inputs seriously. It's your job to write the function to fit what minimize does, not the other way around.
scipy.optimize.minimize(fun, x0, args=(),
fun: callable
The objective function to be minimized.
fun(x, *args) -> float
where x is an 1-D array with shape (n,) and args is a tuple of the fixed
parameters needed to completely specify the function.

numpy matrix trace behaviour

If X is a NumPy matrix object, why does np.trace(X) return a scalar (as expected) but X.trace() return a 1x1 matrix object?
>>> X = np.matrix([[1, 2], [3, 4]])
>>> np.trace(X)
5
>>> X.trace()
matrix([[5]]) # Why not just 5, which would be more useful?
I'm using NumPy 1.7.1, but don't see anything in the release notes of 1.8 to suggest anything's changed.
def __array_finalize__(self, obj):
self._getitem = False
if (isinstance(obj, matrix) and obj._getitem): return
ndim = self.ndim
if (ndim == 2):
return
if (ndim > 2):
newshape = tuple([x for x in self.shape if x > 1])
ndim = len(newshape)
if ndim == 2:
self.shape = newshape
return
elif (ndim > 2):
raise ValueError("shape too large to be a matrix.")
else:
newshape = self.shape
if ndim == 0:
self.shape = (1, 1)
elif ndim == 1:
self.shape = (1, newshape[0])
return
This is from the matrix definition, subclassing ndarray. The trace function is not changed so it is actually the same function getting called.
This function is getting called every time a matrix object is created. The problem is that if ndims is less than 2, it is forced to be larger.
Then here comes some educated guess work, which i think should be true, but i'm not familiar enough with numpy codebase to figure it out exactly.
np.trace and ndarray.trace are two different functions.
np.trace is defined in "core/fromnumeric.py"
ndarray.trace is defined in "core/src/multiarray/methods.c or calculation.c"
np.trace converts the object to a ndarray
ndarray.trace will try to keep the object as the subclassed object.
Unsure about this, i did not understand squat of that code tbh
both trace functions, will keep the result as an array object (subclassed or not). If it's a single value, it will return that single value, or else it returns the array object.
Since the result is kept as a matrix object, it will be forced to be two dimensional by the function above here. And because of this, it will not be returned as a single value, but as the matrix object.
This conclusion is further backed up by editing the _array_finalize__ function like this:
def __array_finalize__(self, obj):
self._getitem = False
if (isinstance(obj, matrix) and obj._getitem): return
ndim = self.ndim
if (ndim == 2):
return
if (ndim > 2):
newshape = tuple([x for x in self.shape if x > 1])
ndim = len(newshape)
if ndim == 2:
self.shape = newshape
return
elif (ndim > 2):
raise ValueError("shape too large to be a matrix.")
else:
newshape = self.shape
return
if ndim == 0:
self.shape = (1, 1)
elif ndim == 1:
self.shape = (1, newshape[0])
return
notice the new return before the last if-else check. Now the result of X.trace() is a single value.
THIS IS NOT A FIX, revert the change if you try this yourself.
They have good reasons for doing this
np.tracedoes not have this problems since it convert's it to an array object directly.
The code for np.trace is (without the docstring):
def trace(a, offset=0, axis1=0, axis2=1, dtype=None, out=None):
return asarray(a).trace(offset, axis1, axis2, dtype, out)
From the docstring of asarray
Array interpretation of a. No copy is performed if the input
is already an ndarray. If a is a subclass of ndarray, a base
class ndarray is returned.
Because X.trace is coded that way! The matrix documentation says:
A matrix is a specialized 2-D array that retains its 2-D nature
through operations.
np.trace is coded as (using ndarray.trace):
return asarray(a).trace(offset, axis1, axis2, dtype, out)
It's harder to follow how the matrix trace is evaluated. But looking at https://github.com/numpy/numpy/blob/master/numpy/matrixlib/defmatrix.py
I suspect it is equivalent to:
np.asmatrix(X.A.trace())
In that same file, sum is defined as:
return N.ndarray.sum(self, axis, dtype, out, keepdims=True)._collapse(axis)
mean, prod etc do the same. _collapse returns a scalar if axis is None. There isn't an explicit definition for a matrix trace, so it probably uses __array_finalize__. In other words, trace returns the default matrix type.
Several constructs that return the scalar are:
X.A.trace()
X.diagonal().sum()
X.trace()._collapse(None)