1 /* -*- c -*- */
2
3 /*
4 * vim:syntax=c
5 */
6
7 /*
8 *****************************************************************************
9 ** INCLUDES **
10 *****************************************************************************
11 */
12
13 /*
14 * _UMATHMODULE IS needed in __ufunc_api.h, included from numpy/ufuncobject.h.
15 * This is a mess and it would be nice to fix it. It has nothing to do with
16 * __ufunc_api.c
17 */
18 #define _UMATHMODULE
19 #define _MULTIARRAYMODULE
20 #define NPY_NO_DEPRECATED_API NPY_API_VERSION
21
22 #include "Python.h"
23
24 #include "npy_config.h"
25
26 #include "numpy/arrayobject.h"
27 #include "numpy/ufuncobject.h"
28 #include "numpy/npy_3kcompat.h"
29 #include "abstract.h"
30
31 #include "numpy/npy_math.h"
32 #include "number.h"
33
34 static PyUFuncGenericFunction pyfunc_functions[] = {PyUFunc_On_Om};
35
36 static int
object_ufunc_type_resolver(PyUFuncObject * ufunc,NPY_CASTING casting,PyArrayObject ** operands,PyObject * type_tup,PyArray_Descr ** out_dtypes)37 object_ufunc_type_resolver(PyUFuncObject *ufunc,
38 NPY_CASTING casting,
39 PyArrayObject **operands,
40 PyObject *type_tup,
41 PyArray_Descr **out_dtypes)
42 {
43 int i, nop = ufunc->nin + ufunc->nout;
44
45 out_dtypes[0] = PyArray_DescrFromType(NPY_OBJECT);
46 if (out_dtypes[0] == NULL) {
47 return -1;
48 }
49
50 for (i = 1; i < nop; ++i) {
51 Py_INCREF(out_dtypes[0]);
52 out_dtypes[i] = out_dtypes[0];
53 }
54
55 return 0;
56 }
57
58 static int
object_ufunc_loop_selector(PyUFuncObject * ufunc,PyArray_Descr ** NPY_UNUSED (dtypes),PyUFuncGenericFunction * out_innerloop,void ** out_innerloopdata,int * out_needs_api)59 object_ufunc_loop_selector(PyUFuncObject *ufunc,
60 PyArray_Descr **NPY_UNUSED(dtypes),
61 PyUFuncGenericFunction *out_innerloop,
62 void **out_innerloopdata,
63 int *out_needs_api)
64 {
65 *out_innerloop = ufunc->functions[0];
66 *out_innerloopdata = ufunc->data[0];
67 *out_needs_api = 1;
68
69 return 0;
70 }
71
72 PyObject *
ufunc_frompyfunc(PyObject * NPY_UNUSED (dummy),PyObject * args,PyObject * kwds)73 ufunc_frompyfunc(PyObject *NPY_UNUSED(dummy), PyObject *args, PyObject *kwds) {
74 PyObject *function, *pyname = NULL;
75 int nin, nout, i, nargs;
76 PyUFunc_PyFuncData *fdata;
77 PyUFuncObject *self;
78 const char *fname = NULL;
79 char *str, *types, *doc;
80 Py_ssize_t fname_len = -1;
81 void * ptr, **data;
82 int offset[2];
83 PyObject *identity = NULL; /* note: not the same semantics as Py_None */
84 static char *kwlist[] = {"", "nin", "nout", "identity", NULL};
85
86 if (!PyArg_ParseTupleAndKeywords(args, kwds, "Oii|$O:frompyfunc", kwlist,
87 &function, &nin, &nout, &identity)) {
88 return NULL;
89 }
90 if (!PyCallable_Check(function)) {
91 PyErr_SetString(PyExc_TypeError, "function must be callable");
92 return NULL;
93 }
94
95 nargs = nin + nout;
96
97 pyname = PyObject_GetAttrString(function, "__name__");
98 if (pyname) {
99 fname = PyUnicode_AsUTF8AndSize(pyname, &fname_len);
100 }
101 if (fname == NULL) {
102 PyErr_Clear();
103 fname = "?";
104 fname_len = 1;
105 }
106
107 /*
108 * ptr will be assigned to self->ptr, holds a pointer for enough memory for
109 * self->data[0] (fdata)
110 * self->data
111 * self->name
112 * self->types
113 *
114 * To be safest, all of these need their memory aligned on void * pointers
115 * Therefore, we may need to allocate extra space.
116 */
117 offset[0] = sizeof(PyUFunc_PyFuncData);
118 i = (sizeof(PyUFunc_PyFuncData) % sizeof(void *));
119 if (i) {
120 offset[0] += (sizeof(void *) - i);
121 }
122 offset[1] = nargs;
123 i = (nargs % sizeof(void *));
124 if (i) {
125 offset[1] += (sizeof(void *)-i);
126 }
127 ptr = PyArray_malloc(offset[0] + offset[1] + sizeof(void *) +
128 (fname_len + 14));
129 if (ptr == NULL) {
130 Py_XDECREF(pyname);
131 return PyErr_NoMemory();
132 }
133 fdata = (PyUFunc_PyFuncData *)(ptr);
134 fdata->callable = function;
135 fdata->nin = nin;
136 fdata->nout = nout;
137
138 data = (void **)(((char *)ptr) + offset[0]);
139 data[0] = (void *)fdata;
140 types = (char *)data + sizeof(void *);
141 for (i = 0; i < nargs; i++) {
142 types[i] = NPY_OBJECT;
143 }
144 str = types + offset[1];
145 memcpy(str, fname, fname_len);
146 memcpy(str+fname_len, " (vectorized)", 14);
147 Py_XDECREF(pyname);
148
149 /* Do a better job someday */
150 doc = "dynamic ufunc based on a python function";
151
152 self = (PyUFuncObject *)PyUFunc_FromFuncAndDataAndSignatureAndIdentity(
153 (PyUFuncGenericFunction *)pyfunc_functions, data,
154 types, /* ntypes */ 1, nin, nout, identity ? PyUFunc_IdentityValue : PyUFunc_None,
155 str, doc, /* unused */ 0, NULL, identity);
156
157 if (self == NULL) {
158 PyArray_free(ptr);
159 return NULL;
160 }
161 Py_INCREF(function);
162 self->obj = function;
163 self->ptr = ptr;
164
165 self->type_resolver = &object_ufunc_type_resolver;
166 self->legacy_inner_loop_selector = &object_ufunc_loop_selector;
167 PyObject_GC_Track(self);
168
169 return (PyObject *)self;
170 }
171
172 /* docstring in numpy.add_newdocs.py */
173 PyObject *
add_newdoc_ufunc(PyObject * NPY_UNUSED (dummy),PyObject * args)174 add_newdoc_ufunc(PyObject *NPY_UNUSED(dummy), PyObject *args)
175 {
176 PyUFuncObject *ufunc;
177 PyObject *str;
178 if (!PyArg_ParseTuple(args, "O!O!:_add_newdoc_ufunc", &PyUFunc_Type, &ufunc,
179 &PyUnicode_Type, &str)) {
180 return NULL;
181 }
182 if (ufunc->doc != NULL) {
183 PyErr_SetString(PyExc_ValueError,
184 "Cannot change docstring of ufunc with non-NULL docstring");
185 return NULL;
186 }
187
188 PyObject *tmp = PyUnicode_AsUTF8String(str);
189 if (tmp == NULL) {
190 return NULL;
191 }
192 char *docstr = PyBytes_AS_STRING(tmp);
193
194 /*
195 * This introduces a memory leak, as the memory allocated for the doc
196 * will not be freed even if the ufunc itself is deleted. In practice
197 * this should not be a problem since the user would have to
198 * repeatedly create, document, and throw away ufuncs.
199 */
200 char *newdocstr = malloc(strlen(docstr) + 1);
201 if (!newdocstr) {
202 Py_DECREF(tmp);
203 return PyErr_NoMemory();
204 }
205 strcpy(newdocstr, docstr);
206 ufunc->doc = newdocstr;
207
208 Py_DECREF(tmp);
209 Py_RETURN_NONE;
210 }
211
212
213 /*
214 *****************************************************************************
215 ** SETUP UFUNCS **
216 *****************************************************************************
217 */
218
219 NPY_VISIBILITY_HIDDEN PyObject *npy_um_str_out = NULL;
220 NPY_VISIBILITY_HIDDEN PyObject *npy_um_str_where = NULL;
221 NPY_VISIBILITY_HIDDEN PyObject *npy_um_str_axes = NULL;
222 NPY_VISIBILITY_HIDDEN PyObject *npy_um_str_axis = NULL;
223 NPY_VISIBILITY_HIDDEN PyObject *npy_um_str_keepdims = NULL;
224 NPY_VISIBILITY_HIDDEN PyObject *npy_um_str_casting = NULL;
225 NPY_VISIBILITY_HIDDEN PyObject *npy_um_str_order = NULL;
226 NPY_VISIBILITY_HIDDEN PyObject *npy_um_str_dtype = NULL;
227 NPY_VISIBILITY_HIDDEN PyObject *npy_um_str_subok = NULL;
228 NPY_VISIBILITY_HIDDEN PyObject *npy_um_str_signature = NULL;
229 NPY_VISIBILITY_HIDDEN PyObject *npy_um_str_sig = NULL;
230 NPY_VISIBILITY_HIDDEN PyObject *npy_um_str_extobj = NULL;
231 NPY_VISIBILITY_HIDDEN PyObject *npy_um_str_array_prepare = NULL;
232 NPY_VISIBILITY_HIDDEN PyObject *npy_um_str_array_wrap = NULL;
233 NPY_VISIBILITY_HIDDEN PyObject *npy_um_str_array_finalize = NULL;
234 NPY_VISIBILITY_HIDDEN PyObject *npy_um_str_ufunc = NULL;
235 NPY_VISIBILITY_HIDDEN PyObject *npy_um_str_pyvals_name = NULL;
236
237 /* intern some strings used in ufuncs, returns 0 on success */
238 static int
intern_strings(void)239 intern_strings(void)
240 {
241 if (!(npy_um_str_out = PyUnicode_InternFromString("out"))) return -1;
242 if (!(npy_um_str_where = PyUnicode_InternFromString("where"))) return -1;
243 if (!(npy_um_str_axes = PyUnicode_InternFromString("axes"))) return -1;
244 if (!(npy_um_str_axis = PyUnicode_InternFromString("axis"))) return -1;
245 if (!(npy_um_str_keepdims = PyUnicode_InternFromString("keepdims"))) return -1;
246 if (!(npy_um_str_casting = PyUnicode_InternFromString("casting"))) return -1;
247 if (!(npy_um_str_order = PyUnicode_InternFromString("order"))) return -1;
248 if (!(npy_um_str_dtype = PyUnicode_InternFromString("dtype"))) return -1;
249 if (!(npy_um_str_subok = PyUnicode_InternFromString("subok"))) return -1;
250 if (!(npy_um_str_signature = PyUnicode_InternFromString("signature"))) return -1;
251 if (!(npy_um_str_sig = PyUnicode_InternFromString("sig"))) return -1;
252 if (!(npy_um_str_extobj = PyUnicode_InternFromString("extobj"))) return -1;
253 if (!(npy_um_str_array_prepare = PyUnicode_InternFromString("__array_prepare__"))) return -1;
254 if (!(npy_um_str_array_wrap = PyUnicode_InternFromString("__array_wrap__"))) return -1;
255 if (!(npy_um_str_array_finalize = PyUnicode_InternFromString("__array_finalize__"))) return -1;
256 if (!(npy_um_str_ufunc = PyUnicode_InternFromString("__array_ufunc__"))) return -1;
257 if (!(npy_um_str_pyvals_name = PyUnicode_InternFromString(UFUNC_PYVALS_NAME))) return -1;
258 return 0;
259 }
260
261 /* Setup the umath part of the module */
262
initumath(PyObject * m)263 int initumath(PyObject *m)
264 {
265 PyObject *d, *s, *s2;
266 int UFUNC_FLOATING_POINT_SUPPORT = 1;
267
268 #ifdef NO_UFUNC_FLOATING_POINT_SUPPORT
269 UFUNC_FLOATING_POINT_SUPPORT = 0;
270 #endif
271
272 /* Add some symbolic constants to the module */
273 d = PyModule_GetDict(m);
274
275 PyDict_SetItemString(d, "pi", s = PyFloat_FromDouble(NPY_PI));
276 Py_DECREF(s);
277 PyDict_SetItemString(d, "e", s = PyFloat_FromDouble(NPY_E));
278 Py_DECREF(s);
279 PyDict_SetItemString(d, "euler_gamma", s = PyFloat_FromDouble(NPY_EULER));
280 Py_DECREF(s);
281
282 #define ADDCONST(str) PyModule_AddIntConstant(m, #str, UFUNC_##str)
283 #define ADDSCONST(str) PyModule_AddStringConstant(m, "UFUNC_" #str, UFUNC_##str)
284
285 ADDCONST(ERR_IGNORE);
286 ADDCONST(ERR_WARN);
287 ADDCONST(ERR_CALL);
288 ADDCONST(ERR_RAISE);
289 ADDCONST(ERR_PRINT);
290 ADDCONST(ERR_LOG);
291 ADDCONST(ERR_DEFAULT);
292
293 ADDCONST(SHIFT_DIVIDEBYZERO);
294 ADDCONST(SHIFT_OVERFLOW);
295 ADDCONST(SHIFT_UNDERFLOW);
296 ADDCONST(SHIFT_INVALID);
297
298 ADDCONST(FPE_DIVIDEBYZERO);
299 ADDCONST(FPE_OVERFLOW);
300 ADDCONST(FPE_UNDERFLOW);
301 ADDCONST(FPE_INVALID);
302
303 ADDCONST(FLOATING_POINT_SUPPORT);
304
305 ADDSCONST(PYVALS_NAME);
306
307 #undef ADDCONST
308 #undef ADDSCONST
309 PyModule_AddIntConstant(m, "UFUNC_BUFSIZE_DEFAULT", (long)NPY_BUFSIZE);
310
311 PyModule_AddObject(m, "PINF", PyFloat_FromDouble(NPY_INFINITY));
312 PyModule_AddObject(m, "NINF", PyFloat_FromDouble(-NPY_INFINITY));
313 PyModule_AddObject(m, "PZERO", PyFloat_FromDouble(NPY_PZERO));
314 PyModule_AddObject(m, "NZERO", PyFloat_FromDouble(NPY_NZERO));
315 PyModule_AddObject(m, "NAN", PyFloat_FromDouble(NPY_NAN));
316
317 s = PyDict_GetItemString(d, "true_divide");
318 PyDict_SetItemString(d, "divide", s);
319
320 s = PyDict_GetItemString(d, "conjugate");
321 s2 = PyDict_GetItemString(d, "remainder");
322 /* Setup the array object's numerical structures with appropriate
323 ufuncs in d*/
324 _PyArray_SetNumericOps(d);
325
326 PyDict_SetItemString(d, "conj", s);
327 PyDict_SetItemString(d, "mod", s2);
328
329 if (intern_strings() < 0) {
330 PyErr_SetString(PyExc_RuntimeError,
331 "cannot intern umath strings while initializing _multiarray_umath.");
332 return -1;
333 }
334
335 return 0;
336 }
337