2011-04-28 16 views
8

Lo sé, a menudo hay muchas maneras de resolver ciertos problemas. Pero aquí yo sé qué camino quiero tener, pero no soy capaz de hacer que funcione con Python y el TRAGO ...Swig, devolviendo una matriz de dobles

Tengo un C-función, lo que me devuelve una matriz de valores dobles:

double *my(int x) 
{ 
    double a,b,*buf; 
    buf = malloc (x * sizeof(double)); 
    a=3.14; 
    b=2.7; 
    buf[0]=a; 
    buf[1]=b; 
    return buf; 
} 

Aquí, definitivamente quiero tener la matriz como un valor de retorno. No, como en muchos ejemplos, una función 'nula', que escribe en una matriz de entrada. Ahora, me gustaría obtener un envoltorio TRAGO-pitón, que podría ser utilizado como:

>>> import example 
>>> print example.my(7) 
[3.14,2.7] 

todo lo que hago, tengo algunos problemas conceptuales aquí - Siempre me s.th. como <Swig Object of type 'double *' at 0xFABCABA12>

traté de definir algunos typemaps en mi archivo SWG:

%typemap(out) double [ANY] { 
    int i; 
    $result = PyList_New($1_dim0); 
    for (i = 0; i < $1_dim0; i++) { 
    PyObject *o = PyFloat_FromDouble((double) $1[i]); 
    PyList_SetItem($result,i,o); 
    } 
} 

Pero todavía soy incapaz de salir mis resultados según sea necesario. ¿Alguien tiene un ejemplo de código simple para lograr esta tarea?

+0

ups, sí, este es un subconjunto súper pequeño del código real que tengo enfrente de mí. Perdón por la confusion. – user701370

Respuesta

-3

No sé cuánto sabes C - así que disculpas si estoy enseñando a chupar los huevos aquí ...

No hay ninguna clase Array en la llanura-ole C. Una matriz es siempre una apunta a una pieza de memoria, no es una "cosa" en sí misma y, por lo tanto, no puede simplemente imprimirse por sí misma.

En este caso, su "buf" es del tipo "doble *". AFAICRem, si desea imprimir los valores reales almacenados en "la memoria apuntada por buf", debe desasignar cada uno, p. Ej. (En pseudocódigo): para i = 0 para buflength print buf [i]

+1

Incorrecto: lea la sección 6 de [c-faq] (http://c-faq.com/). Las matrices no son punteros; los punteros no son matrices. – pmg

+0

Sí, no son idénticos ... ese no era mi punto. El punto es que en c, no se puede hacer, decir "my_array.length" En C, una matriz no sabe qué tan grande es (lo que hace en muchos lenguajes de OO) y no se puede imprimir con sensatez de la manera descrita arriba. Tienes que hacer el trabajo tú mismo. –

1

Usted Es posible que desee consultar la documentación en torno a carray.i:

% incluyen "carrays.i" % array_class (int, intArray);

http://www.swig.org/Doc2.0/Python.html#Python_nn48

+1

No veo cómo podrían funcionar para la salida (el caso de entrada es bastante claro en la documentación). ¿Podría dar un ejemplo? – kynan

4

El primer problema es que su typemap no coincide, se necesita un %typemap(out) double * { ... } ya que su función devuelve un puntero a doblar y no una doble matriz.

Si su lista es de tamaño fijo (es decir, un entero literal) como en el ejemplo que dio (que supongo que no es lo que quiere) simplemente podría cambiar el mapa de tipos como di más arriba e intercambiar $1_dim0 para el tamaño fijo .

De lo contrario, su problema es que su %typemap(out) double * no puede conocer el valor de su parámetro int x. Podría devolver una estructura que contenga tanto el puntero como el tamaño. Luego puede definir fácilmente un mapa de tipos para convertirlo en una lista (o una matriz NumPy; consulte también mi respuesta al Wrap C struct with array member for access in python: SWIG? cython? ctypes?).

Por cierto, no es posible devolver una matriz de tamaño fijo en C (ver también esta respuesta: Declaring a C function to return an array), por lo que un %typemap(out) double [ANY] { ... } nunca puede coincidir.

3

Sufrí un problema similar y lo resolvió de la siguiente manera.

// example.i 

%module example 

%include "carrays.i" 
%array_class(float, floatArray); 

float * FloatArray(int N); 

float SumFloats(float * f); 

 

# ipython 

> a = example.floatArray(23) # array generated by swig's class constructor 

> a 

<example.floatArray; proxy of <Swig Object of type 'floatArray *' at 0x2e74180> > 

> a[0] 

-2.6762280573445764e-37 # unfortunately it is created uninitialized.. 

> b = example.FloatArray(23) # array generated by function 

> b 

<Swig Object of type 'float *' at 0x2e6ad80> 

> b[0] 
--------------------------------------------------------------------------- 
TypeError         Traceback (most recent call last) 
# ..... 
TypeError: 'SwigPyObject' object is not subscriptable 

> #But there is a way to access b!! 

> p = example.floatArray_frompointer(b) # i found this function by example. and twice tab 

> p 

<example.floatArray; proxy of <Swig Object of type 'floatArray *' at 0x2e66750> > 

> p[0] 

0.0 

> p[0] = 42 

> p[0] 

42.0 

Afortunadamente, todos estos tipos (float *, floatArray *, y de proxy de floatArray *) puede hacerse pasar con éxito para C++ función (como SumFloats).

1

Si no le importa tirar en el módulo Python numpy en el código Python, puede hacer lo siguiente:

En el archivo de interfaz SWIG:

%{ 
#define SWIG_FILE_WITH_INIT 
%} 
%include "numpy.i" 
%init %{ 
import_array(); 
%} 

%apply(float ARGOUT_ARRAY1[ANY]) {(float outarray1d[9])}; 
void rf(float outarray1d[9]); 

Sólo los dos últimos son líneas Específico para este ejemplo, lo primero es predeterminado para numpy.i (ver la documentación de numpy.i en otro lugar: http://docs.scipy.org/doc/numpy/reference/swig.interface-file.html).

En el archivo C (también puede ser inline en el archivo .i):

void rf(float outarray1d[9]) { 
    float _internal_rf[9]; 
    /* ... */ 
    memcpy(outarray1d, _internal_rf, 9*sizeof(float)); 
} 

entonces usted tiene una función que se puede llamar desde Python como

import mymodule 
a = mymodule.rf() 
# a is a numpy array of float32's, with len 9 

Ahora, si usted don No quiero ser forzado a jalar el módulo numpy en tu proyecto python, entonces te sugiero que revises numpy.i para ver cómo hacen el truco% typemap - según tengo entendido, está hecho con SWIG typemaps y no está inherentemente atado numpy - debería ser posible hacer el mismo truco con tuplas o listas como valor de retorno.

Cuestiones relacionadas