What is the correct way to pass a numpy 2d – array to a c function using ctypes ? My current approach so far (leads to a segfault):
C code :
JavaScript
x
10
10
1
void test(double **in_array, int N) {
2
int i, j;
3
for(i = 0; i<N; i++) {
4
for(j = 0; j<N; j++) {
5
printf("%e t", in_array[i][j]);
6
}
7
printf("n");
8
}
9
}
10
Python code:
JavaScript
1
12
12
1
from ctypes import *
2
import numpy.ctypeslib as npct
3
4
array_2d_double = npct.ndpointer(dtype=np.double,ndim=2, flags='CONTIGUOUS')
5
liblr = npct.load_library('libtest.so', './src')
6
7
liblr.test.restype = None
8
liblr.test.argtypes = [array_2d_double, c_int]
9
10
x = np.arange(100).reshape((10,10)).astype(np.double)
11
liblr.test(x, 10)
12
Advertisement
Answer
This is probably a late answer, but I finally got it working. All credit goes to Sturla Molden at this link.
The key is, note that double**
is an array of type np.uintp
. Therefore, we have
JavaScript
1
3
1
xpp = (x.ctypes.data + np.arange(x.shape[0]) * x.strides[0]).astype(np.uintp)
2
doublepp = np.ctypeslib.ndpointer(dtype=np.uintp)
3
And then use doublepp
as the type, pass xpp
in. See full code attached.
The C code:
JavaScript
1
12
12
1
// dummy.c
2
#include <stdlib.h>
3
4
__declspec(dllexport) void foobar(const int m, const int n, const
5
double **x, double **y)
6
{
7
size_t i, j;
8
for(i=0; i<m; i++)
9
for(j=0; j<n; j++)
10
y[i][j] = x[i][j];
11
}
12
The Python code:
JavaScript
1
28
28
1
# test.py
2
import numpy as np
3
from numpy.ctypeslib import ndpointer
4
import ctypes
5
6
_doublepp = ndpointer(dtype=np.uintp, ndim=1, flags='C')
7
8
_dll = ctypes.CDLL('dummy.dll')
9
10
_foobar = _dll.foobar
11
_foobar.argtypes = [ctypes.c_int, ctypes.c_int, _doublepp, _doublepp]
12
_foobar.restype = None
13
14
def foobar(x):
15
y = np.zeros_like(x)
16
xpp = (x.__array_interface__['data'][0]
17
+ np.arange(x.shape[0])*x.strides[0]).astype(np.uintp)
18
ypp = (y.__array_interface__['data'][0]
19
+ np.arange(y.shape[0])*y.strides[0]).astype(np.uintp)
20
m = ctypes.c_int(x.shape[0])
21
n = ctypes.c_int(x.shape[1])
22
_foobar(m, n, xpp, ypp)
23
return y
24
25
if __name__ == '__main__':
26
x = np.arange(9.).reshape((3, 3))
27
y = foobar(x)
28
Hope it helps,
Shawn