簡體   English   中英

使用 swig 進行 python 列表輸入和輸出

[英]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)表示您想要返回針對每行數據點評估某個函數的結果列表,並提出以下內容。 我改變的事情:

  1. 類型映射用數字列表的 Python 列表替換前四個參數。
  2. f中結果的空間被分配了。
  3. 接受其他數字類型,除了floatPyFloat_AsDouble被稱為每個值, PyErr_Occurred叫,看它是否無法轉換。
  4. freearg現在釋放兩個分配。
  5. argout現在可以正確處理f輸出參數。
  6. 我添加了一個示例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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM