我正在尝试使用以下结构创建一个C函数的python接口:(可以找到完整代码here)
void get_pi_typed (int *type,
double *x,
double *y,
int *len,
int *typeA,
int *typeB,
double *r_low,
double *r,
int *len_r,
int *inds,
double *rc) {
\*DETAILS LEFT OUT
for (i=0;i<*len_r;i++) {
\*DETAILS LEFT OUT
rc[i] = (double)num_cnt/denom_cnt;
}
}
我的Python代码如下所示:
import numpy as np
import ctypes as ct
# must be a double array, with single dimension that is contiguous
array_1d_int = np.ctypeslib.ndpointer(dtype=np.int32, ndim=1, flags='CONTIGUOUS')
array_1d_double = np.ctypeslib.ndpointer(dtype=np.double, ndim=1, flags='CONTIGUOUS')
# Load the library as _libspfc.
_libspfc = np.ctypeslib.load_library('../src/libspatialfuncs', '.')
_libspfc.get_pi_typed.argtypes = [array_1d_int,\
array_1d_double,\
array_1d_double,\
ct.c_int,\
ct.c_int,\
ct.c_int,\
array_1d_double,\
array_1d_double,\
ct.c_int,\
ct.c_int,\
array_1d_double,\
]
_libspfc.get_pi_typed.restype = None
def getPiTyped(posmat,typeA=-1,typeB=-1,r=np.array([1.]),rLow=None):
"""
Python equivalent to get_pi_typed.
posmat: a matrix with columns type, x and y
typeA: the "from" type that we are interested in, -1 is wildcard
typeB: the "to" type that we are interested i, -1 is wildcard
r: the series of spatial distances wer are interested in
rLow: the low end of each range....0 by default
"""
if not isinstance(r, np.ndarray): #if it is not a 1D numpy array (for ex a scalar or a list), bring it into that shape
r=np.array(r)
r=r.reshape((-1))
if rLow is None:
rLow = np.zeros_like(r)
if not isinstance(rLow, np.ndarray): #if it is not a 1D numpy array (for ex a scalar or a list), bring it into that shape
rLow=np.array(rLow)
rLow=rLow.reshape((-1))
#prepare output array
rc = np.empty_like(r, dtype=np.double)
_libspfc.get_theta_typed(posmat[:,0],posmat[:,1],posmat[:,2],posmat.shape[0],typeA,typeB,rLow,r,r.shape[0],np.arange(1,r.shape[0]+1),rc)
return rc
然而,当我尝试运行代码时,我得到以下错误,这似乎与第一个参数的类型转换有关:
x =np.array([[1.,0.,0.],[1.,1.,0.],[2.,0.5,np.sqrt(.75)]])
sf.getPiTyped(x,1,2,1.5)
ArgumentError: argument 1: <type 'exceptions.TypeError'>: Don't know how to convert parameter 1
我尝试了许多argtypes变体,以及通过posmat[:,0]
将int
转换为int32
或.astype
,但我总是得到同样的错误。我做错了什么?
修改
根据下面的第一条评论,我向所有数组输入参数添加了.ctypes.data
。 ArgumentError
现已消失。但是我得到Segmentation Fault
,很难调查,因为python崩溃了
EDIT2: 我试图使数组列连续
posmat=np.ascontiguousarray(np.asfortranarray(posmat))
但我仍然得到了seg错误
答案 0 :(得分:1)
上面的Warren强调了错误,int参数必须通过引用传递。另请注意,数组必须是连续的。这是最终的代码:
import numpy as np
import ctypes as ct
# Load the library as _libspfc.
_libspfc = np.ctypeslib.load_library('../src/libspatialfuncs', '.')
def getPiTyped(posmat,typeA=-1,typeB=-1,r=np.array([1.]),rLow=None):
"""
Python equivalent to get_pi_typed.
posmat: a matrix with columns type, x and y
typeA: the "from" type that we are interested in, -1 is wildcard
typeB: the "to" type that we are interested i, -1 is wildcard
r: the series of spatial distances wer are interested in
rLow: the low end of each range....0 by default
"""
#prepare inputs
# argument 1 to 3: make a copy, so the matrix is C contiguous (already included in astype)
ty=posmat[:,0].astype(np.int32)
x=posmat[:,1].copy()
y=posmat[:,2].copy()
n = ct.c_int(posmat.shape[0])
typeA = ct.c_int(typeA)
typeB = ct.c_int(typeB)
if not isinstance(r, np.ndarray): #if it is not a 1D numpy array (for ex a scalar or a list), bring it into that shape
r=np.array(r)
r=r.reshape((-1))
if rLow is None:
rLow = np.zeros_like(r)
if not isinstance(rLow, np.ndarray): #if it is not a 1D numpy array (for ex a scalar or a list), bring it into that shape
rLow=np.array(rLow)
rLow=rLow.reshape((-1))
rLen=ct.c_int(r.shape[0])
ind=np.arange(1,r.shape[0]+1,dtype=np.int32)
#prepare output array
rc = np.empty_like(r, dtype=np.double)
_libspfc.get_pi_typed(ty,\
x,\
y,\
ct.byref(n),\
ct.byref(typeA),\
ct.byref(typeB),\
rLow,\
r,\
ct.byref(rLen),\
ind,\
rc)
return rc