Skip to content

Instantly share code, notes, and snippets.

Embed
What would you like to do?
How to wrap C code in Python
#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;
}
#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;
}
double chi2(double m, double b, double *x, double *y, double *yerr, int N);
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(),
)
@beaylott

This comment has been minimized.

Copy link

@beaylott beaylott commented Aug 10, 2012

How about a ctypes version: https://gist.github.com/3313315 ...

@AraHaan

This comment has been minimized.

Copy link

@AraHaan AraHaan commented Dec 27, 2016

Nice code however what if my module does not need fucntions but need to do something like this where it calls classes from a backend module.

from importlib.machinery import FileFinder
from ._pycx_backend import *
import sys

extension_importers = [JsonImporter(), PycxImporter()]
hook_list = []
for importer in extension_importers:
    hook_list.append((importer.find_loader, importer.extensions))

sys.path_hooks.insert(0, FileFinder.path_hook(*hook_list))
sys.path_importer_cache.clear()

Basically I want to write this in using C Code similar to how you wrote this without using all too annoying Cython because it is entirely unreadable.

@RitamDey

This comment has been minimized.

Copy link

@RitamDey RitamDey commented Apr 11, 2017

Can't get it work on Python3.6. Importing in REPL tells me that Py_InitModule3

screenshot from 2017-04-11 21-11-32

Edit: Confirmed its initialization function outdated. Here is the updated gist from StackOverflow: https://gist.github.com/GreenJoey/b08528d6abe62da70f28f73c39c0efd0

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment