From 77be77a26e197270b32821f4d71113017e6db0f7 Mon Sep 17 00:00:00 2001 From: Michael Droettboom Date: Thu, 17 Jul 2014 12:58:20 -0400 Subject: [PATCH 1/2] Add implementation using Numpy C UFunc API --- README.md | 1 + c_ufunc/c_ufunc.c | 187 ++++++++++++++++++++++++++++++++++++++++++++++ c_ufunc/setup.py | 10 +++ 3 files changed, 198 insertions(+) create mode 100644 c_ufunc/c_ufunc.c create mode 100644 c_ufunc/setup.py diff --git a/README.md b/README.md index fb718cb..8744bb9 100644 --- a/README.md +++ b/README.md @@ -8,3 +8,4 @@ following, but feel free to add other methods:: * ``cython`` - a pure Cython-based wrapper * ``c_numpy`` - a pure C (with Numpy API) wrapper * ``c_auto`` - a hand-written vectorized C wrapper with an auto-generated Python wrapper from the vectorized C wrappers. +* ``c_ufunc`` - a pure C using the Numpy UFunc API wrapper diff --git a/c_ufunc/c_ufunc.c b/c_ufunc/c_ufunc.c new file mode 100644 index 0000000..98fd2c7 --- /dev/null +++ b/c_ufunc/c_ufunc.c @@ -0,0 +1,187 @@ +#include "Python.h" +#include "numpy/arrayobject.h" +#include "numpy/ufuncobject.h" + +#include "numpy/npy_3kcompat.h" + +#include "numpy/npy_math.h" + +#include "erfa.h" + +typedef npy_intp intp; + +static void +increment_ufunc(intp ndim, char **args, intp *steps) +{ + intp i; + for (i = 0; i < ndim; ++i) { + *(args[i]) += steps[i]; + } +} + +#define BEGIN_LOOP \ + intp dN = *dimensions++; \ + intp N; \ + for (N = 0; N < dN; N++) { \ + +#define END_LOOP(x) \ + increment_ufunc((x), args, steps); \ + } \ + +/* + ***************************************************************************** + ** UFUNC LOOPS ** + ***************************************************************************** + */ + +/*/////////////////////////////////////////////////////////////////////////// + eraAtco13 +*/ + +static void +eraAtco13_wrapper(char **args, intp *dimensions, intp *steps, void *extra) +{ + int ret; + + BEGIN_LOOP + ret = eraAtco13( + *(double *)args[0], + *(double *)args[1], + *(double *)args[2], + *(double *)args[3], + *(double *)args[4], + *(double *)args[5], + *(double *)args[6], + *(double *)args[7], + *(double *)args[8], + *(double *)args[9], + *(double *)args[10], + *(double *)args[11], + *(double *)args[12], + *(double *)args[13], + *(double *)args[14], + *(double *)args[15], + *(double *)args[16], + *(double *)args[17], + (double *)args[18], + (double *)args[19], + (double *)args[20], + (double *)args[21], + (double *)args[22], + (double *)args[23]); + if (ret > 0) { + PyErr_SetString(PyExc_ValueError, "dubious year"); + return; + } else if (ret < 0) { + PyErr_SetString(PyExc_ValueError, "unacceptable date"); + return; + } + END_LOOP(24) +} + +static PyUFuncGenericFunction eraAtco13_functions[] = { eraAtco13_wrapper }; +static void *eraAtco13_data[] = {NULL}; +static char eraAtco13_types[] = { + NPY_DOUBLE, NPY_DOUBLE, NPY_DOUBLE, NPY_DOUBLE, NPY_DOUBLE, NPY_DOUBLE, + NPY_DOUBLE, NPY_DOUBLE, NPY_DOUBLE, NPY_DOUBLE, NPY_DOUBLE, NPY_DOUBLE, + NPY_DOUBLE, NPY_DOUBLE, NPY_DOUBLE, NPY_DOUBLE, NPY_DOUBLE, NPY_DOUBLE, + NPY_DOUBLE, NPY_DOUBLE, NPY_DOUBLE, NPY_DOUBLE, NPY_DOUBLE, NPY_DOUBLE }; + + +static void +eraD2dtf_wrapper(char **args, intp *dimensions, intp *steps, void *extra) +{ + int ret; + int ihmsf[4]; + + BEGIN_LOOP + ret = eraD2dtf( + (char *)args[0], + *(int *)args[1], + *(double *)args[2], + *(double *)args[3], + (int *)args[4], + (int *)args[5], + (int *)args[6], + ihmsf); + + if (ret > 0) { + PyErr_SetString(PyExc_ValueError, "dubious year"); + return; + } else if (ret < 0) { + PyErr_SetString(PyExc_ValueError, "unacceptable date"); + return; + } + + *(int *)args[7] = ihmsf[0]; + *(int *)args[8] = ihmsf[1]; + *(int *)args[9] = ihmsf[2]; + *(int *)args[10] = ihmsf[3]; + END_LOOP(11) +} + +static PyUFuncGenericFunction eraD2dtf_functions[] = { eraD2dtf_wrapper }; +static void *eraD2dtf_data[] = {NULL}; +static char eraD2dtf_types[] = { + NPY_STRING, NPY_INT, NPY_DOUBLE, NPY_DOUBLE, NPY_INT, NPY_INT, NPY_INT, + NPY_INT, NPY_INT, NPY_INT, NPY_INT }; + + +/*/////////////////////////////////////////////////////////////////////////// + module level +*/ + +#if defined(NPY_PY3K) +static struct PyModuleDef moduledef = { + PyModuleDef_HEAD_INIT, + "c_ufunc", + NULL, + -1, + NULL, + NULL, + NULL, + NULL, + NULL +}; +#endif + +#if defined(NPY_PY3K) +#define RETVAL m +PyObject *PyInit_c_ufunc(void) +#else +#define RETVAL +PyMODINIT_FUNC +initc_ufunc(void) +#endif +{ + PyObject *m; + PyObject *d; + PyObject *f; + +#if defined(NPY_PY3K) + m = PyModule_Create(&moduledef); +#else + m = Py_InitModule("c_ufunc", NULL); +#endif + if (m == NULL) + return RETVAL; + + import_array(); + import_ufunc(); + + d = PyModule_GetDict(m); + + f = PyUFunc_FromFuncAndData( + eraAtco13_functions, eraAtco13_data, eraAtco13_types, 1, 18, 6, + PyUFunc_None, "eraAtco13", "eraAtco13", 0); + PyDict_SetItemString(d, "atco13", f); + Py_DECREF(f); + + f = PyUFunc_FromFuncAndData( + eraD2dtf_functions, eraD2dtf_data, eraD2dtf_types, 1, 4, 7, + PyUFunc_None, "eraD2dtf", "eraD2dtf", 0); + PyDict_SetItemString(d, "eraD2dtf", f); + Py_DECREF(f); + + return RETVAL; +} diff --git a/c_ufunc/setup.py b/c_ufunc/setup.py new file mode 100644 index 0000000..a83248a --- /dev/null +++ b/c_ufunc/setup.py @@ -0,0 +1,10 @@ +from distutils.core import setup +from distutils.extension import Extension +setup(name='c_ufunc', + ext_modules=[ + Extension( + 'c_ufunc', + ['c_ufunc.c'], + libraries=['erfa'] + )], + ) From b502a7f2509abb687f6f5dc34a1522091e516bfc Mon Sep 17 00:00:00 2001 From: Michael Droettboom Date: Fri, 18 Jul 2014 08:59:16 -0400 Subject: [PATCH 2/2] Use numpy include path. --- c_ufunc/setup.py | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/c_ufunc/setup.py b/c_ufunc/setup.py index a83248a..93c9dc2 100644 --- a/c_ufunc/setup.py +++ b/c_ufunc/setup.py @@ -1,10 +1,19 @@ from distutils.core import setup from distutils.extension import Extension + +import numpy as np + +try: + numpy_include = np.get_include() +except AttributeError: + numpy_include = np.get_numpy_include() + setup(name='c_ufunc', ext_modules=[ Extension( 'c_ufunc', ['c_ufunc.c'], - libraries=['erfa'] + libraries=['erfa'], + include_dirs=[numpy_include] )], )