Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Cython calling lapack, error: `Cannot take address of Python variable'

My problem is very similar to that posed here, and so I am trying to implement what was proposed in the answer there, based on this example of calling blas bundled with python. My code is only a slightly modified version of that example.pyx, here's my relevant code (with file f2pyptr.h unchanged) :

#example.pyx (single precision linear system solver via lapack)
import numpy as np
import scipy.linalg.lapack
import cython
cimport numpy as np

cdef extern from "/(pwd)/f2pyptr.h":
void *f2py_pointer(object) except NULL

ctypedef int sgesv_t(
int *N, int *NRHS,
float *A, int* LDA,
int* IPIV,
float *B,
int *LDB,
int *INFO)

cdef sgesv_t *sgesv = <sgesv_t*>f2py_pointer(scipy.linalg.lapack.sgesv._cpointer)

def myfunc_sgesv():
  cdef int N, NRHS, LDA, LDB, INFO
  N = 10
  NRHS = 1
  LDA = 10
  LDB = 10
  cdef np.ndarray[np.float32_t, ndim=2] A = np.ones((N,N), np.float32, order = "F")
  cdef np.ndarray[np.float32_t, ndim=2] B = np.ones((N, NRHS),np.float32, order = "F")
  cdef np.ndarray[np.int_t, ndim=1] IPIV = np.empty((N,), dtype = np.int)
  sgesv(&N, &NRHS, &A[0,0], &LDA, &IPIV, &B[0,0], &LDB, &INFO)*

def myfunc_sgesv():
  cdef int N, NRHS, LDA, LDB, INFO
  N = 10
  NRHS = 1
  LDA = 10
  LDB = 10

  cdef np.ndarray[np.float32_t, ndim=2] A = np.ones((N,N), np.float32, order = "F")
  cdef np.ndarray[np.float32_t, ndim=2] B = np.ones((N, NRHS),np.float32, order = "F")
  cdef np.ndarray[np.int_t, ndim=1] IPIV = np.empty((N,), dtype = np.int)

  sgesv(&N, &NRHS, &A[0,0], &LDA, &IPIV, &B[0,0], &LDB, &INFO)

With the standard setup.py file, I call python setup.py build_ext --inplace

which results in

Compiling example.pyx because it changed.
Cythonizing example.pyx

Error compiling Cython file:
------------------------------------------------------------
...

    cdef np.ndarray[np.float32_t, ndim=2] A = np.ones((N,N), np.float32, order = "F")
    cdef np.ndarray[np.float32_t, ndim=2] B = np.ones((N, NRHS),np.float32, order = "F")
    cdef np.ndarray[np.int_t, ndim=1] IPIV = np.empty((N,), dtype = np.int)

    sgesv(&N, &NRHS, &A[0,0], &LDA, &IPIV, &B[0,0], &LDB, &INFO)
                            ^
------------------------------------------------------------

example.pyx:103:33: Cannot take address of Python variable
Traceback (most recent call last):
File "setup.py", line 5, in <module>
ext_modules = cythonize("example.pyx")
File "/idiap/home/jnewling/.local/lib/python2.7/site-packages/Cython-0.20.1/Cython/Buil/Dependencies.py", line 785, in cythonize
cythonize_one(*args[1:]) File "/idiap/home/jnewling/.local/lib/python2.7/site-packages/Cython-0.20.1/Cython/Buil/Dependencies.py", line 902, in cythonize_one raise CompileError(None, pyx_file) Cython.Compiler.Errors.CompileError: example.pyx

I have the original example.pyx running fine, as well as a modified single precision version (i.e. sgemm), and so cannot see why my sgesv implementation fails.

Any specific diagnosis or suggestions of alternative approaches would be most welcome.

like image 250
newling Avatar asked Jul 15 '26 15:07

newling


1 Answers

Not sure if this answer is correct, but I will tell you what I tried as it may help you:

I got the error Cannot take address of Python variable at a different place when I compiled your code. I got the error at & IPIV. I then noticed it is an array so I changed it to:

sgesv(&N, &NRHS, &A[0,0], &LDA, &IPIV[0], &B[0,0], &LDB, &INFO). I then got the error Cannot assign type 'int_t *' to 'int *' . Then found the following answer: Passing numpy integer array to c code and changed the code to:

cdef np.ndarray[int, ndim=1, mode='c'] IPIV = np.empty((N,), dtype = ctypes.c_int) sgesv(&N, &NRHS, &A[0,0], &LDA, &IPIV[0], &B[0,0], &LDB, &INFO)

and now it compiles without any errors.

like image 51
Yuvika Avatar answered Jul 18 '26 04:07

Yuvika



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!