Numpy Ctypes:分段错误。通过指针传递数组

时间:2016-01-25 15:29:50

标签: python arrays numpy ctypes

我正在尝试使用以下结构创建一个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.dataArgumentError现已消失。但是我得到Segmentation Fault,很难调查,因为python崩溃了

EDIT2: 我试图使数组列连续

posmat=np.ascontiguousarray(np.asfortranarray(posmat))

但我仍然得到了seg错误

1 个答案:

答案 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