使用数组成员包装C结构以便在python中访问:SWIG?用Cython?ctypes的?

kyn*_*nan 12 c python swig struct cython

我想访问一个C函数,它返回一个包含double数组的结构(其中这些数组的长度由结构的其他int成员给出)来自python.声明是

typedef struct {
  int dim;
  int vertices;
  int quadrature_degree;
  int polynomial_degree;
  int ngi;
  int quadrature_familiy;
  double *weight; /* 1D: ngi */
  double *l;      /* 2D: ngi * dim */
  double *n;      /* 2D: ngi * vertices */
  double *dn;     /* 3D: ngi * vertices * dim */
} element;

extern void get_element(int dim, int vertices, int quad_degree, int poly_degree, element* e);
Run Code Online (Sandbox Code Playgroud)

重要的是我希望能够以double*正确形状的NumPy数组访问所有成员(即dn应该可以作为3D数组访问).

简单地SWIG包装这给了我很好的结构,但所有double*成员都<Swig Object of type 'double *' at 0x348c8a0>使它们无用.我玩过NumPy SWIG接口文件,但无法使任何类型的图像( DATA_TYPE* INPLACE_ARRAY1, int DIM1 )工作(我认为在这种情况下不可能让它们匹配,但我很高兴被证明是错误的).

我的猜测是我必须PyArrayObject为这些成员处理NumPy数组的代码初始化,而SWIG扩展我的结构以使它们可以在Python中访问?这看起来很多工作.任何人都可以看到使用SWIG更好的方式吗?如果这样可以更容易,那么可以更改结构或返回它的方法.

或者,我看了一下cython和ctypes.这些更适合我想要实现的目标吗?我没有使用过cython,所以无法判断它的包装能力.对于ctypes,我可以大致想象一下如何做,但这意味着手工编写我希望合理自动化的包装器可以为我做的事情.

任何建议都感激不尽!

fab*_*ioM 8

Cython规则:

cdef extern from "the header.h":

ctypedef struct element:
  int dim
  int vertices
  int quadrature_degree
  int polynomial_degree
  int ngi
  int quadrature_familiy
  double *weight
  double *l
  double *n
  double *dn

void get_element(int dim, int vertices, int quad_degree, int poly_degree, element* e)
Run Code Online (Sandbox Code Playgroud)

然后你可以从python空间接口它


kyn*_*nan 6

使用SWIG需要整个结构的类型映射.只有指针成员的Tyepmaps是不够的,因为它们没有上下文来知道初始化NumPy数组的大小.我设法得到了我想要的以下类型图(基本上是从numpy.i复制和粘贴并适应我的需求,可能不是很强大):

%typemap (in,numinputs=0) element * (element temp) {
  $1 = &temp;
}

%typemap (argout) element * {
  /* weight */
  {
    npy_intp dims[1] = { $1->ngi };
    PyObject * array = PyArray_SimpleNewFromData(1, dims, NPY_DOUBLE, (void*)($1->weight));
    if (!array) SWIG_fail;
    $result = SWIG_Python_AppendOutput($result,array);
  }
  /* l */
  {
    npy_intp dims[2] = { $1->ngi, $1->dim };
    PyObject * array = PyArray_SimpleNewFromData(2, dims, NPY_DOUBLE, (void*)($1->l));
    if (!array) SWIG_fail;
    $result = SWIG_Python_AppendOutput($result,array);
  }
  /* n */
  {
    npy_intp dims[2] = { $1->ngi, $1->vertices };
    PyObject * array = PyArray_SimpleNewFromData(2, dims, NPY_DOUBLE, (void*)($1->n));
    if (!array) SWIG_fail;
    $result = SWIG_Python_AppendOutput($result,array);
  }
  /* dn */
  {
    npy_intp dims[3] = { $1->ngi, $1->vertices, $1->dim };
    PyObject * array = PyArray_SimpleNewFromData(3, dims, NPY_DOUBLE, (void*)($1->dn));
    if (!array) SWIG_fail;
    $result = SWIG_Python_AppendOutput($result,array);
  }
}
Run Code Online (Sandbox Code Playgroud)

这与C函数的不同之处在于它返回一个带有我想要的数据的NumPy数组元组,这比element以后从对象中提取它更方便.第一个类型图还消除了传递类型对象的需要element.因此,我可以element完全从python用户隐藏结构.

python接口最终看起来像这样:

weight, l, n, dn = get_element(dim, vertices, quadrature_degree, polynomial_degree)
Run Code Online (Sandbox Code Playgroud)