67 votes

Distribuer des extensions basées sur Cython en utilisant LAPACK

Je suis en train d'écrire un module Python qui inclut des extensions Cython et utilise LAPACK (et BLAS ). Je suis prêt à utiliser soit clapack ou lapacke ou une sorte de f2c ou f2py solution si nécessaire. Ce qui est important, c'est que je puisse appeler lapack y blas des routines de Cython dans des boucles serrées sans surcharge d'appels Python.

J'ai trouvé un exemple aquí . Cependant, cet exemple dépend de SAGE. Je veux que mon module puisse être installé sans installer SAGE, car mes utilisateurs ne voudront probablement pas ou n'auront pas besoin de SAGE pour autre chose. Mes utilisateurs sont susceptibles d'avoir installé des paquets tels que numpy, scipy, pandas et scikit learn, ce qui constitue des dépendances raisonnables. Quelle est la meilleure combinaison d'interfaces à utiliser, et à quoi ressemblerait le fichier setup.py minimal qui pourrait récupérer les informations nécessaires (de numpy, scipy, etc.) pour la compilation ?

EDIT : Voici ce que j'ai fini par faire. Cela fonctionne sur mon macbook, mais je n'ai aucune idée de sa portabilité. Il y a sûrement un meilleur moyen.

from distutils.core import setup
from distutils.extension import Extension
from Cython.Distutils import build_ext
import numpy
from Cython.Build import cythonize
from numpy.distutils.system_info import get_info

# TODO: This cannot be the right way
blas_include = get_info('blas_opt')['extra_compile_args'][1][2:]
includes = [blas_include,numpy.get_include()]

setup(
    cmdclass = {'build_ext': build_ext},
    ext_modules = cythonize([Extension("cylapack", ["cylapack.pyx"],
                                       include_dirs = includes,
                                       libraries=['blas','lapack'])
                   ])
)

Cela fonctionne parce que, sur mon macbook, l'option clapack.h se trouve dans le même répertoire que le fichier d'en-tête cblas.h . Je peux alors faire cela dans mon fichier pyx :

ctypedef np.int32_t integer

cdef extern from "cblas.h":
    double cblas_dnrm2(int N,double *X, int incX)
cdef extern from "clapack.h":
    integer dgelsy_(integer *m, integer *n, integer *nrhs, 
    double *a, integer *lda, double *b, integer *ldb, integer *
    jpvt, double *rcond, integer *rank, double *work, integer *
    lwork, integer *info)

6voto

ajcr Points 4047

Si j'ai bien compris la question, vous pourriez utiliser les wrappers Cython de SciPy pour les routines BLAS et LAPACK. Ces wrappers sont documentés ici :

Comme l'indique la documentation, il vous incombe de vérifier que tous les tableaux que vous passez à ces fonctions sont correctement alignés pour les routines Fortran. Vous pouvez simplement importer et utiliser ces fonctions selon vos besoins dans votre fichier .pyx. Par exemple :

from scipy.linalg.cython_blas cimport dnrm2 
from scipy.linalg.cython_lapack cimport dgelsy 

Étant donné qu'il s'agit d'un code bien testé, largement utilisé et fonctionnant sur différentes plates-formes, je dirais qu'il s'agit d'un bon candidat pour distribuer de manière fiable les extensions Cython qui appellent directement les routines BLAS et LAPACK.


Si vous ne souhaitez pas que votre code dépende de l'ensemble de SciPy, vous pouvez trouver la plupart des fichiers pertinents pour ces fonctions d'habillage dans le répertoire SciPy linalg répertoire aquí . Une référence utile est ces lignes de setup.py qui listent les fichiers sources et les fichiers d'en-tête. Notez qu'un compilateur Fortran est nécessaire !

Sur théorie il devrait être possible d'isoler ici uniquement les fichiers sources nécessaires à la compilation des wrappers Cython BLAS et LAPACK, puis de les regrouper sous forme d'extension indépendante avec votre module.

Sur pratique c'est très délicat à faire. Le processus de construction du sous-module linalg nécessite quelques fonctions Python pour faciliter la compilation sur différentes plates-formes (par exemple, à partir de aquí ). La construction repose également sur d'autres fichiers sources C et Fortran ( aquí ), dont les chemins sont codés en dur dans ces fonctions Python.

Il est clair que beaucoup de travail a été fait pour s'assurer que SciPy compile correctement sur différents systèmes d'exploitation et architectures.

Je suis sûr que c'est possible, mais après avoir mélangé les fichiers et modifié les chemins, je n'ai pas encore trouvé le bon moyen de construire cette partie du sous-module linalg indépendamment du reste de SciPy. Si je trouve la bonne méthode, je ne manquerai pas de mettre à jour cette réponse.

3voto

totlmstr Points 61

SAGE est, d'après ce que j'ai compris, une interface pour Cython. Vous utilisez distutils ce qui devrait permettre de compiler comme indiqué ici : http://docs.cython.org/src/quickstart/build.html

Si vous vous interrogez encore sur la portabilité, cette page devrait vous aider : http://docs.cython.org/src/userguide/source_files_and_compilation.html

De plus, ces lignes, en supposant qu'elles se trouvent dans une setup.py fichier :

from distutils.core import setup 
from distutils.extension import Extension 
from Cython.Distutils import build_ext 

sont ceux qui font la compilation. De plus, ces lignes (de la docs) :

setup( 
    cmdclass = {'build_ext': build_ext}, 
    ext_modules = [Extension("grouptitle", ["file.c", "file2.c"])] 
) 

font référence au code C et y accèdent dans Cython pour être compilés. En d'autres termes, ce que vous avez maintenant, ce sont les exigences de base, et vous ne pouvez pas faire plus simple.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X