Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Numba data type error: Cannot unify array

I am using Numba to speed up a series of functions as shown below. if I set the step_size variable in function PosMomentSingle to a float (e.g. step_size = 0.5), instead of an integer (e.g step_size = 1.0), I get the following error:

Cannot unify array(float32, 1d, C) and array(float64, 1d, C) for 'axle_coords.2', defined at <ipython-input-182-37c789ca2187> (12)

File "<ipython-input-182-37c789ca2187>", line 12:
def nbSimpleSpanMoment(L, axles, spacings, step_size):
    <source elided>
    
    while np.min(axle_coords) < L:

I found it quite hard to understand what the problem is, but my guess is there is an issue with the function after @jit (nbSimpleSpanMoment), with some kind of a datatype mismatch. I tried setting all variables to float32, then to float64 (e.g. L = np.float32(L)) but whatever I try creates a new set of errors. Since the error message is quite cryptic, I am unable to debug the issue. Can someone with numba experience explain what I am doing wrong here?

I placed my code below to recreate the problem.

Thank you for the help!

import numba as nb
import numpy as np

@nb.vectorize(nopython=True)
def nbvectMoment(L,x):
    if x<L/2.0:
        return 0.5*x
    else:
        return 0.5*(L-x)

@nb.jit(nopython=True)
def nbSimpleSpanMoment(L, axles, spacings, step_size):
    travel = L + np.sum(spacings)
    maxmoment = 0
    axle_coords = -np.cumsum(spacings)
    moment_inf = np.empty_like(axles)
    while np.min(axle_coords) < L:
        axle_coords = axle_coords + step_size
        y = nbvectMoment(L,axle_coords)
        for k in range(y.shape[0]):
            if axle_coords[k] >=0 and axle_coords[k] <= L:
                moment_inf[k] = y[k]
            else:
                moment_inf[k] = 0.0   
        moment = np.sum(moment_inf * axles)
        if maxmoment < moment:
            maxmoment = moment
    return np.around(maxmoment,1)

def PosMomentSingle(current_axles, current_spacings):
    data_list = []
    for L in range (1,201):
        L=float(L)        
        if L <= 40:
            step_size = 0.5
        else:
            step_size = 0.5            
        axles = np.array(current_axles, dtype='f')
        spacings = np.array(current_spacings, dtype='f')            
        axles_inv = axles[::-1]
        spacings_inv = spacings[::-1]           
        spacings = np.insert(spacings,0,0)
        spacings_inv = np.insert(spacings_inv,0,0)            
        left_to_right = nbSimpleSpanMoment(L, axles, spacings, step_size)
        right_to_left = nbSimpleSpanMoment(L, axles_inv, spacings_inv, step_size)            
        data_list.append(max(left_to_right, right_to_left))
    return data_list

load_effects = []
for v in range(14,31):
    load_effects.append(PosMomentSingle([8, 32, 32], [14, v]))
load_effects = np.array(load_effects)
like image 672
marillion Avatar asked Nov 02 '20 03:11

marillion


Video Answer


1 Answers

After removing all type conversions in your code, the following error was returned

TypingError: Cannot unify array(int64, 1d, C) and array(float64, 1d, C) for 'axle_coords.2'

This helped me to trace back the error to the dtype of spacings. In your code this initialized as a C compatible single, which seems to be different from a python float32, see here. After changing this to np.float64 the code now runs.

The code below now runs and unify error does not occur anymore.

import numba as nb
import numpy as np

@nb.vectorize(nopython=True)
def nbvectMoment(L,x):
    if x<L/2.0:
        return 0.5*x
    else:
        return 0.5*(L-x)

@nb.jit(nopython=True)
def nbSimpleSpanMoment(L, axles, spacings, step_size):
    travel = L + np.sum(spacings)
    maxmoment = 0
    axle_coords = -np.cumsum(spacings)
    moment_inf = np.empty_like(axles)
    while np.min(axle_coords) < L:
        axle_coords = axle_coords + step_size
        y = nbvectMoment(L,axle_coords)
        for k in range(y.shape[0]):
            if axle_coords[k] >=0 and axle_coords[k] <= L:
                moment_inf[k] = y[k]
            else:
                moment_inf[k] = 0.0
        moment = np.sum(moment_inf * axles)
        if maxmoment < moment:
            maxmoment = moment
    return np.around(maxmoment,1)

def PosMomentSingle(current_axles, current_spacings):
    data_list = []
    for L in range (1,201):
        L=float(L)
        if L <= 40:
            step_size = 0.5
        else:
            step_size = 0.5
        axles = np.array(current_axles, np.float32)
        spacings = np.array(current_spacings, dtype=np.float64)
        axles_inv = axles[::-1]
        spacings_inv = spacings[::-1]
        spacings = np.insert(spacings,0,0)
        spacings_inv = np.insert(spacings_inv,0,0)
        left_to_right = nbSimpleSpanMoment(L, axles, spacings, step_size)
        right_to_left = nbSimpleSpanMoment(L, axles_inv, spacings_inv, step_size)
        data_list.append(max(left_to_right, right_to_left))
    return data_list

load_effects = []
for v in range(14,31):
    load_effects.append(PosMomentSingle([8, 32, 32], [14, v]))
load_effects = np.array(load_effects)
like image 58
Timo Avatar answered Oct 05 '22 15:10

Timo