Skip to content

Instantly share code, notes, and snippets.

@benjaminirving
Last active June 18, 2023 09:38
Show Gist options
  • Star 5 You must be signed in to star a gist
  • Fork 3 You must be signed in to fork a gist
  • Save benjaminirving/436262a58f9da5a68532 to your computer and use it in GitHub Desktop.
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/)

Python <-> c++ interface example for multidimensional arrays

# 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
# 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)
/*
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;
}
/*
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);
};
}
# 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'),
)
@WillieMaddox
Copy link

Is Test7 supposed to return a 2D numpy array? Because I'm getting a list. Thanks.

@benjaminirving
Copy link
Author

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