1 #define NPY_NO_DEPRECATED_API NPY_1_7_API_VERSION
2 
3 #include <Python.h>
4 #include <stdio.h>
5 #include <assert.h>
6 
7 #include "numpy/arrayobject.h"
8 #include "numpy/ndarraytypes.h"
9 
10 struct Obj
11 {
12     size_t dim;
13     void * f;
14     void * params;
15 };
16 
assign_pointer(struct Obj * obj,size_t dim,PyObject * f,PyObject * params)17 void assign_pointer(struct Obj * obj, size_t dim, PyObject * f, PyObject * params)
18 {
19     obj->dim = dim;
20     obj->f = (void*)f;
21     obj->params = (void*)params;
22 }
23 
obj_alloc(void)24 struct Obj * obj_alloc(void)
25 {
26     struct Obj * obj = malloc(sizeof(struct Obj));
27     assert (obj != NULL);
28     return obj;
29 };
30 
obj_free(struct Obj ** obj)31 void obj_free(struct Obj ** obj){
32     free(*obj);
33     *obj = NULL;
34 }
35 
destruct_obj(PyObject * objin)36 void destruct_obj(PyObject * objin)
37 {
38     void* objPtr = PyCapsule_GetPointer(objin,NULL);
39     struct Obj* obj = (struct Obj*)objPtr;
40     obj_free(&obj);
41 }
42 
alloc_cobj(PyObject * self,PyObject * args)43 static PyObject* alloc_cobj( PyObject* self, PyObject* args ) {
44     /* import_array(); */
45     struct Obj * obj = obj_alloc();
46     PyObject* pyObj = PyCapsule_New((void*)obj,NULL,&destruct_obj);
47     return pyObj;
48 }
49 
assign(PyObject * self,PyObject * args)50 static PyObject* assign( PyObject* self, PyObject* args ) {
51     PyObject* pyObj;
52     PyObject * pyDim;
53     PyObject* pyF;
54     PyObject* pyParams;
55 
56     if(!PyArg_ParseTuple(args,"OOOO",&pyObj,&pyDim,&pyF,&pyParams,NULL)) return NULL;
57 
58     if (!PyCallable_Check(pyF)){
59         PyErr_SetString(PyExc_TypeError, "Third parameter must be callable");
60         return NULL;
61     }
62     /* Py_XINCREF(pyF); */
63 
64 
65     void* objPtr = PyCapsule_GetPointer(pyObj,NULL);
66     struct Obj* obj = (struct Obj*)objPtr;
67 
68     #if PY_MAJOR_VERSION >= 3
69     size_t d;
70     /* printf("%d\n",PyLong_Check(pyDim)); */
71     if (PyLong_Check(pyDim)){
72         d = PyLong_AsSsize_t(pyDim);
73         assign_pointer(obj,d,pyF,pyParams);
74     }
75     else{
76         PyErr_SetString(PyExc_TypeError, "Second parameter must be an int");
77         return NULL;
78     }
79     #else
80     size_t d;
81     if (PyInt_Check(pyDim)){
82         d = PyInt_AsSsize_t(pyDim);
83         assign_pointer(obj,d,pyF,pyParams);
84     }
85     else{
86         PyErr_SetString(PyExc_TypeError, "Second parameter must be an int");
87         return NULL;
88     }
89     #endif
90 
91     return Py_None;
92 }
93 
eval_py_obj(size_t N,const double * x,double * out,void * obj_void)94 int eval_py_obj(size_t N, const double * x, double * out, void * obj_void)
95 {
96     struct Obj * obj = obj_void;
97     size_t dim = obj->dim;
98 
99     npy_intp dims[2];
100     dims[0] = N;
101     dims[1] = dim;
102 
103     PyObject * pyX = PyArray_SimpleNewFromData(N,dims,NPY_DOUBLE,(double*)x);
104     PyObject * arglist = PyTuple_Pack(2,pyX,obj->params);
105     PyObject * pyResult = PyObject_CallObject(obj->f,arglist);
106     PyArrayObject * arr = (PyArrayObject*)PyArray_ContiguousFromAny(pyResult,NPY_DOUBLE,1,1);
107 
108     size_t ndims = (size_t)PyArray_NDIM(arr);
109     if (ndims > 1){
110         PyErr_SetString(PyExc_TypeError, "Wrapped python function must return a flattened (1d) array\n");
111         return 1;
112     }
113     npy_intp * dimss  = (npy_intp*)PyArray_DIMS(arr);
114 
115     if ((size_t)dimss[0] != N){
116         PyErr_SetString(PyExc_TypeError, "Wrapped python function must return an array with the same number of rows as input\n");
117         return 1;
118     }
119 
120     double * vals = (double*)PyArray_DATA(arr);
121     for (size_t ii = 0; ii < N; ii++){
122         out[ii] = vals[ii];
123     }
124 
125     Py_XDECREF(arr);
126     Py_XDECREF(arglist);
127     Py_XDECREF(pyResult);
128     return 0;
129 }
130 
eval_test_5d(PyObject * self,PyObject * args)131 static PyObject * eval_test_5d(PyObject * self, PyObject * args)
132 {
133     PyObject* pyObj;
134 
135     if(!PyArg_ParseTuple(args,"O",&pyObj, NULL)) return NULL;
136 
137     size_t N = 2;
138     void* objPtr = PyCapsule_GetPointer(pyObj,NULL);
139     struct Obj * obj = objPtr;
140 
141     double pt[10]= {0.1,0.2,0.3,0.4,0.5,0.6,0.7,0.8,0.9,1.0};
142     double out[5];
143 
144     int res = eval_py_obj(N,pt,out,obj);
145     if (res == 1){
146         return NULL;
147     }
148     return Py_None;
149 }
150 
151 
152 static struct PyMethodDef pycback_methods[] = {
153     {"assign",assign,METH_VARARGS,""},
154     {"alloc_cobj",alloc_cobj,METH_VARARGS,""},
155     {"eval_test_5d",eval_test_5d,METH_VARARGS,""},
156     {NULL, NULL, 0, NULL}
157 };
158 
159 #if PY_MAJOR_VERSION >= 3
160 static struct PyModuleDef pycback_module = {
161     PyModuleDef_HEAD_INIT,
162     "pycback",
163     "",
164     -1,
165     pycback_methods
166 };
167 #endif
168 
169 #if PY_MAJOR_VERSION >= 3
170 PyMODINIT_FUNC
PyInit_pycback(void)171 PyInit_pycback(void) {
172     PyObject* mod = PyModule_Create(&pycback_module);
173     import_array();
174     return mod;
175 }
176 
177 #else
178 PyMODINIT_FUNC
initpycback(void)179 initpycback(void) {
180     (void)Py_InitModule("pycback",pycback_methods);
181     import_array();
182 }
183 #endif
184 
185