मैंने पायथन के लिए एक सी एक्सटेंशन लिखा है और मॉड्यूल को एक .so फ़ाइल में सफलतापूर्वक संकलित किया गया है। हालांकि जब मैं पायथन पक्ष में लिपटे सी फ़ंक्शन का उपयोग करने की कोशिश कर रहा हूं (पायथन में एक परीक्षण कोड जो लिपटे सी फ़ंक्शन को कॉल करता है) मुझे निम्नलिखित मिलता है ImportError

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

मुझे पूरा यकीन है कि आयात त्रुटि में undefined symbol: dgetri_ इसलिए है क्योंकि जेनरेट की गई .so फ़ाइल को LAPACK लाइब्रेरी का लिंक नहीं मिला। तो मेरा प्रश्न निम्नलिखित है,

मैं अजगर के लिए c एक्सटेंशन कोड कैसे संकलित करूं, जब लपेटा हुआ C फ़ंक्शन .so प्रारूप में मॉड्यूल उत्पन्न करने के लिए LAPACK लाइब्रेरी पर निर्भर करता है?

वर्तमान में मैं अजगर के utils.core मॉड्यूल का उपयोग करके सी कोड संकलित कर रहा हूं। मुझे लगता है कि मुझे कमांड लाइन से LAPACK लिंक करने के लिए सी कोड को संकलित करने की आवश्यकता है, लेकिन यह नहीं पता कि उपयोग करने के लिए उपयुक्त कमांड कौन से हैं?

किसी भी मदद की सराहना की जाती है।

3
Geek 31 अगस्त 2018, 03:25

3 जवाब

आपकी रुचि scipy.linalg.cython_lapack. यह LAPACK के कार्य dgetri दूसरों के बीच में। और अच्छी खबर है:

यह पुस्तकालयों के साथ स्पष्ट रूप से लिंक किए बिना किसी भी तृतीय पक्ष साइथन मॉड्यूल से साइपी के बीएलएएस और लैपैक का उपयोग करना संभव बनाता है। इसका मतलब यह है कि स्किकिट-लर्न और स्टैटसमॉडल जैसी परियोजनाओं को BLAS और LAPACK पर एक अलग बिल्ड निर्भरता बनाए रखने की आवश्यकता नहीं है।

dger का उपयोग करने का एक उदाहरण Calling पर उपलब्ध है। BLAS / LAPACK सीधे SciPy इंटरफ़ेस और साइथन का उपयोग कर रहा है। यह भी देखें आंतरिक सरणी परिभाषाओं के साथ Cython Lapack के प्रदर्शन में सुधार? मैंने MPI python-Open-MPI के अपने उत्तर में cython_blas का उपयोग करने का तरीका बताया है। , तो यहां बताया गया है कि इसे dgetri के लिए कैसे अनुकूलित किया जा सकता है:

  1. कोड के महत्वपूर्ण भाग को एक समर्पित फ़ाइल myinverse.pyx में Cython में लिखा जाता है।

  2. साइथन द्वारा इस फ़ाइल को myinverse.c फ़ाइल में बदल दिया गया है

  3. यह सी फ़ाइल आपके पसंदीदा सी कंपाइलर gcc द्वारा एक साझा लाइब्रेरी बनाने के लिए संकलित की गई है myinverse.so

  4. अनुकूलित फ़ंक्शन का उपयोग आपके प्रोग्राम में import myinverse के बाद किया जा सकता है।

यहाँ एक साइथन मॉड्यूल है, जिसे .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 = <int *> 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 = <double *> 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,""

.pyx फ़ाइल को साइथोनाइज़ और संकलित करने के लिए, निम्न मेकफ़ाइल का उपयोग किया जा सकता है (मुझे आशा है कि आप लिनक्स का उपयोग कर रहे हैं ...)

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

नया अजगर myinverse फ़ंक्शन, चेनिंग LAPACK's dgetrf() और dgetri(), को मुख्य पायथन फ़ाइल में कहा जाता है:

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
2
francis 2 सितंबर 2018, 00:33
1
अतिरिक्त लाभ के रूप में: scipy में स्थापित BLAS/LAPACK पुस्तकालयों के विभिन्न संस्करणों के लिए कुछ संगतता कोड है, उदा। क्या scipy को MKL, OpenBLAS या अन्य के साथ बनाया गया था। इसका मतलब यह है कि जब scipy से साइथन रैपर का उपयोग किया जाता है, तो कॉलिंग कोड को इस बारे में चिंता करने की आवश्यकता नहीं होती है कि किस linalg लाइब्रेरी का उपयोग किया जाता है।
 – 
Josef
2 सितंबर 2018, 04:50
सभी विवरणों के लिए धन्यवाद। वे दिलचस्प पढ़ रहे हैं। हालाँकि मुझे linux में संकलन करते समय निम्नलिखित दो पंक्तियों का उपयोग करके अपना कोड काम करना पड़ा:
 – 
Geek
2 सितंबर 2018, 08:54

वैकल्पिक रूप से मैंने अपना कोड 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

निम्नलिखित लिंक मुझे उपयोगी लगा, https://docs.python.org/2/extending/build.html

1
Geek 2 सितंबर 2018, 08:59

वैकल्पिक रूप से आप मॉड्यूल को लैपैक से जोड़ने के लिए बना सकते हैं।

जैसे

from distutils.core import setup
from distutils.extension import Extension

setup(
    name='MyExtension',
    version='0.1',
    ext_modules=[
        Extension('lib_name', ['lib_name.cpp'], extra_link_args=['-lopenblas']),
    ],
    scripts=['lib_name.cpp', '__init__.py'],
)
0
user2980150 3 अप्रैल 2020, 13:40