Skip to content

Instantly share code, notes, and snippets.

@eldstal
Last active November 2, 2017 13:47
Show Gist options
  • Save eldstal/ab64720e428db5c87093d1589899788f to your computer and use it in GitHub Desktop.
Save eldstal/ab64720e428db5c87093d1589899788f to your computer and use it in GitHub Desktop.
Numpy C++ module
all: nativemodule.so
%.so: %.cpp
g++ -ggdb -std=c++11 -shared -I/usr/include/python2.7 -lpython2.7 -fPIC -o $@ $<
run: nativemodule.so
./run.py
/*
* Native implementations of some functions for tighter type control
*/
#define NPY_NO_DEPRECATED_API NPY_1_7_API_VERSION
#include <Python.h>
#include "numpy/arrayobject.h"
#include <cstdint>
#include <string>
#include <sstream>
#include <ctime>
#include <iostream>
using std::cerr;
using std::string;
using std::endl;
void doStuff(double * in, long int inh, long int inw,
double * out, long int outh, long int outw) {
// Just repeat the input array over and over again into the larger output
for (int r=0; r<outh; ++r) {
for (int c=0; c<outw; ++c) {
size_t index = r * outw + c;
size_t in_index = index % (inh*inw);
out[index] = in[in_index];
}
}
}
/**
* Sizzle and swizzle a numpy array
* This is called directly from python.
* Parameter: input array, 2-dimensional
* Parameter: h, the desired output height
* Parameter: w, the desired output width
*
* The input array must be smaller or equal to hxw.
* The return value (numpy array of doubles) is hxw.
*/
static PyObject* py_dostuff(PyObject* self, PyObject* args)
{
PyObject* in_thumb;
long int out_dims[2]; // h, w
/* parse numpy arguments. Object, Long, Long: Oll */
if (!PyArg_ParseTuple(args, "Oll",
&in_thumb,
&out_dims[0],
&out_dims[1])) {
cerr << "Unable to parse arguments. " << endl;
return NULL;
}
// Figure out the shape of the input array
PyArrayObject* thumb_array = (PyArrayObject*) PyArray_FromAny(in_thumb,
NULL,
2, 2,
NPY_ARRAY_CARRAY_RO,
0);
int ndims = PyArray_NDIM(thumb_array);
long int* dims = PyArray_DIMS(thumb_array);
if (ndims != 2) {
cerr << "Non-2D array passed to upsample_fixp." << endl;
return NULL;
}
long int thumb_h = dims[0];
long int thumb_w = dims[1];
// TODO: assert that in_thumb.dtype is double
long int origin[2] = {0, 0};
// Get a 1D C array that refers directly to our source data as inarray[y*w + x]
double* inarray;
inarray = (double*) PyArray_GetPtr(thumb_array, origin);
// Create a numpy array of floats where our results go
PyArrayObject* ret = (PyArrayObject*) PyArray_SimpleNew(2, out_dims, NPY_DOUBLE);
// Get a C-mapping retdata[y*w + x] where we can write stuff into the numpy array
double* retdata;
retdata = (double*) PyArray_GetPtr(ret, origin);
// Here's the computational kernel. Compute, write to retdata and enjoy.
doStuff(inarray, thumb_h, thumb_w, retdata, out_dims[0], out_dims[1]);
// Return the numpy array back to the python caller
return PyArray_Return(ret);
}
/*
* Bind Python function names to our C functions
*/
static PyMethodDef native_methods[] = {
{"dostuff", py_dostuff, METH_VARARGS},
{NULL, NULL}
};
/*
* Python calls this to let us initialize our module
*/
PyMODINIT_FUNC
initnative()
{
(void) Py_InitModule("native", native_methods);
import_array();
}
#!/bin/env python2
import numpy
import native
in_array = numpy.ndarray((2, 4))
in_array[0,:] = [ 1, 2 , 4, 8 ]
in_array[1,:] = [ 256, 128, 64, 32 ]
print in_array
upscaled = native.dostuff(in_array, 10, 10)
print upscaled
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment