繁体   English   中英

具有ctypes功能的Numpy数组接口

[英]Numpy array interface with ctypes function

我正在尝试将共享C库与某些python代码连接起来。 与库的接口是这样的

typedef struct{
    int v1;
    double* v2} input;

还有另外两种类型,例如:配置和输出类型。

我使用ctypes Structure在python中设置这些结构,如下所示:

class input(Structure):
    _fields_ = [("v1",c_int),("v2",POINTER(c_double)]

C代码有一些函数接收指向该结构的指针,argtypes定义如下:

fun.argtypes = [constraints,input,POINTER(input)]

constraints是另一个具有一些用于配置的int字段的结构。

首先,我更新输入结构中的v2字段

input.v2 = generated_array.ctypes.data_as(POINTER(c_double))

然后我称之为:

fun(constraints,input,byref(output))

函数原型请求struct和* to struct(假设输出结构类型与输入结构类型相同)。

然后我想访问存储在输出的v2字段中的乐趣结果。 但是我得到了意想不到的结果。 这样做有更好/更正确的方法吗?

我在这里搜索了很多并阅读了文档,但我找不到有什么问题。 我没有任何错误消息,但是我从共享库中收到的警告似乎表明这些接口存在错误。


我猜我发现了这个问题:

当我调用该方法时,会调用一个numpy数组。 然后我创建了4个向量:

    out_real = ascontiguousarray(zeros(din.size,dtype=c_double))
    out_imag = ascontiguousarray(zeros(din.size,dtype=c_double))
    in_real  = ascontiguousarray(din.real,dtype = c_double)
    in_imag  = ascontiguousarray(din.imag,dtype = c_double) 

其中din是输入向量。 我用这种方式测试了方法:

    print in_real.ctypes.data_as(POINTER(c_double))    
    print in_imag.ctypes.data_as(POINTER(c_double))
    print out_real.ctypes.data_as(POINTER(c_double))
    print out_imag.ctypes.data_as(POINTER(c_double))

结果是:

    <model.LP_c_double object at 0x1d81f80>
    <model.LP_c_double object at 0x1d81f80>
    <model.LP_c_double object at 0x1d81f80>
    <model.LP_c_double object at 0x1d81f80>

似乎所有人都指向同一个地方。

经过一些更改后,它按预期工作...


经过几次测试后,我发现第一次代码几乎是正确的。 我创建了一次Structure实例并更新了它的字段。 我改变了每次调用fun创建一个新实例。 我还将所有数组类型更改为等效的ctypes类型; 这似乎使功能按预期工作。

打印行为仍然保持在上面的测试中,但即使有这种奇怪的行为,该功能似乎也能正常工作。 正如下面的@ericsun评论指出的那样正确。

struct有一个可能用于数组长度的int字段,尽管我只是猜测没有完整的函数原型。 如果确实如此,这里有一个可能有用的例子。

首先,我需要在共享库中编译测试函数。 我只需将输入数组乘以2:

import os
import numpy as np
from ctypes import *

open('tmp.c', 'w').write('''\
typedef struct {
    int v1; double *v2;
} darray;
int test(darray *input, darray *output) {
    int i;
    /* note: this should first test for compatible size */
    for (i=0; i < input->v1; i++)
        *(output->v2 + i) = *(input->v2 + i) * 2;
    return 0;
}
''')
os.system('gcc -shared -o tmp.so tmp.c')

接下来创建ctypes定义。 我添加了一个classmethod做出darraynumpy.ndarray

c_double_p = POINTER(c_double)

class darray(Structure):
    _fields_ = [
      ('v1', c_int),
      ('v2', c_double_p),
    ]
    @classmethod
    def fromnp(cls, a):
        return cls(len(a), a.ctypes.data_as(c_double_p))

lib = CDLL('./tmp.so')
lib.test.argtypes = POINTER(darray), POINTER(darray)

测试:

a1 = np.arange(3) + 1.0
a2 = np.zeros(3)
print 'before:', '\na1 =', a1, '\na2 =', a2 

lib.test(darray.fromnp(a1), darray.fromnp(a2))
print 'after:', '\na1 =', a1, '\na2 =', a2 

输出:

before: 
a1 = [ 1.  2.  3.] 
a2 = [ 0.  0.  0.]
after: 
a1 = [ 1.  2.  3.] 
a2 = [ 2.  4.  6.]

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM