1

I have a c++ implementation wrapped with SWIG and compiled to a module which can be used by python.

I am using ctypes to call the function with ctype arguments, int double etc. The output of my_function(ctype args) is an int**, i.e. it's a multidimensional array.

How can I cast this into a 2D numpy array inside the python script? I have been looking at ctypes pointers but so far I have had no luck. I have spent many, many hours reading the C-API of python and numpy for use with SWIG, and implementing on the c++ side to return a numpy array has so far been incredibly hard and completely unsuccessful.

The Quantum Physicist
  • 24,987
  • 19
  • 103
  • 189
xitiru
  • 31
  • 3
  • Looks like a duplicate. What about this answer? http://stackoverflow.com/questions/22425921/pass-a-2d-numpy-array-to-c-using-ctypes – The Quantum Physicist Sep 28 '16 at 10:19
  • That question seems to be the dual to this one, @TheQuantumPhysicist (numpy -> int**, not int** -> numpy) – Eric Sep 28 '16 at 11:01
  • Is the `int**` dynamically allocated? Whose job is it to `delete []` it? – Eric Sep 28 '16 at 11:04
  • "`int**`, i.e. it's a multidimensional array" - non sequitur. A pointer is not an array. It can **point to** an array, but it can also point to a single item or to nothing at all. `int i; int* ip = &i; int** ipp = &ip;` – Pete Becker Sep 28 '16 at 12:52

2 Answers2

0

I don't think this can be done on the Python side; it will have to be done within the C/C++ layer using NumPy's C-API interface (PyArray_SimpleNewFromData is the relevant function – see this answer for some details). Here is an example of this in a Cython script.

Note that handling of deallocation is complicated in this case: as far as I know, there's no mechanism to allow numpy to handle it automatically. You'll just have to make sure that whatever script deallocates the array doesn't do so when the numpy wrapper is still being used.

Edit: if your int** does not point to a contiguous memory block, I don't believe this will work. NumPy can only (easily) handle contiguous data buffers.

Community
  • 1
  • 1
jakevdp
  • 77,104
  • 11
  • 125
  • 160
  • This can definitely be done on the python side (ctypes gives you all the machinery needed to dereference pointers), but you're right in saying that numpy only works with contiguous data buffers. Of course, it's possible (but unlikely) that the data is contiguous – Eric Sep 28 '16 at 14:07
  • I understand ctypes lets you manipulate pointers, but I don't think you can call the equivalent of numpy's ``PyArray_SimpleNewFromData`` from the Python side (though I'd be happy to be proven wrong!) – jakevdp Sep 28 '16 at 14:12
  • I think [this question](https://stackoverflow.com/questions/4355524/getting-data-from-ctypes-array-into-numpy) solves the 1D case, and since the data is disjoint anyway, that's the best you can do. – Eric Sep 28 '16 at 14:17
0

Using NumPy and numpy.i, this is quite easy

Interface header

#pragma once
void fun(int** outArray, int* nRows, int* nCols);

Implementation

#include "test.h"
#include <malloc.h>
void fun(int** outArray, int* nRows, int* nCols) {
  int _nRows = 100;
  int _nCols = 150;
  int* _outArray = (int*)malloc(sizeof(int)*_nRows*_nCols);
  *outArray = _outArray;
  *nRows = _nRows;
  *nCols = _nCols;
}

SWIG interface header

%module example
%{
  #define SWIG_FILE_WITH_INIT
  #include "test.h"
%}

%include "numpy.i"

%init
%{
  import_array();
%}

%apply (int** ARGOUTVIEWM_ARRAY2, int* DIM1, int* DIM2) {(int** outArray, int* nRows, int* nCols)}
%include "test.h"

The typemap ARGOUTVIEWM_ARRAY2 creates a managed NumPy array and free is automatically called, when the NumPy object is destroyed in Python.

If you want to create the wrapper yourself using the Python C API, you can look into the generated code made by SWIG using numpy.i

Jens Munk
  • 4,627
  • 1
  • 25
  • 40