Python <-> c++ interface example for multidimensional arrays
Last active
June 18, 2023 09:38
-
-
Save benjaminirving/436262a58f9da5a68532 to your computer and use it in GitHub Desktop.
Python to c++ interface example files. Used to demonstrate how to pass multidimensional numpy arrays to c++ vectors and back (see http://www.birving.com/blog/2014/05/13/passing-numpy-arrays-between-python-and/)
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# Python running example | |
from __future__ import print_function | |
import numpy as np | |
from rect import PyRectangle | |
# Initialising the wrapped c++ function | |
R1 = PyRectangle(0, 0, 9, 9); | |
#Test1: Doing the area example calculation | |
print("Test 1, Area: ", R1.getArea()) | |
#Test2: Passing a list from python to c++ | |
list1 = [1,2,3,4,5] | |
print("Test 2, Sum list: ", R1.sum_vec(list1)) | |
#Test3: Passing a numpy array from python to c++ | |
list2 = np.array([1,2,3,4,5]) | |
print(" Test 3, Sum list: ", R1.sum_vec(list2)) | |
#Test4: Passing a 2D list from python to c++ | |
list3 = [[1, 2, 3], [4, 5, 6]] | |
print("Test 4, Sum list: ", R1.sum_mat(list3)) | |
#Test5: Passing a 2D numpy array from python to c++ | |
# Passing by value makes a second copy so best to pass by reference as demonstrated in the next example | |
list4 = np.array([[1, 2, 3], [4, 5, 6]]) | |
print("Test 5, Sum list: ", R1.sum_mat(list4)) | |
#Test6: Passing a 2D numpy array from python to c++ as a constant reference | |
list5 = np.array([[1, 2, 3], [4, 5, 6]]) | |
print("Test 6, Sum list: ", R1.sum_mat_ref(list5)) | |
#Test7: Returning a 2D numpy array from c++ | |
list6 = np.array([[1, 2, 3], [4, 5, 6]]) | |
print("Test 7, Sum list: ", R1.ret_mat(list6)) | |
# This should work with any n-dimensional array |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# distutils: language = c++ | |
# distutils: sources = Rectangle.cpp | |
# Cython interface file for wrapping the object | |
# | |
# | |
from libcpp.vector cimport vector | |
# c++ interface to cython | |
cdef extern from "Rectangle.h" namespace "shapes": | |
cdef cppclass Rectangle: | |
Rectangle(int, int, int, int) except + | |
int x0, y0, x1, y1 | |
int getLength() | |
int getHeight() | |
int getArea() | |
void move(int, int) | |
double sum_vec(vector[double]) | |
double sum_mat(vector[vector[double]]) | |
double sum_mat_ref(vector[vector[double]] &) | |
vector[vector[double]] ret_mat(vector[vector[double]]) | |
# creating a cython wrapper class | |
cdef class PyRectangle: | |
cdef Rectangle *thisptr # hold a C++ instance which we're wrapping | |
def __cinit__(self, int x0, int y0, int x1, int y1): | |
self.thisptr = new Rectangle(x0, y0, x1, y1) | |
def __dealloc__(self): | |
del self.thisptr | |
def getLength(self): | |
return self.thisptr.getLength() | |
def getHeight(self): | |
return self.thisptr.getHeight() | |
def getArea(self): | |
return self.thisptr.getArea() | |
def move(self, dx, dy): | |
self.thisptr.move(dx, dy) | |
def sum_vec(self, sv): | |
return self.thisptr.sum_vec(sv) | |
def sum_mat(self, sv): | |
return self.thisptr.sum_mat(sv) | |
def sum_mat_ref(self, sv): | |
return self.thisptr.sum_mat_ref(sv) | |
def ret_mat(self, sv): | |
return self.thisptr.ret_mat(sv) |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* | |
Passing variables / arrays between cython and cpp | |
Example from | |
http://docs.cython.org/src/userguide/wrapping_CPlusPlus.html | |
Adapted to include passing of multidimensional arrays | |
*/ | |
#include "Rectangle.h" | |
using namespace shapes; | |
Rectangle::Rectangle(int X0, int Y0, int X1, int Y1) | |
{ | |
x0 = X0; | |
y0 = Y0; | |
x1 = X1; | |
y1 = Y1; | |
} | |
Rectangle::~Rectangle() | |
{ | |
} | |
int Rectangle::getLength() | |
{ | |
return (x1 - x0); | |
} | |
int Rectangle::getHeight() | |
{ | |
return (y1 - y0); | |
} | |
int Rectangle::getArea() | |
{ | |
return (x1 - x0) * (y1 - y0); | |
} | |
void Rectangle::move(int dx, int dy) | |
{ | |
x0 += dx; | |
y0 += dy; | |
x1 += dx; | |
y1 += dy; | |
} | |
/* | |
Inputting a 1D vectoror list and returning its sum | |
*/ | |
double Rectangle::sum_vec(std::vector<double> sv) | |
{ | |
double tot=0; | |
int svs = sv.size(); | |
std::cout << "vector length " << svs << std::endl; | |
for (int ii=0; ii<svs; ii++) | |
{ | |
tot = tot + sv.at(ii); | |
} | |
return tot; | |
} | |
/* | |
Inputting a 2D vector or list and returning its sum | |
*/ | |
double Rectangle::sum_mat(std::vector< std::vector<double> > sv) | |
{ | |
double tot=0; | |
int svrows = sv.size(); | |
int svcols = sv[0].size(); | |
std::cout << "vector length " << svrows << " , " << svcols << std::endl; | |
for (int ii=0; ii<svrows; ii++) | |
{ | |
for (int jj=0; jj<svcols; jj++) | |
{ | |
tot = tot + sv.at(ii).at(jj); | |
} | |
} | |
return tot; | |
} | |
/* | |
Passing a 2D vector by reference or list and returning its sum | |
*/ | |
double Rectangle::sum_mat_ref(const std::vector< std::vector<double> > & sv) | |
{ | |
double tot=0; | |
int svrows = sv.size(); | |
int svcols = sv[0].size(); | |
std::cout << "vector length " << svrows << " , " << svcols << std::endl; | |
for (int ii=0; ii<svrows; ii++) | |
{ | |
for (int jj=0; jj<svcols; jj++) | |
{ | |
tot = tot + sv.at(ii).at(jj); | |
} | |
} | |
return tot; | |
} | |
/* | |
Inputting a 2D vector, performing a simple operation and returning a new 2D vector | |
*/ | |
std::vector< std::vector<double> > Rectangle::ret_mat(std::vector< std::vector<double> > sv) | |
{ | |
int svrows = sv.size(); | |
int svcols = sv[0].size(); | |
std::vector< std::vector<double> > tot; | |
tot.resize(svrows, std::vector<double> (svcols, -1)); | |
std::cout << "vector length " << svrows << " , " << svcols << std::endl; | |
for (int ii=0; ii<svrows; ii++) | |
{ | |
for (int jj=0; jj<svcols; jj++) | |
{ | |
tot.at(ii).at(jj) = (2*sv.at(ii).at(jj)); | |
} | |
} | |
return tot; | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* | |
Passing variables / arrays between cython and cpp | |
Example from | |
http://docs.cython.org/src/userguide/wrapping_CPlusPlus.html | |
Adapted to include passing of multidimensional arrays | |
*/ | |
#include <vector> | |
#include <iostream> | |
namespace shapes { | |
class Rectangle { | |
public: | |
int x0, y0, x1, y1; | |
Rectangle(int x0, int y0, int x1, int y1); | |
~Rectangle(); | |
int getLength(); | |
int getHeight(); | |
int getArea(); | |
void move(int dx, int dy); | |
double sum_vec(std::vector<double> sv); | |
double sum_mat(std::vector< std::vector<double> > sv); | |
double sum_mat_ref(const std::vector< std::vector<double> > & sv); | |
std::vector< std::vector<double> > ret_mat(std::vector< std::vector<double> > sv); | |
}; | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# Cython compile instructions | |
from distutils.core import setup | |
from Cython.Build import cythonize | |
# Use python setup.py build --inplace | |
# to compile | |
setup( | |
name = "rectangleapp", | |
ext_modules = cythonize('*.pyx'), | |
) |
Thanks WillieMaddox. For my test I was just interested in passing the data in and out, and I think I must have converted to an array later with np.array() . I guess this could also be put in the rect.pyx file if more convenient.
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Is Test7 supposed to return a 2D numpy array? Because I'm getting a list. Thanks.