python numpy cython

python - Envoltura simple del código C con cython



numpy (4)

Aquí hay un ejemplo pequeño pero completo de pasar matrices numpy a una función C externa, lógicamente

fc( int N, double* a, double* b, double* z ) # z = a + b

usando Cython. (Esto seguramente es bien conocido por aquellos que lo conocen bien. Los comentarios son bienvenidos. Último cambio: 23 de febrero de 2011, para Cython 0.14).

Primero lee o desglosa la construcción de Cython y Cython con NumPy .

2 pasos:

  • python f-setup.py build_ext --inplace
    gira f.pyx y fc.cpp -> f.so , una biblioteca dinámica
  • python test-f.py
    import f cargas f.so ; f.fpy( ... ) llama al C fc( ... ) .

python f-setup.py usa distutils para ejecutar cython, compilar y vincular:
cython f.pyx -> f.cpp
compilar f.cpp y fc.cpp
link fo fc.o -> f.so , una lib dinámica que python import f cargará.

Para los estudiantes, sugeriría: haga un diagrama de estos pasos, revise los archivos a continuación, luego descárguelos y ejecútelos.

( distutils es un paquete enorme e intrincado que se usa para hacer paquetes de Python para su distribución e instalarlos. Aquí estamos usando solo una pequeña parte para compilar y vincular a f.so Este paso no tiene nada que ver con Cython, pero puede ser confuso, los errores simples en .pyx pueden causar páginas de mensajes de error oscuros de compilación y enlace de g ++. Consulte también las preguntas de distutils doc y / o SO en distutils ).

Al igual que make , setup.py volverá a ejecutar cython f.pyx y g++ -c ... f.cpp si f.pyx es más reciente que f.cpp .
Para limpiar, rm -r build/ .

Una alternativa a setup.py sería ejecutar los pasos por separado, en un script o Makefile:
cython --cplus f.pyx -> f.cpp # see cython -h
g++ -c ... f.cpp -> fo
g++ -c ... fc.cpp -> fc.o
cc-lib fo fc.o -> dynamic library f.so
Modifique el contenedor cc-lib-mac continuación para su plataforma e instalación: no es bonito, pero es pequeño.

Para ver ejemplos reales de Cython wrapping C, mire los archivos .pyx en cualquier SciKit .

Ver también: Cython para usuarios de NumPy y cython .

Para descomprimir los siguientes archivos, corte y pegue el lote en un archivo grande, digamos cython-numpy-c-demo , luego en Unix (en un nuevo directorio limpio) ejecute sh cython-numpy-c-demo .

