[Numpy-discussion] Pass 2d ndarray into C **double using ctypes

Yuxiang Wang yw5aj at virginia.edu
Thu Jan 1 21:56:07 EST 2015


1) @Strula Sorry about my stupid mistake! That piece of code totally
gave away how green I am in coding C :)

And yes, that piece of code works like a charm now! I am able to run
my model. Thanks a million!

2) @Strula and also thanks for your insight on the limitation of the
method. Currently I am just passing in 2d ndarray for data input, so I
can get away with this method; but it is really important to keep that
piece of knowledge in mind.

3) @Nathaniel Could you please give a hint on how should this be done
with the ctypes library (only for reading a 2d ndarray)? I noticed
that it wouldn't work if I set:
_doublepp = ctypes.POINTER(ctypes.POINTER(ctypes.c_double))
xpp = x.ctypes.data_as(ctypes.POINTER(ctypes.POINTER(ctypes.c_double)))
Could you please give a hint if possible?
(Complete code is attached at the end of this message)

4) I wanted to say that it seems to me, as the project gradually
scales up, Cython is easier to deal with, especially when I am using a
lot of numpy arrays. If it is even higher dimensional data, it would
be verbose while it is really succinct to use Cython.

Attached is the complete code.

Code #1: From Strula, and it worked:
// dummy.c
#include <stdlib.h>

__declspec(dllexport) void foobar(const int m, const int n, const
double **x, double **y)
{
    size_t i, j;
    for(i=0; i<m; i++)
        for(j=0; j<n; j++)
            y[i][j] = x[i][j];
}

# test.py
import numpy as np
from numpy.ctypeslib import ndpointer
import ctypes

_doublepp = ndpointer(dtype=np.uintp, ndim=1, flags='C')

_dll = ctypes.CDLL('dummy.dll')

_foobar = _dll.foobar
_foobar.argtypes = [ctypes.c_int, ctypes.c_int, _doublepp, _doublepp]
_foobar.restype = None

def foobar(x):
    y = np.zeros_like(x)
    xpp = (x.__array_interface__['data'][0]
      + np.arange(x.shape[0])*x.strides[0]).astype(np.uintp)
    ypp = (y.__array_interface__['data'][0]
      + np.arange(y.shape[0])*y.strides[0]).astype(np.uintp)
    m = ctypes.c_int(x.shape[0])
    n = ctypes.c_int(x.shape[1])
    _foobar(m, n, xpp, ypp)
    return y

if __name__ == '__main__':
    x = np.arange(9.).reshape((3, 3))
    y = foobar(x)

Code #2: Tried to use ctypes but it does not seem to work. Just being
curious how it should be done.
# test2.py
import numpy as np
import ctypes

_doublepp = ctypes.POINTER(ctypes.POINTER(ctypes.c_double))

_dll = ctypes.CDLL('dummy.dll')

_foobar = _dll.foobar
_foobar.argtypes = [ctypes.c_int, ctypes.c_int, _doublepp, _doublepp]
_foobar.restype = None

def foobar(x):
    y = np.zeros_like(x)
    xpp = x.ctypes.data_as(ctypes.POINTER(ctypes.POINTER(ctypes.c_double)))
    ypp = y.ctypes.data_as(ctypes.POINTER(ctypes.POINTER(ctypes.c_double)))
    m = ctypes.c_int(x.shape[0])
    n = ctypes.c_int(x.shape[1])
    _foobar(m, n, xpp, ypp)
    return y

if __name__ == '__main__':
    x = np.arange(9.).reshape((3, 3))
    y = foobar(x)



Shawn

On Thu, Jan 1, 2015 at 2:52 PM, Sturla Molden <sturla.molden at gmail.com> wrote:
> On 01/01/15 19:56, Nathaniel Smith wrote:
>
>> However, I suspect that this question can't really be answered in a
>> useful way without more information about why exactly the C code wants
>> a **double (instead of a *double) and what it expects to do with it.
>
>> E.g., is it going to throw away the passed in array and return a new
>> one?
>
> That is an important question.
>
> The solution I provided only allows a 2D array to be passed in and
> possibly modified inplace. It does not allow the C function pass back a
> freshly allocated array.
>
> The problem is of course that the meaning of double** is ambiguous. It
> could mean a pointer to an array of pointers. But it could also mean a
> double* passed by reference, in which case the function would modify the
> pointer instead of the data it points to.
>
> Sturla
>
> _______________________________________________
> NumPy-Discussion mailing list
> NumPy-Discussion at scipy.org
> http://mail.scipy.org/mailman/listinfo/numpy-discussion



-- 
Yuxiang "Shawn" Wang
Gerling Research Lab
University of Virginia
yw5aj at virginia.edu
+1 (434) 284-0836
https://sites.google.com/a/virginia.edu/yw5aj/



More information about the NumPy-Discussion mailing list