How do I vectorize a function which has multiple outputs with Numba?

For example, I want to vectorize the following function:

@nb.njit(nb.types.UniTuple(nb.float64,2)(nb.float64, nb.float64))
def add_subtract(x,y):
    return x+y, x-y

However, when I use @numba.vectorize like this:

@nb.vectorize([nb.types.UniTuple(nb.float64,2)(nb.float64, nb.float64)])
def add_subtract(x,y):
    return x+y, x-y

It will show:

NotImplementedError                       Traceback (most recent call last)
<ipython-input-80-4e6510dce1de> in <module>
      1 @nb.vectorize([nb.types.UniTuple(nb.float64,2)(nb.float64, nb.float64)])
----> 2 def add_subtract(x,y):
      3     return x+y, x-y

E:anaconda3libsite-packagesnumbanpufuncdecorators.py in wrap(func)
    118         vec = Vectorize(func, **kws)
    119         for sig in ftylist:
--> 120             vec.add(sig)
    121         if len(ftylist) > 0:
    122             vec.disable_compile()

E:anaconda3libsite-packagesnumbanpufuncdufunc.py in add(self, sig)
    168         """
    169         args, return_type = sigutils.normalize_signature(sig)
--> 170         return self._compile_for_argtys(args, return_type)
    171 
    172     def _compile_for_args(self, *args, **kws):

E:anaconda3libsite-packagesnumbanpufuncdufunc.py in _compile_for_argtys(self, argtys, return_type)
    220         actual_sig = ufuncbuilder._finalize_ufunc_signature(
    221             cres, argtys, return_type)
--> 222         dtypenums, ptr, env = ufuncbuilder._build_element_wise_ufunc_wrapper(
    223             cres, actual_sig)
    224         self._add_loop(utils.longint(ptr), dtypenums)

E:anaconda3libsite-packagesnumbanpufuncufuncbuilder.py in _build_element_wise_ufunc_wrapper(cres, signature)
    177     # Get dtypes
    178     dtypenums = [as_dtype(a).num for a in signature.args]
--> 179     dtypenums.append(as_dtype(signature.return_type).num)
    180     return dtypenums, ptr, cres.environment
    181 

E:anaconda3libsite-packagesnumbanpnumpy_support.py in as_dtype(nbtype)
    149     if isinstance(nbtype, types.PyObject):
    150         return np.dtype(object)
--> 151     raise NotImplementedError("%r cannot be represented as a Numpy dtype"
    152                               % (nbtype,))
    153 

NotImplementedError: UniTuple(float64 x 2) cannot be represented as a Numpy dtype

If I rewrite this function like this:

@nb.vectorize([nb.float64[:](nb.float64, nb.float64)])
def add_subtract(x,y):
    return np.array([x+y, x-y])

It will still show:

NotImplementedError: array(float64, 1d, A) cannot be represented as a Numpy dtype

How do I vectorize this function? Is it possible to vectorize a function which has multiple outputs?

Answer

vectorize only works on a single scalar output (broadcasted to the dimensions of your input vector). As a workaround you can use guvectorize:

import numpy as np
from numba import guvectorize


@guvectorize(
    ["void(float64[:], float64[:] , float64[:], float64[:])"], "(),()->(),()"
)
def add_subtract(x, y, s, d):
    s[:] = x + y
    d[:] = x - y


dim = (2, 3, 4)
x = np.random.random_sample(dim)
y = np.random.random_sample(dim)
s, d = add_subtract(x, y)

Leave a Reply

Your email address will not be published. Required fields are marked *