gumath 0.2.0dev5

Sign up to get free protection for your applications and to get access to all the features.
Files changed (78) hide show
  1. checksums.yaml +7 -0
  2. data/CONTRIBUTING.md +61 -0
  3. data/Gemfile +5 -0
  4. data/History.md +0 -0
  5. data/README.md +5 -0
  6. data/Rakefile +105 -0
  7. data/ext/ruby_gumath/examples.c +126 -0
  8. data/ext/ruby_gumath/extconf.rb +97 -0
  9. data/ext/ruby_gumath/functions.c +106 -0
  10. data/ext/ruby_gumath/gufunc_object.c +79 -0
  11. data/ext/ruby_gumath/gufunc_object.h +55 -0
  12. data/ext/ruby_gumath/gumath/AUTHORS.txt +5 -0
  13. data/ext/ruby_gumath/gumath/INSTALL.txt +42 -0
  14. data/ext/ruby_gumath/gumath/LICENSE.txt +29 -0
  15. data/ext/ruby_gumath/gumath/MANIFEST.in +3 -0
  16. data/ext/ruby_gumath/gumath/Makefile.in +62 -0
  17. data/ext/ruby_gumath/gumath/README.rst +20 -0
  18. data/ext/ruby_gumath/gumath/config.guess +1530 -0
  19. data/ext/ruby_gumath/gumath/config.h.in +52 -0
  20. data/ext/ruby_gumath/gumath/config.sub +1782 -0
  21. data/ext/ruby_gumath/gumath/configure +5049 -0
  22. data/ext/ruby_gumath/gumath/configure.ac +167 -0
  23. data/ext/ruby_gumath/gumath/doc/_static/copybutton.js +66 -0
  24. data/ext/ruby_gumath/gumath/doc/conf.py +26 -0
  25. data/ext/ruby_gumath/gumath/doc/gumath/functions.rst +62 -0
  26. data/ext/ruby_gumath/gumath/doc/gumath/index.rst +26 -0
  27. data/ext/ruby_gumath/gumath/doc/index.rst +45 -0
  28. data/ext/ruby_gumath/gumath/doc/libgumath/data-structures.rst +130 -0
  29. data/ext/ruby_gumath/gumath/doc/libgumath/functions.rst +78 -0
  30. data/ext/ruby_gumath/gumath/doc/libgumath/index.rst +25 -0
  31. data/ext/ruby_gumath/gumath/doc/libgumath/kernels.rst +41 -0
  32. data/ext/ruby_gumath/gumath/doc/releases/index.rst +11 -0
  33. data/ext/ruby_gumath/gumath/install-sh +527 -0
  34. data/ext/ruby_gumath/gumath/libgumath/Makefile.in +170 -0
  35. data/ext/ruby_gumath/gumath/libgumath/Makefile.vc +160 -0
  36. data/ext/ruby_gumath/gumath/libgumath/apply.c +201 -0
  37. data/ext/ruby_gumath/gumath/libgumath/extending/bfloat16.c +130 -0
  38. data/ext/ruby_gumath/gumath/libgumath/extending/examples.c +176 -0
  39. data/ext/ruby_gumath/gumath/libgumath/extending/graph.c +393 -0
  40. data/ext/ruby_gumath/gumath/libgumath/extending/pdist.c +140 -0
  41. data/ext/ruby_gumath/gumath/libgumath/extending/quaternion.c +156 -0
  42. data/ext/ruby_gumath/gumath/libgumath/func.c +177 -0
  43. data/ext/ruby_gumath/gumath/libgumath/gumath.h +205 -0
  44. data/ext/ruby_gumath/gumath/libgumath/kernels/binary.c +547 -0
  45. data/ext/ruby_gumath/gumath/libgumath/kernels/unary.c +449 -0
  46. data/ext/ruby_gumath/gumath/libgumath/nploops.c +219 -0
  47. data/ext/ruby_gumath/gumath/libgumath/tbl.c +223 -0
  48. data/ext/ruby_gumath/gumath/libgumath/thread.c +175 -0
  49. data/ext/ruby_gumath/gumath/libgumath/xndloops.c +130 -0
  50. data/ext/ruby_gumath/gumath/python/extending.py +24 -0
  51. data/ext/ruby_gumath/gumath/python/gumath/__init__.py +74 -0
  52. data/ext/ruby_gumath/gumath/python/gumath/_gumath.c +577 -0
  53. data/ext/ruby_gumath/gumath/python/gumath/examples.c +93 -0
  54. data/ext/ruby_gumath/gumath/python/gumath/functions.c +77 -0
  55. data/ext/ruby_gumath/gumath/python/gumath/pygumath.h +95 -0
  56. data/ext/ruby_gumath/gumath/python/test_gumath.py +405 -0
  57. data/ext/ruby_gumath/gumath/setup.py +298 -0
  58. data/ext/ruby_gumath/gumath/vcbuild/INSTALL.txt +36 -0
  59. data/ext/ruby_gumath/gumath/vcbuild/vcbuild32.bat +21 -0
  60. data/ext/ruby_gumath/gumath/vcbuild/vcbuild64.bat +21 -0
  61. data/ext/ruby_gumath/gumath/vcbuild/vcclean.bat +10 -0
  62. data/ext/ruby_gumath/gumath/vcbuild/vcdistclean.bat +11 -0
  63. data/ext/ruby_gumath/include/gumath.h +205 -0
  64. data/ext/ruby_gumath/include/ruby_gumath.h +41 -0
  65. data/ext/ruby_gumath/lib/libgumath.a +0 -0
  66. data/ext/ruby_gumath/lib/libgumath.so +1 -0
  67. data/ext/ruby_gumath/lib/libgumath.so.0 +1 -0
  68. data/ext/ruby_gumath/lib/libgumath.so.0.2.0dev3 +0 -0
  69. data/ext/ruby_gumath/ruby_gumath.c +295 -0
  70. data/ext/ruby_gumath/ruby_gumath.h +41 -0
  71. data/ext/ruby_gumath/ruby_gumath_internal.h +45 -0
  72. data/ext/ruby_gumath/util.c +68 -0
  73. data/ext/ruby_gumath/util.h +48 -0
  74. data/gumath.gemspec +47 -0
  75. data/lib/gumath.rb +7 -0
  76. data/lib/gumath/version.rb +5 -0
  77. data/lib/ruby_gumath.so +0 -0
  78. metadata +206 -0
