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