从 scipy 的 weave.inline 将 C 数组返回到 python 范围

Posted

技术标签:

【中文标题】从 scipy 的 weave.inline 将 C 数组返回到 python 范围【英文标题】:Returning C arrays into python scope from scipy's weave.inline 【发布时间】:2012-07-08 15:28:48 【问题描述】:

我正在使用 scipy 的 weave.inline 来执行计算量大的任务。我在将一维数组返回到 python 范围时遇到问题。 Weave.inline 使用一个名为“return_val”的特殊参数来将值返回到 python 范围。 以下返回整数值的示例效果很好:

>>> from scipy.weave import inline
>>> print inline(r'''int N = 10; return_val = N;''')
10

但是下面的例子,它确实在没有提示错误的情况下编译,并没有返回我期望的数组:

>>> from scipy.weave import inline
>>> code =\
    r'''                                                              
       int* pairs;                                                       
       int  lenght = 0;                                                      
       for (int i=0;i<N;i++)                                            
         lenght   += 1;                                                     
         pairs     = (int *)malloc(sizeof(int)*lenght);                       
         pairs[i]  = i;
         std::cout << pairs[i] << std::endl;              
                                                                        
       return_val = pairs;                                               
    '''
 >>> N  = 5
 >>> R = inline(code,['N'])
 >>> print "RETURN_VAL:",R
 0
 1
 2
 3
 4
 RETURN_VAL: 1    

我需要动态重新分配数组“对”的大小,这就是我不能传递 numpy.array 或 python 列表本身的原因。

【问题讨论】:

【参考方案1】:

您需要做的就是使用原始 python c-api calls,或者如果您正在寻找更方便的东西,可以使用内置的 scipy weave 包装器。

不保证泄漏或效率,但它应该看起来有点像这样:

from scipy.weave import inline

code = r'''
    py::list ret; 
    for(int i = 0; i < N; i++) 
        py::list item;
        for(int j = 0; j < i; j++) 
            item.append(j);
        
        ret.append(item);
    
    return_val = ret;
    '''
N  = 5 
R = inline(code,['N'])
print R

【讨论】:

工作得很好,到目前为止没有任何泄漏或效率低下的迹象。谢谢。 这取决于你的问题,如果计算单个元素的工作量很大,元素数量很少,并且如果你打算在一个最后是python循环。但既然您已经决定使用 C/C++ 来提高效率,那么没有理由不一直使用 C 和 numpy 数组。【参考方案2】:

如果您事先完全不知道输出数组的大小,则必须在您的内联代码中创建它。我很确定使用 malloc 分配的数组会导致内存泄漏,因为您无法控制何时释放此内存。

解决方案是创建一个 numpy 数组,用函数的结果填充它并返回它。

import scipy.weave

code = r"""
npy_intp dims[1] = n;

PyObject* out_array = PyArray_SimpleNew(1, dims, NPY_DOUBLE);
double* data = (double*) ((PyArrayObject*) out_array)->data;

for (int i=0; i<n; ++i) data[i] = i;

return_val = out_array;
Py_XDECREF(out_array);
"""

n = 5
out_array = scipy.weave.inline(code, ["n"])
print "Array:", out_array

【讨论】:

在我看来,“数据”的大小是在循环之前分配的。问题是,我需要在循环中扩展数组,这就是我将 Andrew 的解决方案标记为正确的原因。是否有可能为特定目的修改您的代码? 数组永远不能原地展开。在您问题的代码中,您不是在扩展pairs 数组,而是在每个循环中创建一个新数组,丢失旧数组并泄漏其内存。我不知道您要解决什么问题,以及是否绝对没有选择通过循环进行有效的第一次通过以确定最终数组大小。

以上是关于从 scipy 的 weave.inline 将 C 数组返回到 python 范围的主要内容,如果未能解决你的问题,请参考以下文章

将 numba.jit 与 scipy.integrate.ode 一起使用

以 SQLite 和 HDF5 格式从/导入到 numpy、scipy

存储 scipy griddata 使用的权重以供重用

scipy.optimize.leastsq 有界约束

你如何从给定的 scipy 随机分布中提取随机数?

如何从一个巨大的(scipy.sparse)矩阵计算对角矩阵?