Created
August 3, 2012 13:41
-
-
Save dfm/3247796 to your computer and use it in GitHub Desktop.
How to wrap C code in Python
This file contains 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
#include <Python.h> | |
#include <numpy/arrayobject.h> | |
#include "chi2.h" | |
/* Docstrings */ | |
static char module_docstring[] = | |
"This module provides an interface for calculating chi-squared using C."; | |
static char chi2_docstring[] = | |
"Calculate the chi-squared of some data given a model."; | |
/* Available functions */ | |
static PyObject *chi2_chi2(PyObject *self, PyObject *args); | |
/* Module specification */ | |
static PyMethodDef module_methods[] = { | |
{"chi2", chi2_chi2, METH_VARARGS, chi2_docstring}, | |
{NULL, NULL, 0, NULL} | |
}; | |
/* Initialize the module */ | |
PyMODINIT_FUNC init_chi2(void) | |
{ | |
PyObject *m = Py_InitModule3("_chi2", module_methods, module_docstring); | |
if (m == NULL) | |
return; | |
/* Load `numpy` functionality. */ | |
import_array(); | |
} | |
static PyObject *chi2_chi2(PyObject *self, PyObject *args) | |
{ | |
double m, b; | |
PyObject *x_obj, *y_obj, *yerr_obj; | |
/* Parse the input tuple */ | |
if (!PyArg_ParseTuple(args, "ddOOO", &m, &b, &x_obj, &y_obj, | |
&yerr_obj)) | |
return NULL; | |
/* Interpret the input objects as numpy arrays. */ | |
PyObject *x_array = PyArray_FROM_OTF(x_obj, NPY_DOUBLE, NPY_IN_ARRAY); | |
PyObject *y_array = PyArray_FROM_OTF(y_obj, NPY_DOUBLE, NPY_IN_ARRAY); | |
PyObject *yerr_array = PyArray_FROM_OTF(yerr_obj, NPY_DOUBLE, | |
NPY_IN_ARRAY); | |
/* If that didn't work, throw an exception. */ | |
if (x_array == NULL || y_array == NULL || yerr_array == NULL) { | |
Py_XDECREF(x_array); | |
Py_XDECREF(y_array); | |
Py_XDECREF(yerr_array); | |
return NULL; | |
} | |
/* How many data points are there? */ | |
int N = (int)PyArray_DIM(x_array, 0); | |
/* Get pointers to the data as C-types. */ | |
double *x = (double*)PyArray_DATA(x_array); | |
double *y = (double*)PyArray_DATA(y_array); | |
double *yerr = (double*)PyArray_DATA(yerr_array); | |
/* Call the external C function to compute the chi-squared. */ | |
double value = chi2(m, b, x, y, yerr, N); | |
/* Clean up. */ | |
Py_DECREF(x_array); | |
Py_DECREF(y_array); | |
Py_DECREF(yerr_array); | |
if (value < 0.0) { | |
PyErr_SetString(PyExc_RuntimeError, | |
"Chi-squared returned an impossible value."); | |
return NULL; | |
} | |
/* Build the output tuple */ | |
PyObject *ret = Py_BuildValue("d", value); | |
return ret; | |
} |
This file contains 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
#include "chi2.h" | |
double chi2(double m, double b, double *x, double *y, double *yerr, int N) { | |
int n; | |
double result = 0.0, diff; | |
for (n = 0; n < N; n++) { | |
diff = (y[n] - (m * x[n] + b)) / yerr[n]; | |
result += diff * diff; | |
} | |
return result; | |
} |
This file contains 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
double chi2(double m, double b, double *x, double *y, double *yerr, int N); |
This file contains 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
from distutils.core import setup, Extension | |
import numpy.distutils.misc_util | |
c_ext = Extension("_chi2", ["_chi2.c", "chi2.c"]) | |
setup( | |
ext_modules=[c_ext], | |
include_dirs=numpy.distutils.misc_util.get_numpy_include_dirs(), | |
) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Can't get it work on Python3.6. Importing in REPL tells me that Py_InitModule3
Edit: Confirmed its initialization function outdated. Here is the updated gist from StackOverflow: https://gist.github.com/GreenJoey/b08528d6abe62da70f28f73c39c0efd0