Calling fortran/c code in scipy from numba

In the past, I have rewritten several scipy functions so I can call them from Numba. This is becoming easier with each Numba release due to the growing support for numpy and python functions.

But I am still facing a bottleneck when deep inside the scipy function a function written in fortran is called. In particular, I am trying to rewrite scipy.optimize.root which calls _root_hybr which calls minpack._hybrd.

The signature of minpack._hybrd is available as it is a compiled function? Is there an automatic way to use it from a numba njitted function? If not, how can I do it manually?

1 Like

Hi @hgrecco,

I think the issue here is that the scipy.optimize._minpack module is a C extension module which unfortunately doesn’t export the symbols you need. i.e.:

$ nm lib/python3.7/site-packages/scipy/optimize/_minpack.cpython-37m-x86_64-linux-gnu.so|grep hybrd
00000000000211e0 d doc_hybrd
00000000000066a0 t hybrd_
0000000000002f80 t minpack_hybrd

the hybrd_ symbol is likely the one from minpack itself, but it’s local only so Numba cannot bind to it.

Normally, if there’s a global symbol, you can just bind to the library with ctypes.CDLL and then get the address of the symbol and describe the argtypes/restype or create a ctypes.CFUNCTYPE for it and off you go. Example:

import ctypes as ct
DSO = ct.CDLL('libm.so')
fptr_cos = DSO.cos

# describe the function pointer
fptr_cos.argtypes = (ct.c_double,)
fptr_cos.restype = ct.c_double

print(fptr_cos(1.2))

# or bind with a CFUNCTYPE description
fty = ct.CFUNCTYPE(ct.c_double, ct.c_double)
bind = fty(fptr_cos)
print(bind(1.2))

from numba import njit

@njit
def foo(x):
    return bind(x), fptr_cos(x)

print(foo(1.2))

If you can get minpack as a library then the above ctypes binding could work.

Hope this helps?

Thanks a lot for the reply! It helps.