0

I'm trying to write a function that can be vectorized by numba to act as a ufunc on a set of arrays:

from numba import float32, float64, vectorize

@vectorize([float32, float32, float32, float32(float32, float32, float32, float32, float32, float32, float32, numba.float32),
            float64, float64, float64, float64(float64, float64, float64, float64, float64, float64, float64, numba.float64)])
def _cafec_coeff_ufunc(ET_bar,
                       PET_bar,
                       R_bar,
                       PR_bar,
                       L_bar,
                       PL_bar,
                       RO_bar,
                       PRO_bar):
            
    # calculate alpha
    if PET_bar == 0:
        if ET_bar == 0:
            alpha = 1
        else:
            alpha = 0
    else:
        alpha = ET_bar / PET_bar

    # calculate beta
    if PR_bar == 0:
        if R_bar == 0:
            beta = 1
        else:
            beta = 0
    else:
        beta = R_bar / PR_bar

    # calculate gamma
    if PRO_bar == 0:
        if RO_bar == 0:
            gamma = 1
        else:
            gamma = 0
    else:
        gamma = RO_bar / PRO_bar

    # calculate delta
    if PL_bar == 0:
        if L_bar == 0:
            delta = 1
        else:
            delta = 0
    else:
        delta = L_bar / PL_bar

    return alpha, beta, gamma, delta

I call the above function in another function, passing the eight arrays it needs as arguments. My expectation is that this function will be applied in a broadcasting fashion, as if a 1-D loop for each element i (assuming all input arrays are equal size) with the ufunc getting scalars from each array at the i-th index as its arguments, finally returning with four arrays with corresponding values in the i-th locations of the output arrays (result of the ufunc broadcast reduced into output arrays).

alpha, beta, gamma, delta = _cafec_coeff_ufunc(ETbar, PETbar, Rbar, PRbar, Lbar, PLbar, RObar, PRObar)

When I run the code above as part of a unit test for the calling method I get the following errors in console:

  File "C:\home\git\indices_python\palmer.py", line 342, in <module>
    numba.float64, numba.float64, numba.float64, numba.float64(numba.float64, numba.float64, numba.float64, numba.float64, numba.float64, numba.float64, numba.float64, numba.float64)])
  File "C:\Anaconda3\lib\site-packages\numba\npyufunc\decorators.py", line 120, in wrap
    vec.add(sig)
  File "C:\Anaconda3\lib\site-packages\numba\npyufunc\dufunc.py", line 139, in add
    args, return_type = sigutils.normalize_signature(sig)
  File "C:\Anaconda3\lib\site-packages\numba\sigutils.py", line 35, in normalize_signature
    % (sig.__class__.__name__,))
TypeError: invalid signature: 'Float' instance not allowed

I can modify the signature by adding quotes around the signature itself in order to turn it into a string. and when I do this the error now becomes this:

  File "C:\home\git\indices_github\palmer.py", line 346, in <module>
    @numba.vectorize(['f8,f8,f8,f8(f8,f8,f8,f8,f8,f8,f8,f8)'])
  File "C:\home\Anaconda3\lib\site-packages\numba\npyufunc\decorators.py", line 120, in wrap
    vec.add(sig)
  File "C:\home\Anaconda3\lib\site-packages\numba\npyufunc\dufunc.py", line 139, in add
    args, return_type = sigutils.normalize_signature(sig)
  File "C:\home\Anaconda3\lib\site-packages\numba\sigutils.py", line 45, in normalize_signature
    check_type(ty)
  File "C:\home\Anaconda3\lib\site-packages\numba\sigutils.py", line 40, in check_type
    "got %r" % (ty,))
TypeError: invalid signature: expected a type instance, got (float64, float64, float64, float64, float64, float64, float64, float64) -> float64

What am I doing wrong here?

halfer
  • 19,824
  • 17
  • 99
  • 186
James Adams
  • 8,448
  • 21
  • 89
  • 148
  • I think the problem is that numba is incompatible with returning tuples of numpy arrays. What is the goal? Just want a code that is running fast? How flexible are you on return types? How long are the vectors? – Okapi575 Dec 20 '17 at 13:32
  • Thanks. Yes, I think this is true. I was able to break this into a single ufunc that I now call four times with different array inputs. The signature is "f8(f8,f8)" now and all is working as expected. The vectors being processed here are not long, so I'm not sure if this gives much of a performance boost, I should test... – James Adams Dec 21 '17 at 01:07

0 Answers0