This is an archival dump of old wiki content --- see scipy.org for current material

Writing C++ extensions that use NumPy arrays

Some basics

Passing numpy arrays to C++ using ctypes requires 3 steps:

1. In Python: make a ctypes object of the numpy array. For example:

```import numpy as N
from numpyctypes import c_ndarray
c_myarray = c_ndarray(myarray, dtype = N.double, ndim = 3)```

c_ndarray() checks if the given numpy array fulfills the requirements specified by the keyword parameters. The required numpyctypes.py module is attached to this wiki page. Use help(c_ndarray) to find out more.

2. In C++: the numpy arrays are converted to a C struct "numpyArray":

```   1 #include <iostream>
2 #include "ndarray.h"
3
4 extern "C" {
5
6 int myfunc(numpyArray<double> array)
7 {
8 // Do stuff
9 }
10 }
```

It would be nice if the numpy array could be converted right away to a C++ array class, but unfortunately this is not possible. ctypes only understands C variables, and a C struct is the closest thing to a C++ class. The C++ header file ndarray.h contains the definition of "numpyArray" and is attached to this wiki page.

3. In C++: convert the C struct "numpyArray" to a C++ "Ndarray" object.

```   1 #include <iostream>
2 #include "ndarray.h"
3
4 extern "C" {
5
6 int myfunc(numpyArray<double> array)
7 {
8     Ndarray<double,3> a(array);
9    // Do stuff
10 }
11 }
```

Note that you need to know the number of dimensions (axes) of the array to define an "Ndarray" object. "Ndarray" is also defined in the C++ header file "ndarray.h". What's the gain? When using a multidimensional numpy array in a C/C++ extension, you can't simply use a[i][j[k] to access an element. Instead, you need to compute the location of the element using strides info, e.g. a[i*strides[0]+j*strides[1]+k*strides[2]]. The reason for this is the way numpy internally stores an array. Such a way to access an element is rather cumbersome and inconvenient. C++, however, allows to overload the [] operator to incorporate the strides information automatically. This is exactly what Ndarray does: a[i][j][k] is automatically converted to a[i*strides[0]+j*strides[1]+k*strides[2]] in a transparent way. The technique used is called template metaprogramming and it has the advantage that the conversion is done at compile time, not at runtime!

A worked out example

myextension.py

```import numpy as N
from numpy.ctypeslib import load_library
from numpyctypes import c_ndarray

mylib = load_library('libmyextension', '.')       # '.' is the directory of the C++ lib

def myfunc(array1, array2):
arg1 = c_ndarray(array1, dtype=N.double, ndim = 3, shape = (4,3,2))
arg2 = c_ndarray(array2, dtype=N.double, ndim = 3, shape = (4,3,2))
return mylib.myfunc(arg1, arg2)```

myextension.cpp

```   1 #include <iostream>
2 #include "ndarray.h"
3
4 extern "C" {
5
6 int myfunc(numpyArray<double> array1, numpyArray<double> array2)
7 {
8     Ndarray<double,3> a(array1);
9     Ndarray<double,3> b(array2);
10
11     double sum=0.0;
12
13     for (int i = 0; i < a.getShape(0); i++)
14     {
15         for (int j = 0; j < a.getShape(1); j++)
16         {
17             for (int k = 0; k < a.getShape(2); k++)
18             {
19                 a[i][j][k] = 2.0 * b[i][j][k];
20                 sum += a[i][j][k];
21            }
22         }
23     }
24     return sum;
25 }
26 } // end extern "C"
27
```

myfunc() is extremely trivial, but it serves as an example. You need to compile myextension.cpp and make a shared library from it. The easiest way is to use Scons with the constructor file:

```env = Environment()
env.Replace(CFLAGS=['-O2','-Wall','-ansi','-pedantic'])
env.SharedLibrary(target='myextension', source=['myextension.cpp'])```

On a mac, this will create the myextension.dylib. Now you can use myfunc in a python program:

```import numpy as N
from myextension import myfunc

a = N.zeros((4,3,2))
b = N.arange(4*3*2).reshape(4,3,2) * 1.0     # double array !
s = myfunc(a,b)
print s, a, b```

SciPy: C++_Extensions_that_use_NumPy_arrays (last edited 2015-10-24 17:48:24 by anonymous)