¿Cómo comstackr la extensión C para Python donde la función C usa la biblioteca LAPACK?

Escribí una versión en C para Python y el módulo se comstack con éxito en un archivo .so. Sin embargo, cuando bash utilizar la función C envuelta en el lado de Python (un código de prueba en Python que llama a la función C envuelta) obtengo el siguiente ImportError

 ImportError: /home/username/newModule.cpython-36m-x86_64-linux-gnu.so: undefined symbol: dgetri_ 

Estoy bastante seguro de que el undefined symbol: dgetri_ en el error de importación se debe a que el archivo .so generado no encontró el enlace a la biblioteca LAPACK . Así que mi pregunta es la siguiente,

¿Cómo compilo el código de extensión c para python cuando la función C envuelta depende de la biblioteca LAPACK para generar el módulo en formato .so ?

Actualmente estoy comstackndo el código C usando el módulo utils.core de python. Creo que necesito comstackr el código C desde la línea de comandos para vincular LAPACK pero no sé exactamente cuáles son los comandos apropiados para usar.

Cualquier ayuda es apreciada.

Puede estar interesado en usar scipy.linalg.cython_lapack . Proporciona acceso a la función dgetri LAPACK entre otros. Y la buena noticia es:

Esto hace posible utilizar BLAS y LAPACK de SciPy desde cualquier módulo de Cython de terceros sin vincular explícitamente con las bibliotecas. Esto significa que los proyectos como scikit-learn y statsmodels no necesitan mantener una dependencia de comstackción separada en BLAS y LAPACK.

Un ejemplo de uso de dger está disponible en Calling BLAS / LAPACK directamente usando la interfaz SciPy y Cython . Consulte también ¿ Mejora del rendimiento de Cython Lapack con definiciones de matriz internas? Detallé cómo usar cython_blas en mi respuesta a MPI python-Open-MPI , así que aquí es cómo se puede adaptar a dgetri:

  1. La parte crítica del código está escrita en Cython , en un archivo dedicado myinverse.pyx .

  2. Este archivo se convierte en un archivo myinverse.c por Cython

  3. Este archivo c es comstackdo por su comstackdor c gcc favorito para construir una biblioteca compartida myinverse.so

  4. La función optimizada se puede utilizar en su progtwig después de import myinverse .

Aquí hay un módulo de cython, que se colocará en el archivo .pyx:

 import numpy cimport numpy cimport scipy.linalg.cython_lapack ctypedef numpy.float64_t DTYPE_t cimport cython from libc.stdlib cimport malloc, free @cython.boundscheck(False) @cython.wraparound(False) @cython.nonecheck(False) def invert(numpy.ndarray[DTYPE_t, ndim=2] array): cdef int rows = array.shape[0] cdef int cols = array.shape[1] cdef int info = 0 if cols !=rows: return array,1,"not a square matrix" cdef int* ipiv =  malloc(rows * sizeof(int)) if not ipiv: raise MemoryError() scipy.linalg.cython_lapack.dgetrf(&cols,&rows,&array[0,0],&rows,ipiv,&info) if info !=0: free(ipiv) return array,info,"dgetrf failed, INFO="+str(info) #workspace query cdef double workl cdef int lwork=-1 scipy.linalg.cython_lapack.dgetri(&cols,&array[0,0],&rows,ipiv,&workl,&lwork,&info) if info !=0: free(ipiv) return array,info,"dgetri failed, workspace query, INFO="+str(info) #allocation workspace lwork= int(workl) cdef double* work =  malloc(lwork * sizeof(double)) if not work: raise MemoryError() scipy.linalg.cython_lapack.dgetri(&cols,&array[0,0],&rows,ipiv,work,&lwork,&info) if info !=0: free(ipiv) free(work) return array,info,"dgetri failed, INFO="+str(info) free(ipiv) free(work) return array,info,"" 

Para citonizar y comstackr el archivo .pyx, se puede usar el siguiente makefile (espero que estés usando Linux …)

 all: myinverse myinverseb myinverse: myinverse.pyx cython -a myinverse.pyx myinverseb: myinverse.c gcc -shared -pthread -fPIC -fwrapv -O2 -Wall -fno-strict-aliasing -I/usr/include/python2.7 -o myinverse.so myinverse.c 

La nueva función myinverse de python, chainng LAPACK’s dgetrf() y dgetri() , se llama en el archivo principal de python:

 import numpy as np import myinverse n=42 #A=np.zeros((n,n)) #for i in range(n): # A[i,i]=10 A=np.random.rand(n,n) #A=np.zeros((n,n)) Am,info,string=myinverse.invert(A.copy()) if info==0: print np.linalg.norm(A.dot(Am)-np.identity(n), np.inf) else : print "inversion failed, info=",info, string 

Alternativamente, conseguí que mi código funcionara utilizando las siguientes dos líneas mientras comstackba en linux

 $gcc -DNDEBUG -Wall -Wstrict-prototypes -fPIC -I/home/username/anaconda3/include/python3.6m -c stackDoc.cpp -o mydemo.o $gcc -shared mydemo.o -o mydemo.so 

El siguiente enlace me pareció útil, https://docs.python.org/2/extending/building.html