1

I am trying to create a python interface to a C function with the following structure: (Full code can be found 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;
    }
}

My Python code looks like this:

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

However, when I try to run the code I get the following error, which seems to be related to the type conversion of the 1st parameter:

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

I tried many variations of argtypes, as well as to convert posmat[:,0] to int or int32 via .astype, however I always get the same error. What am I doing wrong?

EDIT: According to the 1st comment below I added .ctypes.data to all array input arguments. The ArgumentError is now gone. However I get a Segmentation Fault, very difficult to investigate because python crashes

EDIT2: I tried to make the array column-contiguous

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

but I still get the seg fault

7
  • Does this answer help? If I remember correctly ctypes arrays are pointser. Have you tried passing the arrays as posmat[:, 0].ctypes.data to the c function? Commented Jan 25, 2016 at 15:44
  • Just tried to add .ctypes.data to all numpy array parameters. The ArgumentError is now gone, however I get a SegmentationFault. Commented Jan 25, 2016 at 16:00
  • Well, then that's a step in the right direction, probably. Try to transpose x and pass rows instead of columns. The c function is likely to expect contiguous arrays. Btw, note that I have not done this before and just taking guesses in the dark :) Commented Jan 25, 2016 at 16:03
  • Thanks for your help! I tried to make the array column-contiguous posmat=np.ascontiguousarray(np.asfortranarray(posmat)), but I still get the seg fault Commented Jan 25, 2016 at 16:14
  • You've told ctypes that some arguments are type c_int, but the actual arguments of the C function are pointers to ints. That could certainly trigger a segfault. Commented Jan 25, 2016 at 16:49

1 Answer 1

1

The error was highlighted by Warren above, the int arguments had to be passed by reference. Note also that the arrays have to be contiguous. Here is the final code:

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
Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.