[英]Using swig for python list input and output
我正在使用 SWIG 為基於其 C 代碼的某些函數的評估構建 Python 模塊。
我需要的主要功能定義如下:
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 代碼中,因為 'mx' 出現的唯一地方是在 'for-loop' 行中,其中是對每個點的評估。
我也嘗試閱讀包裝代碼和調試,但我找不到問題所在。 以下是 SWIG 生成的包裝代碼的一部分,我添加了一個“printf”行。 甚至這個字符串也不會在錯誤之前打印出來。
#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
代碼。
我不確定你的評估函數應該做什么,所以我猜測並為它實現了一個包裝器。 我采用value_list = module.eval(point_matrix, func_id)
表示您想要返回針對每行數據點評估某個函數的結果列表,並提出以下內容。 我改變的事情:
f
中結果的空間被分配了。float
, PyFloat_AsDouble
被稱為每個值, PyErr_Occurred
叫,看它是否無法轉換。freearg
現在釋放兩個分配。argout
現在可以正確處理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]
是第一個參數而不是嵌套列表,它將無法正常運行。 也沒有檢查所有子列表的大小是否相同。
希望這可以幫助。 如果有任何不清楚的地方,請告訴我。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.