@@ -0,0 +1,24 @@
1
+ from xnd import xnd
2
+ from ndtypes import ndt
3
+ import gumath.examples as ex
4
+
5
+
6
+ # ==============================================================================
7
+ # Experimental syntax sugar
8
+ # ==============================================================================
9
+
10
+
11
+ class Graph(xnd):
12
+ def __new__(cls, *args, **kwargs):
13
+ return super().__new__(cls, *args, typedef="graph")
14
+
15
+ def shortest_paths(self, start):
16
+ return ex.single_source_shortest_paths(self, start)
17
+
18
+
19
+ class bfloat16(xnd):
20
+ def __new__(cls, *args, **kwargs):
21
+ return super().__new__(cls, *args, dtypedef="bfloat16")
22
+
23
+ def __repr__(self):
24
+ return "bfloat16(%s)" % str(self)
@@ -0,0 +1,74 @@
1
+ #
2
+ # BSD 3-Clause License
3
+ #
4
+ # Copyright (c) 2017-2018, plures
5
+ # All rights reserved.
6
+ #
7
+ # Redistribution and use in source and binary forms, with or without
8
+ # modification, are permitted provided that the following conditions are met:
9
+ #
10
+ # 1. Redistributions of source code must retain the above copyright notice,
11
+ # this list of conditions and the following disclaimer.
12
+ #
13
+ # 2. Redistributions in binary form must reproduce the above copyright notice,
14
+ # this list of conditions and the following disclaimer in the documentation
15
+ # and/or other materials provided with the distribution.
16
+ #
17
+ # 3. Neither the name of the copyright holder nor the names of its
18
+ # contributors may be used to endorse or promote products derived from
19
+ # this software without specific prior written permission.
20
+ #
21
+ # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
22
+ # AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23
+ # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
24
+ # DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
25
+ # FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26
+ # DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
27
+ # SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
28
+ # CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
29
+ # OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
30
+ # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31
+ #
32
+
33
+ from ndtypes import ndt
34
+ from xnd import xnd
35
+ from ._gumath import *
36
+
37
+
38
+ try:
39
+ import numpy as np
40
+ from numba.npyufunc import GUVectorize
41
+
42
+ def xndvectorize(v):
43
+ if isinstance(v, str):
44
+ v = [v]
45
+ if isinstance(v, list):
46
+ lst = [ndt(s).to_nbformat() for s in v]
47
+ sigs = [x[0] for x in lst]
48
+ coretypes = [x[1] for x in lst]
49
+ if (len(set(sigs))) != 1:
50
+ raise ValueError(
51
+ "empty list or different signatures in multimethod")
52
+ sig = sigs[0]
53
+ else:
54
+ raise TypeError("unsupported input type %s" % type(v))
55
+
56
+ def wrap(func):
57
+ guvec = GUVectorize(func, sig, nopython=True)
58
+ for t in coretypes:
59
+ guvec.add(t)
60
+ g = guvec.build_ufunc()
61
+
62
+ def h(*args, **kwargs):
63
+ out = g(*args, **kwargs)
64
+ view = xnd.from_buffer(out)
65
+ ret = xnd.empty(view.type)
66
+ np.copyto(np.array(ret, copy=False), out)
67
+ return ret
68
+
69
+ return h
70
+
71
+ return wrap
72
+
73
+ except ImportError:
74
+ xndvectorize = None
@@ -0,0 +1,577 @@
1
+ /*
2
+ * BSD 3-Clause License
3
+ *
4
+ * Copyright (c) 2017-2018, plures
5
+ * All rights reserved.
6
+ *
7
+ * Redistribution and use in source and binary forms, with or without
8
+ * modification, are permitted provided that the following conditions are met:
9
+ *
10
+ * 1. Redistributions of source code must retain the above copyright notice,
11
+ * this list of conditions and the following disclaimer.
12
+ *
13
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
14
+ * this list of conditions and the following disclaimer in the documentation
15
+ * and/or other materials provided with the distribution.
16
+ *
17
+ * 3. Neither the name of the copyright holder nor the names of its
18
+ * contributors may be used to endorse or promote products derived from
19
+ * this software without specific prior written permission.
20
+ *
21
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
22
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
24
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
25
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
27
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
28
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
29
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
30
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31
+ */
32
+
33
+
34
+ #include <Python.h>
35
+ #include "ndtypes.h"
36
+ #include "pyndtypes.h"
37
+ #include "xnd.h"
38
+ #include "pyxnd.h"
39
+ #include "gumath.h"
40
+
41
+ #ifndef _MSC_VER
42
+ #include "config.h"
43
+ #endif
44
+
45
+ #define GUMATH_MODULE
46
+ #include "pygumath.h"
47
+
48
+ #ifdef _MSC_VER
49
+ #ifndef UNUSED
50
+ #define UNUSED
51
+ #endif
52
+ #else
53
+ #if defined(__GNUC__) && !defined(__INTEL_COMPILER)
54
+ #define UNUSED __attribute__((unused))
55
+ #else
56
+ #define UNUSED
57
+ #endif
58
+ #endif
59
+
60
+
61
+ /* libxnd.so is not linked without at least one xnd symbol. The -no-as-needed
62
+ * linker option is difficult to integrate into setup.py. */
63
+ const void *dummy = NULL;
64
+
65
+
66
+ /****************************************************************************/
67
+ /* Module globals */
68
+ /****************************************************************************/
69
+
70
+ /* Function table */
71
+ static gm_tbl_t *table = NULL;
72
+
73
+ /* Xnd type */
74
+ static PyTypeObject *xnd = NULL;
75
+
76
+ /* Maximum number of threads */
77
+ static int64_t max_threads = 1;
78
+
79
+
80
+ /****************************************************************************/
81
+ /* Error handling */
82
+ /****************************************************************************/
83
+
84
+ static PyObject *
85
+ seterr(ndt_context_t *ctx)
86
+ {
87
+ return Ndt_SetError(ctx);
88
+ }
89
+
90
+
91
+ /****************************************************************************/
92
+ /* Function object */
93
+ /****************************************************************************/
94
+
95
+ static PyTypeObject Gufunc_Type;
96
+
97
+ static PyObject *
98
+ gufunc_new(const gm_tbl_t *tbl, const char *name)
99
+ {
100
+ NDT_STATIC_CONTEXT(ctx);
101
+ GufuncObject *self;
102
+
103
+ self = PyObject_New(GufuncObject, &Gufunc_Type);
104
+ if (self == NULL) {
105
+ return NULL;
106
+ }
107
+
108
+ self->tbl = tbl;
109
+
110
+ self->name = ndt_strdup(name, &ctx);
111
+ if (self->name == NULL) {
112
+ return seterr(&ctx);
113
+ }
114
+
115
+ return (PyObject *)self;
116
+ }
117
+
118
+ static void
119
+ gufunc_dealloc(GufuncObject *self)
120
+ {
121
+ ndt_free(self->name);
122
+ PyObject_Del(self);
123
+ }
124
+
125
+
126
+ /****************************************************************************/
127
+ /* Function calls */
128
+ /****************************************************************************/
129
+
130
+ static void
131
+ clear_objects(PyObject **a, Py_ssize_t len)
132
+ {
133
+ Py_ssize_t i;
134
+
135
+ for (i = 0; i < len; i++) {
136
+ Py_CLEAR(a[i]);
137
+ }
138
+ }
139
+
140
+ static PyObject *
141
+ gufunc_call(GufuncObject *self, PyObject *args, PyObject *kwds)
142
+ {
143
+ NDT_STATIC_CONTEXT(ctx);
144
+ const Py_ssize_t nin = PyTuple_GET_SIZE(args);
145
+ PyObject **a = &PyTuple_GET_ITEM(args, 0);
146
+ PyObject *result[NDT_MAX_ARGS];
147
+ ndt_apply_spec_t spec = ndt_apply_spec_empty;
148
+ const ndt_t *in_types[NDT_MAX_ARGS];
149
+ xnd_t stack[NDT_MAX_ARGS];
150
+ gm_kernel_t kernel;
151
+ int i, k;
152
+
153
+ if (kwds && PyDict_Size(kwds) > 0) {
154
+ PyErr_SetString(PyExc_TypeError,
155
+ "gufunc calls do not support keywords");
156
+ return NULL;
157
+ }
158
+
159
+ if (nin > NDT_MAX_ARGS) {
160
+ PyErr_SetString(PyExc_TypeError,
161
+ "invalid number of arguments");
162
+ return NULL;
163
+ }
164
+
165
+ for (i = 0; i < nin; i++) {
166
+ if (!Xnd_Check(a[i])) {
167
+ PyErr_SetString(PyExc_TypeError, "arguments must be xnd");
168
+ return NULL;
169
+ }
170
+ stack[i] = *CONST_XND(a[i]);
171
+ in_types[i] = stack[i].type;
172
+ }
173
+
174
+ kernel = gm_select(&spec, self->tbl, self->name, in_types, (int)nin, stack, &ctx);
175
+ if (kernel.set == NULL) {
176
+ return seterr(&ctx);
177
+ }
178
+
179
+ if (spec.nbroadcast > 0) {
180
+ for (i = 0; i < nin; i++) {
181
+ stack[i].type = spec.broadcast[i];
182
+ }
183
+ }
184
+
185
+ for (i = 0; i < spec.nout; i++) {
186
+ if (ndt_is_concrete(spec.out[i])) {
187
+ PyObject *x = Xnd_EmptyFromType(xnd, spec.out[i]);
188
+ if (x == NULL) {
189
+ clear_objects(result, i);
190
+ ndt_apply_spec_clear(&spec);
191
+ return NULL;
192
+ }
193
+ result[i] = x;
194
+ stack[nin+i] = *CONST_XND(x);
195
+ }
196
+ else {
197
+ result[i] = NULL;
198
+ stack[nin+i] = xnd_error;
199
+ }
200
+ }
201
+
202
+ #ifdef HAVE_PTHREAD_H
203
+ if (gm_apply_thread(&kernel, stack, spec.outer_dims, spec.flags,
204
+ max_threads, &ctx) < 0) {
205
+ clear_objects(result, spec.nout);
206
+ return seterr(&ctx);
207
+ }
208
+ #else
209
+ if (gm_apply(&kernel, stack, spec.outer_dims, &ctx) < 0) {
210
+ clear_objects(result, spec.nout);
211
+ return seterr(&ctx);
212
+ }
213
+ #endif
214
+
215
+ for (i = 0; i < spec.nout; i++) {
216
+ if (ndt_is_abstract(spec.out[i])) {
217
+ ndt_del(spec.out[i]);
218
+ PyObject *x = Xnd_FromXnd(xnd, &stack[nin+i]);
219
+ stack[nin+i] = xnd_error;
220
+ if (x == NULL) {
221
+ clear_objects(result, i);
222
+ for (k = i+1; k < spec.nout; k++) {
223
+ if (ndt_is_abstract(spec.out[k])) {
224
+ xnd_del_buffer(&stack[nin+k], XND_OWN_ALL);
225
+ }
226
+ }
227
+ }
228
+ result[i] = x;
229
+ }
230
+ }
231
+
232
+ if (spec.nbroadcast > 0) {
233
+ for (i = 0; i < nin; i++) {
234
+ ndt_del(spec.broadcast[i]);
235
+ }
236
+ }
237
+
238
+ switch (spec.nout) {
239
+ case 0: Py_RETURN_NONE;
240
+ case 1: return result[0];
241
+ default: {
242
+ PyObject *tuple = PyTuple_New(spec.nout);
243
+ if (tuple == NULL) {
244
+ clear_objects(result, spec.nout);
245
+ return NULL;
246
+ }
247
+ for (i = 0; i < spec.nout; i++) {
248
+ PyTuple_SET_ITEM(tuple, i, result[i]);
249
+ }
250
+ return tuple;
251
+ }
252
+ }
253
+ }
254
+
255
+ static PyObject *
256
+ gufunc_kernels(GufuncObject *self, PyObject *args GM_UNUSED)
257
+ {
258
+ NDT_STATIC_CONTEXT(ctx);
259
+ PyObject *list, *tmp;
260
+ const gm_func_t *f;
261
+ char *s;
262
+ int i;
263
+
264
+ f = gm_tbl_find(self->tbl, self->name, &ctx);
265
+ if (f == NULL) {
266
+ return seterr(&ctx);
267
+ }
268
+
269
+ list = PyList_New(f->nkernels);
270
+ if (list == NULL) {
271
+ return NULL;
272
+ }
273
+
274
+ for (i = 0; i < f->nkernels; i++) {
275
+ s = ndt_as_string(f->kernels[i].sig, &ctx);
276
+ if (s == NULL) {
277
+ Py_DECREF(list);
278
+ return seterr(&ctx);
279
+ }
280
+
281
+ tmp = PyUnicode_FromString(s);
282
+ ndt_free(s);
283
+ if (tmp == NULL) {
284
+ Py_DECREF(list);
285
+ return NULL;
286
+ }
287
+
288
+ PyList_SET_ITEM(list, i, tmp);
289
+ }
290
+
291
+ return list;
292
+ }
293
+
294
+
295
+ static PyGetSetDef gufunc_getsets [] =
296
+ {
297
+ { "kernels", (getter)gufunc_kernels, NULL, NULL, NULL},
298
+ {NULL}
299
+ };
300
+
301
+
302
+ static PyTypeObject Gufunc_Type = {
303
+ PyVarObject_HEAD_INIT(NULL, 0)
304
+ .tp_name = "_gumath.gufunc",
305
+ .tp_basicsize = sizeof(GufuncObject),
306
+ .tp_dealloc = (destructor)gufunc_dealloc,
307
+ .tp_hash = PyObject_HashNotImplemented,
308
+ .tp_call = (ternaryfunc)gufunc_call,
309
+ .tp_getattro = PyObject_GenericGetAttr,
310
+ .tp_flags = Py_TPFLAGS_DEFAULT,
311
+ .tp_getset = gufunc_getsets
312
+ };
313
+
314
+
315
+ /****************************************************************************/
316
+ /* C-API */
317
+ /****************************************************************************/
318
+
319
+ static void **gumath_api[GUMATH_MAX_API];
320
+
321
+ struct map_args {
322
+ PyObject *module;
323
+ const gm_tbl_t *tbl;
324
+ };
325
+
326
+ static int
327
+ add_function(const gm_func_t *f, void *args)
328
+ {
329
+ struct map_args *a = (struct map_args *)args;
330
+ PyObject *func;
331
+
332
+ func = gufunc_new(a->tbl, f->name);
333
+ if (func == NULL) {
334
+ return -1;
335
+ }
336
+
337
+ return PyModule_AddObject(a->module, f->name, func);
338
+ }
339
+
340
+ static int
341
+ Gumath_AddFunctions(PyObject *m, const gm_tbl_t *tbl)
342
+ {
343
+ struct map_args args = {m, tbl};
344
+
345
+ if (gm_tbl_map(tbl, add_function, &args) < 0) {
346
+ return -1;
347
+ }
348
+
349
+ return 0;
350
+ }
351
+
352
+ static PyObject *
353
+ init_api(void)
354
+ {
355
+ gumath_api[Gumath_AddFunctions_INDEX] = (void *)Gumath_AddFunctions;
356
+
357
+ return PyCapsule_New(gumath_api, "gumath._gumath._API", NULL);
358
+ }
359
+
360
+
361
+ /****************************************************************************/
362
+ /* Module */
363
+ /****************************************************************************/
364
+
365
+ static PyObject *
366
+ unsafe_add_kernel(PyObject *m GM_UNUSED, PyObject *args, PyObject *kwds)
367
+ {
368
+ NDT_STATIC_CONTEXT(ctx);
369
+ static char *kwlist[] = {"name", "sig", "tag", "ptr", NULL};
370
+ gm_kernel_init_t k = {NULL};
371
+ gm_func_t *f;
372
+ char *name;
373
+ char *sig;
374
+ char *tag;
375
+ PyObject *ptr;
376
+ void *p;
377
+
378
+ if (!PyArg_ParseTupleAndKeywords(args, kwds, "sssO", kwlist, &name, &sig,
379
+ &tag, &ptr)) {
380
+ return NULL;
381
+ }
382
+
383
+ p = PyLong_AsVoidPtr(ptr);
384
+ if (p == NULL) {
385
+ return NULL;
386
+ }
387
+
388
+ k.name = name;
389
+ k.sig = sig;
390
+
391
+ if (strcmp(tag, "Opt") == 0) {
392
+ k.Opt = p;
393
+ }
394
+ else if (strcmp(tag, "C") == 0) {
395
+ k.C = p;
396
+ }
397
+ else if (strcmp(tag, "Fortran") == 0) {
398
+ k.Fortran = p;
399
+ }
400
+ else if (strcmp(tag, "Xnd") == 0) {
401
+ k.Xnd = p;
402
+ }
403
+ else if (strcmp(tag, "Strided") == 0) {
404
+ k.Strided = p;
405
+ }
406
+ else {
407
+ PyErr_SetString(PyExc_ValueError,
408
+ "tag must be 'Opt', 'C', 'Fortran', 'Xnd' or 'Strided'");
409
+ return NULL;
410
+ }
411
+
412
+ if (gm_add_kernel(table, &k, &ctx) < 0) {
413
+ return seterr(&ctx);
414
+ }
415
+
416
+ f = gm_tbl_find(table, name, &ctx);
417
+ if (f == NULL) {
418
+ return seterr(&ctx);
419
+ }
420
+
421
+ return gufunc_new(table, f->name);
422
+ }
423
+
424
+ static void
425
+ init_max_threads(void)
426
+ {
427
+ PyObject *os = NULL;
428
+ PyObject *n = NULL;
429
+ int64_t i64;
430
+
431
+ os = PyImport_ImportModule("os");
432
+ if (os == NULL) {
433
+ goto error;
434
+ }
435
+
436
+ n = PyObject_CallMethod(os, "cpu_count", "()");
437
+ if (n == NULL) {
438
+ goto error;
439
+ }
440
+
441
+ i64 = PyLong_AsLongLong(n);
442
+ if (i64 < 1) {
443
+ goto error;
444
+ }
445
+
446
+ max_threads = i64;
447
+
448
+ out:
449
+ Py_XDECREF(os);
450
+ Py_XDECREF(n);
451
+ return;
452
+
453
+ error:
454
+ if (PyErr_Occurred()) {
455
+ PyErr_Clear();
456
+ }
457
+ PyErr_WarnEx(PyExc_RuntimeWarning,
458
+ "could not get cpu count: using max_threads==1", 1);
459
+ goto out;
460
+ }
461
+
462
+ static PyObject *
463
+ get_max_threads(PyObject *m UNUSED, PyObject *args UNUSED)
464
+ {
465
+ return PyLong_FromLongLong(max_threads);
466
+ }
467
+
468
+ static PyObject *
469
+ set_max_threads(PyObject *m UNUSED, PyObject *obj)
470
+ {
471
+ int64_t n;
472
+
473
+ n = PyLong_AsLongLong(obj);
474
+ if (n == -1 && PyErr_Occurred()) {
475
+ return NULL;
476
+ }
477
+
478
+ if (n <= 0) {
479
+ PyErr_SetString(PyExc_ValueError,
480
+ "max_threads must be greater than 0");
481
+ return NULL;
482
+ }
483
+
484
+ max_threads = n;
485
+
486
+ Py_RETURN_NONE;
487
+ }
488
+
489
+
490
+ static PyMethodDef gumath_methods [] =
491
+ {
492
+ /* Methods */
493
+ { "unsafe_add_kernel", (PyCFunction)unsafe_add_kernel, METH_VARARGS|METH_KEYWORDS, NULL },
494
+ { "get_max_threads", (PyCFunction)get_max_threads, METH_NOARGS, NULL },
495
+ { "set_max_threads", (PyCFunction)set_max_threads, METH_O, NULL },
496
+ { NULL, NULL, 1 }
497
+ };
498
+
499
+
500
+ static struct PyModuleDef gumath_module = {
501
+ PyModuleDef_HEAD_INIT, /* m_base */
502
+ "_gumath", /* m_name */
503
+ NULL, /* m_doc */
504
+ -1, /* m_size */
505
+ gumath_methods, /* m_methods */
506
+ NULL, /* m_slots */
507
+ NULL, /* m_traverse */
508
+ NULL, /* m_clear */
509
+ NULL /* m_free */
510
+ };
511
+
512
+
513
+ PyMODINIT_FUNC
514
+ PyInit__gumath(void)
515
+ {
516
+ NDT_STATIC_CONTEXT(ctx);
517
+ PyObject *m = NULL;
518
+ static PyObject *capsule = NULL;
519
+ static int initialized = 0;
520
+
521
+ if (!initialized) {
522
+ dummy = &xnd_error;
523
+
524
+ gm_init();
525
+
526
+ if (import_ndtypes() < 0) {
527
+ return NULL;
528
+ }
529
+ if (import_xnd() < 0) {
530
+ return NULL;
531
+ }
532
+
533
+ capsule = init_api();
534
+ if (capsule == NULL) {
535
+ return NULL;
536
+ }
537
+
538
+ table = gm_tbl_new(&ctx);
539
+ if (table == NULL) {
540
+ return seterr(&ctx);
541
+ }
542
+
543
+ init_max_threads();
544
+
545
+ initialized = 1;
546
+ }
547
+
548
+ if (PyType_Ready(&Gufunc_Type) < 0) {
549
+ return NULL;
550
+ }
551
+
552
+ xnd = Xnd_GetType();
553
+ if (xnd == NULL) {
554
+ goto error;
555
+ }
556
+
557
+ m = PyModule_Create(&gumath_module);
558
+ if (m == NULL) {
559
+ goto error;
560
+ }
561
+
562
+ Py_INCREF(capsule);
563
+ if (PyModule_AddObject(m, "_API", capsule) < 0) {
564
+ goto error;
565
+ }
566
+
567
+ if (Gumath_AddFunctions(m, table) < 0) {
568
+ goto error;
569
+ }
570
+
571
+ return m;
572
+
573
+ error:
574
+ Py_CLEAR(xnd);
575
+ Py_CLEAR(m);
576
+ return NULL;
577
+ }