#-------------------------------------------------------------------------------- cat >f.pyx <</! # f.pyx: numpy arrays -> extern from "fc.h" # 3 steps: # cython f.pyx -> f.c # link: python f-setup.py build_ext --inplace -> f.so, a dynamic library # py test-f.py: import f gets f.so, f.fpy below calls fc() import numpy as np cimport numpy as np cdef extern from "fc.h": int fc( int N, double* a, double* b, double* z ) # z = a + b def fpy( N, np.ndarray[np.double_t,ndim=1] A, np.ndarray[np.double_t,ndim=1] B, np.ndarray[np.double_t,ndim=1] Z ): """ wrap np arrays to fc( a.data ... ) """ assert N <= len(A) == len(B) == len(Z) fcret = fc( N, <double*> A.data, <double*> B.data, <double*> Z.data ) # fcret = fc( N, A.data, B.data, Z.data ) grr char* return fcret ! #-------------------------------------------------------------------------------- cat >fc.h <</! // fc.h: numpy arrays from cython , double* int fc( int N, const double a[], const double b[], double z[] ); ! #-------------------------------------------------------------------------------- cat >fc.cpp <</! // fc.cpp: z = a + b, numpy arrays from cython #include "fc.h" #include <stdio.h> int fc( int N, const double a[], const double b[], double z[] ) { printf( "fc: N=%d a[0]=%f b[0]=%f /n", N, a[0], b[0] ); for( int j = 0; j < N; j ++ ){ z[j] = a[j] + b[j]; } return N; } ! #-------------------------------------------------------------------------------- cat >f-setup.py <</! # python f-setup.py build_ext --inplace # cython f.pyx -> f.cpp # g++ -c f.cpp -> f.o # g++ -c fc.cpp -> fc.o # link f.o fc.o -> f.so # distutils uses the Makefile distutils.sysconfig.get_makefile_filename() # for compiling and linking: a sea of options. # http://docs.python.org/distutils/introduction.html # http://docs.python.org/distutils/apiref.html 20 pages ... # https://stackoverflow.com/questions/tagged/distutils+python import numpy from distutils.core import setup from distutils.extension import Extension from Cython.Distutils import build_ext # from Cython.Build import cythonize ext_modules = [Extension( name="f", sources=["f.pyx", "fc.cpp"], # extra_objects=["fc.o"], # if you compile fc.cpp separately include_dirs = [numpy.get_include()], # .../site-packages/numpy/core/include language="c++", # libraries= # extra_compile_args = "...".split(), # extra_link_args = "...".split() )] setup( name = ''f'', cmdclass = {''build_ext'': build_ext}, ext_modules = ext_modules, # ext_modules = cythonize(ext_modules) ? not in 0.14.1 # version= # description= # author= # author_email= ) # test: import f ! #-------------------------------------------------------------------------------- cat >test-f.py <</! #!/usr/bin/env python # test-f.py import numpy as np import f # loads f.so from cc-lib: f.pyx -> f.c + fc.o -> f.so N = 3 a = np.arange( N, dtype=np.float64 ) b = np.arange( N, dtype=np.float64 ) z = np.ones( N, dtype=np.float64 ) * np.NaN fret = f.fpy( N, a, b, z ) print "fpy -> fc z:", z ! #-------------------------------------------------------------------------------- cat >cc-lib-mac <</! #!/bin/sh me=${0##*/} case $1 in "" ) set -- f.cpp fc.cpp ;; # default: g++ these -h* | --h* ) echo " $me [g++ flags] xx.c yy.cpp zz.o ... compiles .c .cpp .o files to a dynamic lib xx.so " exit 1 esac # Logically this is simple, compile and link, # but platform-dependent, layers upon layers, gloom, doom base=${1%.c*} base=${base%.o} set -x g++ -dynamic -arch ppc / -bundle -undefined dynamic_lookup / -fno-strict-aliasing -fPIC -fno-common -DNDEBUG `# -g` -fwrapv / -isysroot /Developer/SDKs/MacOSX10.4u.sdk / -I/Library/Frameworks/Python.framework/Versions/2.6/include/python2.6 / -I${Pysite?}/numpy/core/include / -O2 -Wall / "$@" / -o $base.so # undefs: nm -gpv $base.so | egrep ''^ *U _+[^P]'' ! # 23 Feb 2011 13:38

Tengo varias funciones C y me gustaría llamarlas desde python. Cython parece ser el camino a seguir, pero realmente no puedo encontrar un ejemplo de cómo se hace esto exactamente. Mi función C se ve así:

void calculate_daily ( char *db_name, int grid_id, int year, double *dtmp, double *dtmn, double *dtmx, double *dprec, double *ddtr, double *dayl, double *dpet, double *dpar ) ;

Todo lo que quiero hacer es especificar los primeros tres parámetros (una cadena y dos enteros) y recuperar 8 matrices numpy (o listas de Python. Todas las matrices dobles tienen N elementos). Mi código asume que los punteros apuntan a un trozo de memoria ya asignado. Además, el código C producido debe vincularse a algunas bibliotecas externas.


Básicamente puedes escribir tu función de Cython de modo que asigne las matrices (asegúrate de que cimport numpy as np ):

cdef np.ndarray[np.double_t, ndim=1] rr = np.zeros((N,), dtype=np.double)

luego pase el puntero .data de cada uno a su función C. Eso debería funcionar. Si no necesita comenzar con ceros, puede usar np.empty para aumentar la velocidad.

Consulte el tutorial de Cython for NumPy Users en los documentos (lo corrigió en el enlace correcto).


Deberías Ctypes un vistazo a Ctypes que probablemente sea lo más fácil de usar si lo único que quieres es una función.