sexta-feira, 22 de agosto de 2014

Python + Numpy + C

Nesse post, vou mostrar um exemplo que fiz de como usar as UFuncs do Numpy. Me baseei neste link (Escrevendo sua própria ufunc) para fazer esse código.
No exemplo, eu criei duas funções em C para usar no Python. Segue o código do arquivo "minhasufuncs.c".

 #include "Python.h"  
 #include "math.h"  
 #include "numpy/ndarraytypes.h"  
 #include "numpy/ufuncobject.h"  

 // Estrutura usada para descrever um método de um tipo de extensão.  
 static PyMethodDef MinhasufuncsMethods[] = {  
     {NULL, NULL, 0, NULL}  
 };  
 //Função 1  
 static void double_FtoERB(char **args, npy_intp *dimensions,  
               npy_intp* steps, void* data)  
 {  
   npy_intp i;  
   npy_intp n = dimensions[0];  
   char *in = args[0], *out = args[1];  
   npy_intp in_step = steps[0], out_step = steps[1];  
   for (i = 0; i < n; i++) {  
     *((double *)out) = 24.7 * (4.37 * 1E-3 * (*(double *)in) + 1.);  
     in += in_step;  
     out += out_step;  
   }  
 }  
 // Função 2  
 static void double_sinc(char **args, npy_intp *dimensions,  
               npy_intp* steps, void* data)  
 {  
   npy_intp i;  
   npy_intp n = dimensions[0];  
   char *in = args[0], *out = args[1];  
   npy_intp in_step = steps[0], out_step = steps[1];  
   for (i = 0; i < n; i++) {  
     *((double *)out) = sin((*(double *)in)) / (*(double *)in) ;  
     in += in_step;  
     out += out_step;  
   }  
 }  
 // Estes são ponteiros para as funções acima  
 PyUFuncGenericFunction FtoERBfuncs[1] =   {&double_FtoERB};  
 PyUFuncGenericFunction sincfuncs[1] =   {&double_sinc};  
 // Estes são as entradas e retorna os dtypes  
 static char FtoERBtypes[2] = {NPY_DOUBLE, NPY_DOUBLE};  
 static char sinctypes[2] = {NPY_DOUBLE, NPY_DOUBLE};  
 static void *FtoERBdata[1] = {NULL};  
 static void *sincdata[1] = {NULL};  
 // Inicializa o módulo "minhasufuncs"  
 PyMODINIT_FUNC initminhasufuncs(void)  
 {  
   PyObject *m, *FtoERB, *sinc, *d;  
   m = Py_InitModule("minhasufuncs", MinhasufuncsMethods);  
   if (m == NULL) {  
     return;  
   }  
   import_array();  
   import_umath();  
   FtoERB = PyUFunc_FromFuncAndData(FtoERBfuncs, FtoERBdata, FtoERBtypes, 1, 1, 1,  
                   PyUFunc_None, "FtoERB",  
                   "FtoERB_docstring", 0);  
   sinc = PyUFunc_FromFuncAndData(sincfuncs, sincdata, sinctypes, 1, 1, 1,  
                   PyUFunc_None, "sinc",  
                   "sinc_docstring", 0);  
   d = PyModule_GetDict(m);  
   PyDict_SetItemString(d, "FtoERB", FtoERB);  
   Py_DECREF(FtoERB);  
   PyDict_SetItemString(d, "sinc", sinc);  
   Py_DECREF(sinc);  
 }  

São criadas duas funções para ser usadas no Python: "FtoERB" e "sinc". Tais funções serão chamadas a partir de um módulo a ser importado no Python, nesse caso, chamado "minhasufuncs". Para gerar a biblioteca compartilhada, usei um arquivo "setup.py". Segue:

 def configuration(parent_package='', top_path=None):  
   import numpy  
   from numpy.distutils.misc_util import Configuration  
   config = Configuration('',  
               parent_package,  
               top_path)  
   config.add_extension('minhasufuncs', ['minhasufuncs.c'])  
   return config  
 if __name__ == "__main__":  
   from numpy.distutils.core import setup  
   setup(configuration=configuration)  

E rode o comando:
 $ python setup.py build_ext --inplace   

Com isso, será gerado um arquivo "minhasufuncs.so". É só chama-lo no Python. Então segue um código-exemplo que chama essas funções.

 # -*- coding: utf-8 -*-  
 #/usr/bin/python  
   
 import numpy as np  
 import minhasufuncs  
 import matplotlib.pyplot as mpl  
   
 x1 = np.linspace(-30,30,8000)  
 y1 = minhasufuncs.sinc(x1)  
 x2 = np.linspace(0,8000,8000)  
 y2 = minhasufuncs.FtoERB(x2)  
 mpl.figure(figsize=(7,12))  
 mpl.subplot(211)  
 mpl.plot(x1,y1,'k',lw=2)  
 mpl.grid()  
 mpl.subplot(212)  
 mpl.plot(x2,y2,'k',lw=2)  
 mpl.grid()  
 mpl.savefig('minhasufuncs.png')  

Os gráficos gerados foram:

CLIQUE AQUI para baixar os meus arquivos.

É isso aí!

Nenhum comentário:

Postar um comentário