我正在使用SWIG为某些功能构建一个Python模块。基于C代码的评估。
我需要的主要功能定义如下:
void eval(double *x, int nx, int mx, double *f, int func_id)
目标python函数应该是:
value_list = module.eval(point_matrix, func_id)
此处, eval 将调用基准函数并返回其值。 func_id 是要调用的函数eval的id, nx 是函数的维度, mx 是要求的点数评价。
实际上,我并不清楚SWIG如何在类型图之间传递值(例如,temp $ argnum,为什么总是使用$ argnum?)。但是通过查看包装代码,我完成了typemap.i文件:
%module cec17
%{
#include "cec17.h"
%}
%typemap(in) (double *x, int nx, int mx) (int count){
if (PyList_Check($input)) {
$3 = PyList_Size($input);
$2 = PyList_Size(PyList_GetItem($input, 0));
count = $3;
int i = 0, j = 0;
$1 = (double *) malloc($2*$3*sizeof(double));
for (i = 0; i < $3; i++){
for (j = 0; j < $2; j++){
PyObject *o = PyList_GetItem(PyList_GetItem($input, i), j);
if (PyFloat_Check(o))
$1[i*$2+j] = PyFloat_AsDouble(o);
else {
PyErr_SetString(PyExc_TypeError, "list must contrain strings");
free($1);
return NULL;
}
}
}
} else {
PyErr_SetString(PyExc_TypeError, "not a list");
return NULL;
}
}
%typemap(freearg) double *x {
free((void *) $1);
}
%typemap(in, numinputs=0) double *f (double temp) {
$1 = &temp;
}
%typemap(argout) double *f {
int i = 0;
int s = count1;
printf("pass arg %d", s);
$result = PyList_New(0);
for (i = 0; i < s; i++){
PyList_Append($result, PyFloat_FromDouble($1[i]));
}
}
void eval(double *x, int nx, int mx, double *f, int func_num);
然而,奇怪的事情发生了。通常,我测试30维函数。当评估少于10个点(mx <10)时,模块工作正常。评估更多点时,会发生错误:
[1] 13616 segmentation fault (core dumped) python test.py
我很确定问题不在c代码中,因为唯一的地方是&#39; mx&#39;发生在&#39; for-loop&#39;其中是每个点的评估。
我还尝试阅读包装代码和调试,但我无法找到问题所在。以下是SWIG生成的包装代码的一部分,我添加了一个&#39; printf&#39;线。在错误发生之前,甚至不会打印此字符串。
#ifdef __cplusplus
extern "C" {
#endif
SWIGINTERN PyObject *_wrap_eval(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
PyObject *resultobj = 0;
double *arg1 = (double *) 0 ;
int arg2 ;
int arg3 ;
double *arg4 = (double *) 0 ;
int arg5 ;
int count1 ;
double temp4 ;
int val5 ;
int ecode5 = 0 ;
PyObject * obj0 = 0 ;
PyObject * obj1 = 0 ;
printf("check point 0");
{
arg4 = &temp4;
}
if (!PyArg_ParseTuple(args,(char *)"OO:eval",&obj0,&obj1)) SWIG_fail;
{
if (PyList_Check(obj0)) {
arg3 = PyList_Size(obj0);
arg2 = PyList_Size(PyList_GetItem(obj0, 0));
count1 = arg3;
int i = 0, j = 0;
arg1 = (double *) malloc(arg2*arg3*sizeof(double));
for (i = 0; i < arg3; i++){
for (j = 0; j < arg2; j++){
PyObject *o = PyList_GetItem(PyList_GetItem(obj0, i), j);
if (PyFloat_Check(o))
arg1[i*arg2+j] = PyFloat_AsDouble(o);
else {
PyErr_SetString(PyExc_TypeError, "list must contrain strings");
free(arg1);
return NULL;
}
}
}
} else {
PyErr_SetString(PyExc_TypeError, "not a list");
return NULL;
}
}
ecode5 = SWIG_AsVal_int(obj1, &val5);
if (!SWIG_IsOK(ecode5)) {
SWIG_exception_fail(SWIG_ArgError(ecode5), "in method '" "eval" "', argument " "5"" of type '" "int""'");
}
arg5 = (int)(val5);
eval(arg1,arg2,arg3,arg4,arg5);
resultobj = SWIG_Py_Void();
{
int i = 0;
int s = count1;
resultobj = PyList_New(0);
for (i = 0; i < s; i++){
PyList_Append(resultobj, PyFloat_FromDouble(arg4[i]));
}
}
return resultobj;
fail:
return NULL;
}
感谢您阅读此内容。 :)
问题似乎有点单调乏味。也许你可以告诉我如何编写正确的typemap.i代码。
感谢您的帮助!
答案 0 :(得分:0)
我不确定你的评估函数应该做什么,所以我猜了一下并为它实现了一个包装器。我用value_list = module.eval(point_matrix, func_id)
表示你想要返回一个对每行数据点评估一些函数的结果列表,并提出以下内容。我改变的事情:
f
中的结果空间被malloced。float
以外的其他数字类型,每个值都会调用PyFloat_AsDouble
,并调用PyErr_Occurred
以查看它是否无法转换。freearg
typemap现在可以释放这两个分配。argout
typemap现在正确处理f
输出参数。我添加了一个示例eval
实现。
%module cec17
%typemap(in) (double *x, int nx, int mx, double* f) %{
if (PyList_Check($input)) {
$3 = PyList_Size($input);
$2 = PyList_Size(PyList_GetItem($input, 0));
$1 = malloc($2 * $3 * sizeof(double));
$4 = malloc($3 * sizeof(double));
for (int i = 0; i < $3; i++) {
for (int j = 0; j < $2; j++) {
PyObject *o = PyList_GetItem(PyList_GetItem($input, i), j);
double tmp = PyFloat_AsDouble(o);
if(PyErr_Occurred())
SWIG_fail;
$1[i * $2 + j] = PyFloat_AsDouble(o);
}
}
} else {
PyErr_SetString(PyExc_TypeError, "not a list");
return NULL;
}
%}
%typemap(freearg) (double *x, int nx, int mx, double* f) %{
free($1);
free($4);
%}
%typemap(argout) (double *x, int nx, int mx, double* f) (PyObject* tmp) %{
tmp = PyList_New($3);
for (int i = 0; i < $3; i++) {
PyList_SET_ITEM(tmp, i, PyFloat_FromDouble($4[i]));
}
$result = SWIG_Python_AppendOutput($result, tmp);
%}
%inline %{
void eval(double *x, int nx, int mx, double *f, int func_num)
{
for(int i = 0; i < mx; ++i) {
f[i] = 0.0;
for(int j = 0; j < nx; ++j)
f[i] += x[i*nx+j];
}
}
%}
输出:
>>> import cec17
>>> cec17.eval([[1,2,3],[4,5,6]],99)
[6.0, 15.0]
可以改进错误检查。例如,检查序列而不是列表。只检查外部列表它实际上是一个列表,因此如果[1,2,3]
是第一个参数而不是嵌套列表,它将无法正常运行。没有检查所有子列表的大小是否相同。
希望这会有所帮助。如果有什么不清楚,请告诉我。