EconForge / interpolation.py

BSD 2-Clause "Simplified" License
123 stars 35 forks source link

literal type error when eval_spline() called without some keyword arguments #107

Closed fmwatson closed 11 months ago

fmwatson commented 1 year ago

Hi

I'm unable to directly use eval_splines at all, doing so raises a LiteralTypingError: somewhere either the module Numpy or an nb.Undefined gets passed to nb.literal().

I am trying to use the same input grid, coefficients and evaluation points as eval_cubic (which runs fine, and presumably calls eval_splines itself!), with order=3, with or without differentiation. My use case is an n-d function of 4+-d input, however I have get the same error even with simplified 1d interpolation with minimal example:

vals = np.random.rand(5)
grid = UCGrid((0., 1., 5))  
coef = filter_cubic(grid, vals)   
eval_spline(grid, coef, [0.22, 0.3], order=3)

Current package versions are: numba 0.56.4 interpolation 2.2.4 python 3.9.16 numpy 1.22.4

I see there have been similar patched issues in the past, so I have tried different versions of interpolation 2.2.0 - 2.2.4, numba 0.52 - 0.57, python 3.8/3.9 (other versions are not compatible with other dependencies). The only difference seems to be whether literal receives an Undefined or Numpy itself.

I might just be making a very basic usage error, but if not I'm not sure how to find the route cause here. I need to shift over to eval_spline to access differentiation!

Thanks for your help

albop commented 11 months ago

Hi @fmwatson,

That bug is not very easy to fix, but there is a simple workaround. You need to specify a value for all arguments of eval_spline. The following code works:

import numpy as np

from interpolation.splines import UCGrid, filter_cubic, eval_spline

vals = np.random.rand(5)
grid = UCGrid((0., 1., 5))  
coef = filter_cubic(grid, vals)   
x = np.array([0.22])

eval_spline(grid, coef, x, out=None, order=3, diff="None", extrap_mode="linear")

Reason arguments are passed as strings is to make them behave as litterals (i.e. a different function gets compiled for each value of them). With current version of numba, I haven't found a way to do that properly with named arguments. Not properly in the sense that it doesn't work for default values.

fmwatson commented 11 months ago

Thanks @albop - that works for me now, and it is indeed a simple workaround (sorry if this is documented elsewhere!)

I wondered if this would also fix what seemed like a similar issue I'm having trying to use eval_cubic/eval_spline in a prange loop, but I still get an error in this case: LoweringError: Failed in nopython mode pipeline (step: native lowering) scalar type Tuple(float64, float64, int64) given for non scalar argument #3

with example code

import numpy as np
import numba as nb
from interpolation.splines import UCGrid, filter_cubic, eval_spline

@nb.jit(nopython=True, parallel=True)
def run_in_pfor(vals, grid, coef, x):
    for i in nb.prange(6):
           _= eval_spline(grid, coef, x, out=None, order=3, diff="None", extrap_mode="linear")

vals = np.random.rand(5)
grid = UCGrid((0., 1., 5))  
coef = filter_cubic(grid, vals)   
x = np.array([0.22])
run_in_pfor(vals, grid, coef, x)

It looks like this was probably unrelated though (I think the error message has changed at least!) - so probably needs its own thread.

albop commented 11 months ago

Humm that's a new one. My guess is it is some limitation of numba parfor but I'm not sure which one (maybe tuple in parallel for loops).

The following code raises the same error:

import numpy as np
import numba as nb
from numba import prange

@nb.jit
def my_fun(vals, grid, coef, x):
    return vals[0] + coef[0] + x[0] + grid[0][0]

@nb.jit(nopython=True, parallel=True)
def run_in_pfor(vals, grid, coef, x):
    t = 0.0
    for h in prange(6):
        res = my_fun(vals, grid, coef, x)
        t += res
    return t

vals = np.random.rand(5)
grid = ((0., 1., 5),)  
coef = vals.copy()
x = np.array([0.22])
run_in_pfor(vals, grid, coef, x)

This indeed deserves its own thread, probably in numba though.

albop commented 11 months ago

I'm closing the issue here as there isn't much I can do about it.