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