Maybe someone could help me:
Python 3.7
scipy 1.5.0
numpy 1.18.1
numba 0.49.1
numba-scipy 0.1.0
numba-special 0.2.0
> import numpy as np
> import numba as nb
> import scipy.special.cython_special
> print(scipy.special.cython_special.eval_legendre)
> print(scipy.special.cython_special.eval_legendre(2.0, 0.546))
I got
>> <cyfunction eval_legendre at 0x0000000012CAF588>
>> -0.05282599999999993
> addr = get_cython_function_address("scipy.special.cython_special", "eval_legendre")
> functype = ctypes.CFUNCTYPE(ctypes.c_double, ctypes.c_double, ctypes.c_double)
> eval_legendre_fn = functype(addr)
I got
File “C:\Users\Enot\PycharmProjects\GPU-DL\venv\lib\site-packages\numba\core\extending.py”, line 407, in get_cython_function_address return _import_cython_function(module_name, function_name)
ValueError: No function ‘eval_legendre’ found in pyx_capi of ‘scipy.special.cython_special’
Good people from https://gitter.im/numba/numba prompt me that:
`eval_legendre is not part of scipy.special.cython_special.pyx_capi (at least not with that name) and therefore numba simply cannot find it. And I have to find some kind of interface to a lower level function with another name.
'__pyx_fuse_0_0eval_legendre': <capsule object "__pyx_t_double_complex (double, __pyx_t_double_complex, int __pyx_skip_dispatch)" at 0x7f575f1c84e0>, '__pyx_fuse_0_1eval_legendre': <capsule object "double (double, double, int __pyx_skip_dispatch)" at 0x7f575f1c8510>, '__pyx_fuse_1_0eval_legendre': <capsule object "__pyx_t_double_complex (long, __pyx_t_double_complex, int __pyx_skip_dispatch)" at 0x7f575f1c8540>, '__pyx_fuse_1_1eval_legendre': <capsule object "double (long, double, int __pyx_skip_dispatch)" at 0x7f575f1c8570>,
I do not need complex numbers so I choose
‘__pyx_fuse_0_1eval_legendre’: <capsule object “double (double, double, int __pyx_skip_dispatch)” at 0x7f575f1c8510>
According to scipy docs: scipy.special.eval_legendre(n, x, out=None) n: array_like degree of the polynomial. xarray_like - points at which to evaluate
It is logical to assume that one of the "double"s - output; other double is input x; and degree of the polynomial is int.
So using an example from the link: support for scipy.special functions : feature request · Issue #3086 · numba/numba · GitHub and link complex argument support for erfc · Issue #1 · person142/numba_special · GitHub
I made smth like:
> import numba as nb
> from numba.extending import intrinsic
> from numba.core import cgutils
> import ctypes
> from numba import types
> from numba.extending import get_cython_function_address
> import scipy.special.cython_special
> from numba import njit
>
> _PTR = ctypes.POINTER
> _dble = ctypes.c_double
> _ptr_dble = _PTR(_dble)
>
> @intrinsic
> def val_to_double_ptr(typingctx, data):
> def impl(context, builder, signature, args):
> ptr = cgutils.alloca_once_value(builder,args[0])
> return ptr
> sig = types.CPointer(types.float64)(types.float64)
> return sig, impl
>
> @intrinsic
> def double_ptr_to_val(typingctx, data):
> def impl(context, builder, signature, args):
> val = builder.load(args[0])
> return val
> sig = types.float64(types.CPointer(types.float64))
> return sig, impl
>
> addr = get_cython_function_address("scipy.special.cython_special", "__pyx_fuse_0_1eval_legendre")
> functype = ctypes.CFUNCTYPE(None, _ptr_dble, _dble, _int)
> eval_legendre_float64_fn = functype(addr)
>
> @njit
> def numba_eval_legendre_float64(n, x):
> out_p = val_to_double_ptr(0.)
> eval_legendre_float64_fn(out_p, x, n)
> out = double_ptr_to_val(out_p)
> return out
>
> print("eval legendre: ", numba_eval_legendre_float64(2, 1.567))
This raises no error but return
> >> eval legendre: 0.0
So do nothing.
Any ideas on how to fix this?
Thank You.