1

我正在尝试将 python 脚本中的一些函数移动到 c 以提高计算速度。我已经成功地为具有多个一维数组作为输入并使用 numpy.i 类型映射返回双精度的函数完成了此操作。

但是,我想移至 c 的另一个函数将 3 维 numpy 数组作为输入,并返回一个 1 维双精度数组。我已经尝试过与之前的函数相同的方法,但到目前为止,这只在调用函数时导致了分段错误。

这就是我所做的:

c中的函数定义为(3d数组是“WF”,要返回的数组是“charges”,而“pos_x”、“pos_y”和“pos_z”是一些1D输入数组):

void GetCharges(double* pos_x, double* pos_y, double* pos_z, double* charges, double*** WF, double resolution, double shape, int number){
...
}

“WF”的条目在代码中的地址为WF[i][j][k]

SWIG 接口文件如下所示:

/* file: GetCharges.i */
%module GetCharges
%{
#define SWIG_FILE_WITH_INIT
#include "GetCharges.h"
%}

%include "numpy.i"

%init %{
import_array();
%}


%apply (double* IN_ARRAY1, int DIM1) {(double* pos_x, int number1),(double* pos_y, int number2),(double* pos_z, int number3)}
%apply (double* IN_ARRAY3, int DIM1, int DIM2, int DIM3) {(double*** WF, int dim1, int dim2, int dim3)}
%apply (double* INPLACE_ARRAY1, int DIM1) {(double* charges, int number4)}

%rename (GetCharges) GetCharges_temp;
%ignore GetCharges;
%inline %{

void GetCharges_temp(double* pos_x, int number1, double* pos_y, int number2, double* pos_z, int number3, double *charges, int number4, double*** WF, int dim1, int dim2, int dim3, double resolution, double  shape)
{
GetCharges(pos_x, pos_y, pos_z, charges, WF, resolution, shape, number1);
}
%}

%include "GetCharges.h"

如您所见,我尝试将 INPLACE_ARRAY 用于返回值的数组。

我不习惯 c,所以也许错误是非常简单和愚蠢的。

任何帮助将非常感激。

4

1 回答 1

2

要了解如何应用映射,请参阅 numpy.i。在这里,您要使用的类型映射定义为

(DATA_TYPE* IN_ARRAY3, DIM_TYPE DIM1, DIM_TYPE DIM2, DIM_TYPE DIM3)

但是您将其应用为

%apply (double* IN_ARRAY3, int DIM1, int DIM2, int DIM3) {(double*** WF, int dim1, int dim2, int dim3)}

所以你把 adouble*放到 a 上double***。虽然 C 会接受这个参数,但你的程序在访问内存时会出现段错误。

您需要将内部三维内存定义为单个类型的向量,double*或者您需要一个额外的包装函数,该函数通过复制它(慢)或提供适当的内存地址(快)来进行正确的映射。

由于您已经添加了一个临时函数,您可以轻松地使用它来创建正确的内存布局,GetCharges(...,double*** WF)但您需要将函数定义更改为

%apply (double* IN_ARRAY3, int DIM1, int DIM2, int DIM3) {(double* WF, int dim1, int dim2, int dim3)}
%apply (double* INPLACE_ARRAY1, int DIM1) {(double* charges, int number4)}

...

void GetCharges_temp(double* pos_x, int number1, double* pos_y, int number2, double* pos_z, int number3, double *charges, int number4, double* WF, int dim1, int dim2, int dim3, double resolution, double  shape)

编辑

为了回答您的评论,我将在此处添加几行: 由于我通常连接现有的 C 代码,因此我假设您已经具有所需的内存布局。对于那个很抱歉。

所以真正的问题是,你如何访问WFin的元素C?你得到一个double*总长度为DIM1*DIM2*DIM3. 在 Numpy 中,您可以通过WF[i][j][k]. 要执行相同的操作,C您需要计算此元素的正确偏移量,WF[k+DIM3*(j +DIM2*i)]好像WF是(C 连续)行主要WF[i+DIM1*(j +DIM2*k)]如果WF是(Fortran 连续)列主要。您可以通过访问来检查 numpy 中的排序WF.flags。此外,您可以使用numpy.ascontiguousarraynumpy.requireC在 numpy 中强制行主要排序。WF

所以基本上所有任何维度的 numpy 数组都是 dim 的向量n1*...*nd,它们以相同的方式访问C:通过计算正确的偏移量。

在行主要存储元素中,快速索引是最后一个(此处k),而在列主要存储元素中,快速索引是第一个(此处i)。快速索引应该在最里面的循环中C以获得最大的加速。

于 2013-09-30T08:50:27.807 回答