[SOLVED] Cannot resolve Numba TypingError

Issue

There is a procedure involving a search over an (eventually) big number of parameter combinations that I am trying to speed up using numba.
I tried to change my initial code to make it compatible but still got a TypingError I do not know how to resolve. I had many issues when using ‘np.asarray()’ so I removed that and am mostly dealing with standard lists now but it still does not work.
I will only mention the parts of the code that seem relevant given the error message, if more is needed, I will supply that too (just to keep it fairly short).

The seemingly crucial part of the error message (the rest, as far as I can tell, is just due to this function being called within another which is again called within another) reads:

Failed in nopython mode pipeline (step: nopython frontend)
No implementation of function Function(<function dot at 0x0000021490EA2400>) found for signature:

dot(list(list(float64)<iv=None>)<iv=None>, reflected list(float64)<iv=None>)

There are 4 candidate implementations:
– Of which 4 did not match due to:
Overload in function ‘_OverloadWrapper._build..ol_generated’: File: numba\core\overload_glue.py: Line 131.
With argument(s): ‘(list(list(float64)<iv=None>)<iv=None>, reflected list(float64)<iv=None>)’:
Rejected as the implementation raised a specific error:
TypingError: Failed in nopython mode pipeline (step: nopython frontend)
No implementation of function Function() found for signature:

  >>> stub(list(list(float64)<iv=None>)<iv=None>, reflected list(float64)<iv=None>)

It seems to originate from the function ‘nvaxes_lab’ defined as follows:

# reference position of NV axis vectors, each row holds the orientation (vector) of one NV axis    
nvaxes_ref = [[1.0, 1.0, 1.0],
     [-1.0, 1.0, -1.0], [1.0, -1.0, -1.0], [-1.0, -1.0, 1.0]]

@njit()
def rot_euler(a, b, g):
    """
    :param a: float, angle of third rotation (around z-axis) in radians
    :param b: float, angle of second rotation (around x-axis) in radians
    :param g: float, angle of first rotation (around z-axis) in radians
    :return: rotation matrix for a general rotation around the Euler angles a (=alpha), b (=beta), g (=gamma) defined
        as follows: rot_euler(a,b,g) = rotZ(a).rotX(b).rotZ(g)
    """
    return [[np.cos(a) * np.cos(g) - np.cos(b) * np.sin(a) * np.sin(g),
             -np.cos(b) * np.cos(g) * np.sin(a) - np.cos(a) * np.sin(g), np.sin(a) * np.sin(b)],
            [np.cos(g) * np.sin(a) + np.cos(a) * np.cos(b) * np.sin(g),
             np.cos(a) * np.cos(b) * np.cos(g) - np.sin(a) * np.sin(g), -np.cos(a) * np.sin(b)],
            [np.sin(b) * np.sin(g), np.cos(g) * np.sin(b), np.cos(b)]]

@njit()    
def nvaxes_lab(a, b, g):
    """
    :param a: float, angle of third Euler rotation (around z-axis) in radians
    :param b: float, angle of second Euler rotation (around x-axis) in radians
    :param g: float, angle of first Euler rotation (around z-axis) in radians
    :return: numpy array of dimensions 3x4, each row holds the orientation (vector) of the corresponding NV-axis
        after rotation by the Euler angles a,b,g
    """
    return [np.dot(rot_euler(a, b, g), nvaxes_ref[0]).astype(float), np.dot(rot_euler(a, b, g), nvaxes_ref[1]).astype(float),
            np.dot(rot_euler(a, b, g).astype(float), nvaxes_ref[2]), np.dot(rot_euler(a, b, g), nvaxes_ref[3]).astype(float)]

The problem seems to be the dot product in each component of the array returned in ‘nvaxes_lab’ … unfortunately, I have no idea how to define the arrays (I tried out multiple versions) or what else I could do to make this error disappear since this is the first time I am using numba.

I would appreciate your help!

Solution

You have a couple of issues. First, the actual error you are seeing comes from when numba compile your function, it uses the C implementations of the numpy functions. Those implementations expect numpy arrays, not lists. So the error:

dot(list(list(float64)<iv=None>)<iv=None>, reflected list(float64)<iv=None>)

is basically trying to tell you that the np.dot function doesn’t know how to handle lists. In the python version, it will coerce the lists to a numpy array, but I guess not in the C/numba version. You can either wrap np.array around each list, or a better option would be to output an array rot_euler.

Next, it is best practice to not reference mutable variables that are defined outside the scope of the function that you are trying to JIT. In nvaxes_lab, you reference each of the elements of nvaxes_ref. You are better off passing those in as a parameter of the function, and to be consistent, also make them an array.

Last, you docstring doesn’t match your return type for nvaxes_lab. You can just vstack the entire list to make it an array.

In terms of converting stuff to floats, because the nvaxes_ref array is already a float array, all of the outputs will be floats as well, so you can drop the astype methods.

import numpy as np
from numba import njit


nvaxes_ref = np.array([
     [1.0, 1.0, 1.0],
     [-1.0, 1.0, -1.0], 
     [1.0, -1.0, -1.0], 
     [-1.0, -1.0, 1.0]
])

@njit
def rot_euler(a, b, g):
    """
    :param a: float, angle of third rotation (around z-axis) in radians
    :param b: float, angle of second rotation (around x-axis) in radians
    :param g: float, angle of first rotation (around z-axis) in radians
    :return: rotation matrix for a general rotation around the Euler angles
        a (=alpha), b (=beta), g (=gamma) defined as follows: 
        rot_euler(a,b,g) = rotZ(a).rotX(b).rotZ(g)
    """
    return np.array([
        [
            np.cos(a) * np.cos(g) - np.cos(b) * np.sin(a) * np.sin(g), 
            -np.cos(b) * np.cos(g) * np.sin(a) - np.cos(a) * np.sin(g), 
            np.sin(a) * np.sin(b)
        ],
        [
            np.cos(g) * np.sin(a) + np.cos(a) * np.cos(b) * np.sin(g),
            np.cos(a) * np.cos(b) * np.cos(g) - np.sin(a) * np.sin(g), 
            -np.cos(a) * np.sin(b)
        ],
        [
            np.sin(b) * np.sin(g), 
            np.cos(g) * np.sin(b), 
            np.cos(b)
        ]
    ])

@njit
def nvaxes_lab(a, b, g, refs):
    """
    :param a: float, angle of third Euler rotation (around z-axis) in radians
    :param b: float, angle of second Euler rotation (around x-axis) in radians
    :param g: float, angle of first Euler rotation (around z-axis) in radians
    :return: numpy array of dimensions 3x4, each row holds the orientation (vector) 
             of the corresponding NV-axis after rotation by the Euler angles a,b,g
    """
    return [
            np.dot(rot_euler(a, b, g), refs[0]),
            np.dot(rot_euler(a, b, g), refs[1]),
            np.dot(rot_euler(a, b, g), refs[2]),
            np.dot(rot_euler(a, b, g), refs[3])
    ]

Answered By – James

Answer Checked By – Clifford M. (BugsFixing Volunteer)

Leave a Reply

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