Khalif21 Khalif21 - 1 month ago 18
C Question

python - pass 3d array to C code

How to pass 3D python array to C code then get return back?
I have researched,



I have tried for 2D

Source :
- http://cboard.cprogramming.com/c-programming/61578-4-dimensional-array-contiguous-allocation.html#post438210

test1.py

import numpy as np
import numpy.ctypeslib as npct
from numpy.ctypeslib import ndpointer
import ctypes
import sys
import time

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

_dll = ctypes.CDLL("foo_test.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)
print x.__array_interface__
print x.shape[0]
print x.strides
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)
print xpp
print ypp
m = ctypes.c_int(x.shape[0])
n = ctypes.c_int(x.shape[1])
o = ctypes.c_int(x.shape[2])
_foobar(m, n, o, xpp, ypp)
return y

if __name__ == '__main__':
n = sys.argv[1]
n = float(n)
dim = np.sqrt(n)
s1=time.clock()
x = np.arange(n).reshape((3,3,3))
# x = np.arange(9).reshape((3,3))
y = foobar(x)
f1 = time.clock()
print 'Execution Time is ', f1-s1, ' Second'
print y[:]


foo_test.c

#include <stdio.h>
#include <stdlib.h>

#ifdef FOO_DLL
#ifdef FOO_EXPORTS
#define FOO_API __declspec(dllexport)
#else
#define FOO_API __declspec(dllimport)
#endif //For FOO_Export
#else
#define FOO_API extern
#endif //for FOO_DLL

#ifdef __cplusplus
extern "C" {
#endif

// http://cboard.cprogramming.com/c-programming/61578-4-dimensional-array-contiguous-allocation.html#post438210
void* my_malloc(char *expr, size_t size)
{
void* result = malloc(size);
printf("Malloc (%s) is size %lu, resulting %p\n", expr, (unsigned long)size, result );
return result;
}

void my_free(void* ptr)
{
printf("Freeing : %p\n", ptr);
free(ptr);
}

#define MY_MALLOC(x) my_malloc(#x, x)
#define MY_FREE(x) my_free(x)

//Create float 2D
float **array2D(int dimx, int dimy)
{
float **allx = MY_MALLOC(dimx * sizeof *allx);
float *ally = MY_MALLOC(dimx * dimy * sizeof *ally);
float **result = allx;
int x;

for(x = 0; x < dimx ; x++, ally += dimy)
{
result[x] = ally;
}

return result;
}

//create float 3D
float ***array3D(int dimx, int dimy, int dimz)
{
float ***allx = MY_MALLOC(dimx * sizeof *allx);
float **ally = MY_MALLOC(dimx * dimy * sizeof *ally);
float *allz = MY_MALLOC(dimx * dimy * dimz * sizeof *allz);
float ***result = allx;
int x, y;

for(x = 0; x < dimx ; x++, ally += dimy)
{
result[x] = ally;
for (y = 0; y <dimy ; y++, allz += dimz)
{
result[x][y] = allz;
}
}

return result;
}


void foobar(const int m, const int n, const int o, const double*** x, double*** y)
{
float ***array3d;
// int x, y;

array3d = array3D(m,n,o);
size_t i,j,k;
for(i = 0; i< m; i++)
{
for(j = 0; j < n; j++)
{
for(k = 0; k < o; k++)
{
array3d[i][j][k] = 5.0;
y[i][j][k] = array3d[i][j][k];
}
}
}
}

#ifdef __cplusplus
}
#endif


The Error said,


Traceback (most recent call last): File "test1.py", line 40, in

y = foobar(x) File "test1.py", line 30, in foobar
_foobar(m, n, o, xpp, ypp) ctypes.ArgumentError: argument 3: : argument must be an ndarray

Answer

Finally, I solved my problem, (Thanks to Evert for suggestion)

c_multiply.c

#include "c_multiply.h"
#include <stdio.h>

void ccmultiply4d(double* array, double multiplier, int m, int n, int o, int p) {

    int i, j,k, l ;
    for (i = 0; i < m; i++)
        for (j = 0; j < n; j++)
            for (k = 0; k < o; k++)
                for (l = 0; l < p; l++)
                {
                    array[i*m*n*o + j*n*o + k*o + l] = array[i*m*n*o + j*n*o + k*o + l] ;
                    printf("Array[%d*%d*%d*%d + %d*%d*%d + %d*%d + %d] * Multiplier  = Array[%d] * %d = %.lf\n", i,m,n,o,j,n,o,k,o,l, i*m*n*o + j*n*o + k*o + l, multiplier, array[i*m*n*o + j*n*o + k*o + l]);
                }

}

test.pyx

import cython

# import both numpy and the Cython declarations for numpy
import numpy as np
cimport numpy as np

# declare the interface to the C code
cdef extern from "c_multiply.h":
    void ccmultiply4d(double* array, double value, int m, int n, int o, int p)


@cython.boundscheck(False)
@cython.wraparound(False)
def multiply(np.ndarray[double, ndim=4, mode="c"] input not None, double value):
    """
    multiply (arr, value)

    Takes a numpy arry as input, and multiplies each elemetn by value, in place

    param: array -- a 2-d numpy array of np.float64
    param: value -- a number that will be multiplied by each element in the array

    """
    cdef int m, n, o, p

    m, n, o, p = input.shape[0], input.shape[1], input.shape[2], input.shape[3]

    ccmultiply4d(&input[0,0,0,0], value, m, n, o, p)
Comments