在python:SWIG中用数组成员包装C结构?赛顿?C类型?

2024-05-13 20:43:46 发布

您现在位置:Python中文网/ 问答频道 /正文

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

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);

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

简单的SWIG包装就可以得到很好的结构,但是所有的double*成员都是{},这使得它们变得毫无用处。我尝试了一下NumPy SWIG接口文件,但是无法让( DATA_TYPE* INPLACE_ARRAY1, int DIM1 )这样的类型映射正常工作(我认为在这种情况下不可能使它们匹配,但我很高兴被证明是错误的)。在

我的猜测是我必须手工编写NumPy数组的初始化代码,作为这些成员的PyArrayObject,SWIG扩展了我的结构,使它们可以在Python中访问?这看起来工作量很大。有人能看到更好的方式使用SWIG吗?如果这样做更容易的话,可以更改结构或返回它的方法。在

或者我看了一下cython和ctypes。这些是不是更适合我要实现的目标?我没用过cython所以不能判断它的包装功能。对于ctypes,我可以粗略地想象如何实现它,但这意味着手工编写我希望一个合理的自动化包装器可以为我做的事情。在

如有任何建议,不胜感激!在


Tags: numpy成员数组element结构swigint手工
3条回答

赛顿规则:

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)

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

看看斯威格的打字图。它们允许您编写自己的代码来处理特定类型、特定实例(类型+名称)甚至参数组。我没有针对结构进行过这样的操作,但是为了特别处理一个C函数需要一个数组及其大小的情况:

%typemap(in) (int argc, Descriptor* argv) {
    /* Check if is a list */
    if (PyList_Check($input)) {
        int size = PyList_Size($input);
        $1 = size;
        ...
        $2 = ...;
    }
}

这将使用一对参数int argc, Descriptor* argv(因为提供的名称也必须匹配),并传递给您所使用的PyObject,然后编写完成转换所需的任何C代码。您可以为double *dn做一个类型映射,它将使用numpycapi进行转换。在

使用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);
  }
}

这与C函数的工作方式不同,它返回一个NumPy数组的元组,其中包含我想要的数据,这比以后从element对象中提取数据要方便得多。第一个typemap进一步消除了传入element类型的对象的需要。因此,我可以对python用户完全隐藏element结构。在

python接口最终如下所示:

^{pr2}$

相关问题 更多 >