1 // Copyright 2012-2013 Tinyarray authors.
2 //
3 // This file is part of Tinyarray. It is subject to the license terms in the
4 // file LICENSE.rst found in the top-level directory of this distribution and
5 // at https://gitlab.kwant-project.org/kwant/tinyarray/blob/master/LICENSE.rst.
6 // A list of Tinyarray authors can be found in the README.rst file at the
7 // top-level directory of this distribution and at
8 // https://gitlab.kwant-project.org/kwant/tinyarray.
9
10 #include <Python.h>
11 #include <limits>
12 #include <cmath>
13 #include <sstream>
14 #include <functional>
15 #include <algorithm>
16 #include "array.hh"
17 #include "arithmetic.hh"
18 #include "conversion.hh"
19
20 // This module assumes C99 behavior of division:
21 // int(-3) / int(2) == -1
22
23 namespace {
24
25 template <typename T>
array_scalar_product(PyObject * a_,PyObject * b_)26 PyObject *array_scalar_product(PyObject *a_, PyObject *b_)
27 {
28 assert(Array<T>::check_exact(a_)); Array<T> *a = (Array<T>*)a_;
29 assert(Array<T>::check_exact(b_)); Array<T> *b = (Array<T>*)b_;
30 int ndim_a, ndim_b;
31 size_t *shape_a, *shape_b;
32 a->ndim_shape(&ndim_a, &shape_a);
33 b->ndim_shape(&ndim_b, &shape_b);
34 assert(ndim_a == 1);
35 assert(ndim_b == 1);
36 size_t n = shape_a[0];
37 if (n != shape_b[0]) {
38 PyErr_SetString(PyExc_ValueError,
39 "Both arguments must have same length.");
40 return 0;
41 }
42 T *data_a = a->data(), *data_b = b->data();
43 // It's important not to start with result = 0. This leads to wrong
44 // results with regard to the sign of zero as 0.0 + -0.0 is 0.0.
45 if (n == 0) return pyobject_from_number(T(0));
46 assert(n > 0);
47 T result = data_a[0] * data_b[0];
48 for (size_t i = 1; i < n; ++i) {
49 result += data_a[i] * data_b[i];
50 }
51 return pyobject_from_number(result);
52 }
53
54 PyObject *(*array_scalar_product_dtable[])(PyObject*, PyObject*) =
55 DTYPE_DISPATCH(array_scalar_product);
56
57 // This routine is not heavily optimized. It's performance has been measured
58 // to be adequate, given that it will be called from Python. The actual
59 // calculation of the matrix product typically uses less than half of the
60 // execution time of tinyarray.dot for two 3 by 3 matrices.
61 template <typename T>
array_matrix_product(PyObject * a_,PyObject * b_)62 PyObject *array_matrix_product(PyObject *a_, PyObject *b_)
63 {
64 assert(Array<T>::check_exact(a_)); Array<T> *a = (Array<T>*)a_;
65 assert(Array<T>::check_exact(b_)); Array<T> *b = (Array<T>*)b_;
66 int ndim_a, ndim_b;
67 size_t *shape_a, *shape_b;
68 a->ndim_shape(&ndim_a, &shape_a);
69 b->ndim_shape(&ndim_b, &shape_b);
70 assert(ndim_a > 0);
71 assert(ndim_b > 0);
72 int ndim = ndim_a + ndim_b - 2;
73 assert(ndim > 0);
74 if (ndim > max_ndim) {
75 PyErr_SetString(PyExc_ValueError,
76 "Result would have too many dimensions.");
77 return 0;
78 }
79 const size_t n = shape_a[ndim_a - 1];
80 size_t shape[max_ndim];
81
82 size_t d = 0, a0 = 1;
83 for (int id = 0, e = ndim_a - 1; id < e; ++id)
84 a0 *= shape[d++] = shape_a[id];
85 size_t b0 = 1;
86 for (int id = 0, e = ndim_b - 2; id < e; ++id)
87 b0 *= shape[d++] = shape_b[id];
88 size_t b1, n2;
89 if (ndim_b == 1) {
90 n2 = shape_b[0];
91 b1 = 1;
92 } else {
93 n2 = shape_b[ndim_b - 2];
94 b1 = shape[d++] = shape_b[ndim_b - 1];
95 }
96 if (n2 != n) {
97 PyErr_SetString(PyExc_ValueError, "Matrices are not aligned.");
98 return 0;
99 }
100
101 size_t size;
102 Array<T> *result = Array<T>::make(ndim, shape, &size);
103 if (!result) return 0;
104
105 T *dest = result->data();
106 if (n == 0) {
107 for (size_t i = 0; i < size; ++i) dest[i] = 0;
108 } else {
109 assert(n > 0);
110 const T *data_a = a->data(), *data_b = b->data();
111 const T *src_a = data_a;
112 for (size_t i = 0; i < a0; ++i, src_a += n) {
113 const T *src_b = data_b;
114 for (size_t j = 0; j < b0; ++j, src_b += (n - 1) * b1) {
115 for (size_t k = 0; k < b1; ++k, ++src_b) {
116 // It's important not to start with sum = 0. This leads to
117 // wrong results with regard to the sign of zero as 0.0 +
118 // -0.0 is 0.0.
119 T sum = src_a[0] * src_b[0];
120 for (size_t l = 1; l < n; ++l)
121 sum += src_a[l] * src_b[l * b1];
122 *dest++ = sum;
123 }
124 }
125 }
126 }
127
128 return (PyObject*)result;
129 }
130
131 PyObject *(*array_matrix_product_dtable[])(PyObject*, PyObject*) =
132 DTYPE_DISPATCH(array_matrix_product);
133
apply_binary_ufunc(Binary_ufunc ** ufunc_dtable,PyObject * a,PyObject * b)134 PyObject *apply_binary_ufunc(Binary_ufunc **ufunc_dtable,
135 PyObject *a, PyObject *b)
136 {
137 Dtype dtype;
138 if (coerce_to_arrays(&a, &b, &dtype) < 0) return 0;
139
140 int ndim_a, ndim_b;
141 size_t *shape_a, *shape_b;
142 reinterpret_cast<Array_base*>(a)->ndim_shape(&ndim_a, &shape_a);
143 reinterpret_cast<Array_base*>(b)->ndim_shape(&ndim_b, &shape_b);
144
145 PyObject *result = 0;
146 int ndim = std::max(ndim_a, ndim_b);
147 size_t stride_a = 1, stride_b = 1, shape[max_ndim];;
148 ptrdiff_t hops_a[max_ndim], hops_b[max_ndim];
149 for (int d = ndim - 1, d_a = ndim_a - 1, d_b = ndim_b - 1;
150 d >= 0; --d, --d_a, --d_b) {
151 size_t ext_a = d_a >= 0 ? shape_a[d_a] : 1;
152 size_t ext_b = d_b >= 0 ? shape_b[d_b] : 1;
153
154 if (ext_a == ext_b) {
155 hops_a[d] = stride_a;
156 hops_b[d] = stride_b;
157 shape[d] = ext_a;
158 stride_a *= ext_a;
159 stride_b *= ext_b;
160 } else if (ext_a == 1) {
161 hops_a[d] = 0;
162 hops_b[d] = stride_b;
163 stride_b *= shape[d] = ext_b;
164 } else if (ext_b == 1) {
165 hops_a[d] = stride_a;
166 hops_b[d] = 0;
167 stride_a *= shape[d] = ext_a;
168 } else {
169 std::ostringstream s;
170 s << "Operands could not be broadcast together with shapes (";
171 for (int d = 0; d < ndim_a; ++d) {
172 s << shape_a[d];
173 if (d + 1 < ndim_a) s << ", ";
174 }
175 s << ") and (";
176 for (int d = 0; d < ndim_b; ++d) {
177 s << shape_b[d];
178 if (d + 1 < ndim_b) s << ", ";
179 }
180 s << ").";
181 PyErr_SetString(PyExc_ValueError, s.str().c_str());
182 goto end;
183 }
184 }
185 for (int d = 1; d < ndim; ++d)
186 {
187 hops_a[d - 1] -= hops_a[d] * shape[d];
188 hops_b[d - 1] -= hops_b[d] * shape[d];
189 }
190
191 result = ufunc_dtable[int(dtype)](ndim, shape, a, hops_a, b, hops_b);
192
193 end:
194 Py_DECREF(a);
195 Py_DECREF(b);
196 return result;
197 }
198
199 } // Anonymous namespace
200
201 template <template <typename> class Op>
202 template <typename T>
ufunc(int ndim,const size_t * shape,PyObject * a_,const ptrdiff_t * hops_a,PyObject * b_,const ptrdiff_t * hops_b)203 PyObject *Binary_op<Op>::ufunc(int ndim, const size_t *shape,
204 PyObject *a_, const ptrdiff_t *hops_a,
205 PyObject *b_, const ptrdiff_t *hops_b)
206 {
207 Op<T> operation;
208
209 assert(Array<T>::check_exact(a_)); Array<T> *a = (Array<T>*)a_;
210 assert(Array<T>::check_exact(b_)); Array<T> *b = (Array<T>*)b_;
211
212 T *src_a = a->data(), *src_b = b->data();
213
214 if (ndim == 0) {
215 T result;
216 if (operation(result, *src_a, *src_b)) return 0;
217 return (PyObject*)pyobject_from_number(result);
218 }
219
220 Array<T> *result = Array<T>::make(ndim, shape);
221 if (result == 0) return 0;
222 T *dest = result->data();
223
224 int d = 0;
225 size_t i[max_ndim];
226 --ndim;
227 i[0] = shape[0];
228 while (true) {
229 if (i[d]) {
230 --i[d];
231 if (d == ndim) {
232 if (operation(*dest++, *src_a, *src_b)) {
233 Py_DECREF(result);
234 return 0;
235 }
236 src_a += hops_a[d];
237 src_b += hops_b[d];
238 } else {
239 ++d;
240 i[d] = shape[d];
241 }
242 } else {
243 if (d == 0) return (PyObject*)result;
244 --d;
245 src_a += hops_a[d];
246 src_b += hops_b[d];
247 }
248 }
249 }
250
251 template <template <typename> class Op>
apply(PyObject * a,PyObject * b)252 PyObject *Binary_op<Op>::apply(PyObject *a, PyObject *b)
253 {
254 return apply_binary_ufunc(dtable, a, b);
255 }
256
257 template <template <typename> class Op>
258 Binary_ufunc *Binary_op<Op>::dtable[] = DTYPE_DISPATCH(ufunc);
259
260 template <typename T>
261 struct Add {
operator ()Add262 bool operator()(T &result, T x, T y) {
263 result = x + y;
264 return false;
265 }
266 };
267
268 template <typename T>
269 struct Subtract {
operator ()Subtract270 bool operator()(T &result, T x, T y) {
271 result = x - y;
272 return false;
273 }
274 };
275
276 template <typename T>
277 struct Multiply {
operator ()Multiply278 bool operator()(T &result, T x, T y) {
279 result = x * y;
280 return false;
281 }
282 };
283
284 template <typename T>
285 struct Remainder {
286 bool operator()(T &result, T x, T y);
287 };
288
289 template <>
operator ()(long & result,long x,long y)290 bool Remainder<long>::operator()(long &result, long x, long y)
291 {
292 if (y == 0 || (y == -1 && x == std::numeric_limits<long>::min())) {
293 const char *msg = (y == 0) ?
294 "Integer modulo by zero." : "Integer modulo overflow.";
295 if (PyErr_WarnEx(PyExc_RuntimeWarning, msg, 1) < 0) return true;
296 result = 0;
297 return false;
298 }
299 long x_mod_y = x % y;
300 result = ((x ^ y) >= 0 /*same sign*/) ? x_mod_y : -x_mod_y;
301 return false;
302 }
303
304 template <>
operator ()(double & result,double x,double y)305 bool Remainder<double>::operator()(double &result, double x, double y)
306 {
307 result = x - std::floor(x / y) * y;
308 return false;
309 }
310
311 template <>
312 template <>
ufunc(int,const size_t *,PyObject *,const ptrdiff_t *,PyObject *,const ptrdiff_t *)313 PyObject *Binary_op<Remainder>::ufunc<Complex>(int, const size_t*,
314 PyObject*, const ptrdiff_t*,
315 PyObject*, const ptrdiff_t*)
316 {
317 PyErr_SetString(PyExc_TypeError,
318 "Modulo is not defined for complex numbers.");
319 return 0;
320 }
321
322 template <typename T>
323 struct Floor_divide {
324 bool operator()(T &result, T x, T y);
325 };
326
327 template <>
operator ()(long & result,long x,long y)328 bool Floor_divide<long>::operator()(long &result, long x, long y)
329 {
330 if (y == 0 || (y == -1 && x == std::numeric_limits<long>::min())) {
331 const char *msg = (y == 0) ?
332 "Integer division by zero." : "Integer division overflow.";
333 if (PyErr_WarnEx(PyExc_RuntimeWarning, msg, 1) < 0) return true;
334 result = 0;
335 return false;
336 }
337 long x_div_y = x / y;
338 result = ((x ^ y) >= 0 /*same sign*/ || (x % y) == 0) ?
339 x_div_y : x_div_y - 1;
340 return false;
341 }
342
343 template <>
operator ()(double & result,double x,double y)344 bool Floor_divide<double>::operator()(double &result, double x, double y)
345 {
346 result = std::floor(x / y);
347 return false;
348 }
349
350 template <>
351 template <>
ufunc(int,const size_t *,PyObject *,const ptrdiff_t *,PyObject *,const ptrdiff_t *)352 PyObject *Binary_op<Floor_divide>::ufunc<Complex>(int, const size_t*,
353 PyObject*, const ptrdiff_t*,
354 PyObject*, const ptrdiff_t*)
355 {
356 PyErr_SetString(PyExc_TypeError,
357 "Floor divide is not defined for complex numbers.");
358 return 0;
359 }
360
361 template <typename T>
362 struct True_divide {
operator ()True_divide363 bool operator()(T &result, T x, T y) {
364 result = x / y;
365 return false;
366 }
367 };
368
369 template <>
370 template <>
ufunc(int ndim,const size_t * shape,PyObject * a_,const ptrdiff_t * hops_a,PyObject * b_,const ptrdiff_t * hops_b)371 PyObject *Binary_op<True_divide>::ufunc<long>(int ndim, const size_t *shape,
372 PyObject *a_, const ptrdiff_t *hops_a,
373 PyObject *b_, const ptrdiff_t *hops_b)
374 {
375 typedef long I;
376 typedef double O;
377
378 assert(Array<I>::check_exact(a_)); Array<I> *a = (Array<I>*)a_;
379 assert(Array<I>::check_exact(b_)); Array<I> *b = (Array<I>*)b_;
380 Array<O> *temp_a = 0;
381 Array<O> *temp_b = 0;
382 PyObject* result = 0;
383 I *src;
384 O *dest;
385 size_t size;
386
387 // convert arrays to double, required by semantics of true divide
388 temp_a = Array<O>::make(ndim, shape, &size);
389 if(!temp_a) goto end;
390 src = a->data();
391 dest = temp_a->data();
392 for (size_t i = 0; i < size; ++i) dest[i] = src[i];
393
394 temp_b = Array<O>::make(ndim, shape, &size);
395 if(!temp_b) goto end;
396 src = b->data();
397 dest = temp_b->data();
398 for (size_t i = 0; i < size; ++i) dest[i] = src[i];
399
400 result = Binary_op<True_divide>::ufunc<O>(ndim, shape,
401 (PyObject*)temp_a, hops_a,
402 (PyObject*)temp_b, hops_b);
403 end:
404 if(temp_a) Py_DECREF(temp_a);
405 if(temp_b) Py_DECREF(temp_b);
406 return result;
407 }
408
409
410 template <typename T>
411 struct Divide {
operator ()Divide412 bool operator()(T &result, T x, T y) {
413 result = x / y;
414 return false;
415 }
416 };
417
418 #if PY_MAJOR_VERSION < 3
419 // not needed in Python 3.x as Array<long> will be converted
420 // to Array<double> for true-division
421 template <>
operator ()(long & result,long x,long y)422 bool Divide<long>::operator()(long &result, long x, long y)
423 {
424 Floor_divide<long> floor_divide;
425 return floor_divide(result, x, y);
426 }
427 #endif
428
dot_product(PyObject * a,PyObject * b)429 PyObject *dot_product(PyObject *a, PyObject *b)
430 {
431 Dtype dtype;
432 if (coerce_to_arrays(&a, &b, &dtype) < 0) return 0;
433
434 PyObject *result = 0;
435 int ndim_a, ndim_b;
436 reinterpret_cast<Array_base*>(a)->ndim_shape(&ndim_a, 0);
437 reinterpret_cast<Array_base*>(b)->ndim_shape(&ndim_b, 0);
438 if (ndim_a == 0 || ndim_b == 0) {
439 PyErr_SetString(PyExc_ValueError,
440 "dot does not support zero-dimensional arrays yet.");
441 goto end;
442 }
443
444 if (ndim_a == 1 && ndim_b == 1)
445 result = array_scalar_product_dtable[int(dtype)](a, b);
446 else
447 result = array_matrix_product_dtable[int(dtype)](a, b);
448
449 end:
450 Py_DECREF(a);
451 Py_DECREF(b);
452 return result;
453 }
454
455 template <typename Op>
apply_unary_ufunc(PyObject * a_)456 PyObject *apply_unary_ufunc(PyObject *a_)
457 {
458 typedef typename Op::IType IT;
459 typedef typename Op::OType OT;
460 Op operation;
461
462 if (Op::error) {
463 PyErr_SetString(PyExc_TypeError, Op::error);
464 return 0;
465 }
466
467 assert(Array<IT>::check_exact(a_)); Array<IT> *a = (Array<IT>*)a_;
468 int ndim;
469 size_t *shape;
470 a->ndim_shape(&ndim, &shape);
471 if (ndim == 0)
472 return (PyObject*)pyobject_from_number(operation(*a->data()));
473
474 if (Op::unchanged) {
475 Py_INCREF(a_);
476 return a_;
477 }
478
479 size_t size;
480 Array<OT> *result = Array<OT>::make(ndim, shape, &size);
481 if (result == 0) return 0;
482 IT *src = a->data();
483 OT *dest = result->data();
484 for (size_t i = 0; i < size; ++i) dest[i] = operation(src[i]);
485 return (PyObject*)result;
486 }
487
488 template <typename T>
489 struct Negative {
490 typedef T IType;
491 typedef T OType;
492 static const char *error;
493 static const bool unchanged = false;
operator ()Negative494 T operator()(T x) { return -x; }
495 };
496
497 template <typename T>
498 const char *Negative<T>::error = 0;
499
500 template <typename T>
501 struct Positive {
502 typedef T IType;
503 typedef T OType;
504 static const char *error;
505 static const bool unchanged = true;
operator ()Positive506 T operator()(T x) { return x; }
507 };
508
509 template <typename T>
510 const char *Positive<T>::error = 0;
511
512 template <typename T>
513 struct Absolute {
514 typedef T IType;
515 typedef T OType;
516 static const char *error;
517 static const bool unchanged = false;
operator ()Absolute518 T operator()(T x) { return std::abs(x); }
519 };
520
521 template <>
522 struct Absolute<Complex> {
523 typedef Complex IType;
524 typedef double OType;
525 static const char *error;
526 static const bool unchanged = false;
operator ()Absolute527 double operator()(Complex x) { return std::abs(x); }
528 };
529
530 template <typename T>
531 const char *Absolute<T>::error = 0;
532 // Needed for gcc 4.4.
533 const char *Absolute<Complex>::error = 0;
534
535 template <typename T>
536 struct Conjugate {
537 typedef T IType;
538 typedef T OType;
539 static const char *error;
540 static const bool unchanged = true;
operator ()Conjugate541 T operator()(T x) { return x; }
542 };
543
544 template <>
545 struct Conjugate<Complex> {
546 typedef Complex IType;
547 typedef Complex OType;
548 static const char *error;
549 static const bool unchanged = false;
operator ()Conjugate550 Complex operator()(Complex x) { return std::conj(x); }
551 };
552
553 template <typename T>
554 const char *Conjugate<T>::error = 0;
555 const char *Conjugate<Complex>::error = 0;
556
557 // Integers are not changed by any kind of rounding.
558 template <typename Kind>
559 struct Round<Kind, long> {
560 typedef long IType;
561 typedef long OType;
562 static const char *error;
563 static const bool unchanged = true;
operator ()Round564 long operator()(long x) { return x; }
565 };
566
567 template <typename Kind>
568 const char *Round<Kind, long>::error = 0;
569
570 template <typename Kind>
571 struct Round<Kind, double> {
572 typedef double IType;
573 typedef double OType;
574 static const char *error;
575 static const bool unchanged = false;
operator ()Round576 double operator()(double x) {
577 Kind rounding_kind;
578 return rounding_kind(x);
579 }
580 };
581
582 template <typename Kind>
583 const char *Round<Kind, double>::error = 0;
584
585 template <typename Kind>
586 struct Round<Kind, Complex> {
587 typedef Complex IType;
588 typedef Complex OType;
589 static const char *error;
590 static const bool unchanged = false;
operator ()Round591 Complex operator()(Complex) {
592 return std::numeric_limits<Complex>::quiet_NaN();
593 }
594 };
595
596 template <typename Kind>
597 const char *Round<Kind, Complex>::error =
598 "Rounding is not defined for complex numbers.";
599
600 // The following three types are used as Kind template parameter for Round.
601
602 struct Nearest {
603 // Rounding to nearest even, same as numpy.
operator ()Nearest604 double operator()(double x) {
605 double y = std::floor(x), r = x - y;
606 if (r > 0.5) {
607 ++y;
608 } else if (r == 0.5) {
609 r = y - 2.0 * std::floor(0.5 * y);
610 if (r == 1) ++y;
611 }
612 if (y == 0 && x < 0) y = -0.0;
613 return y;
614 }
615 };
616
operator ()Floor617 struct Floor { double operator()(double x) { return std::floor(x); } };
618
operator ()Ceil619 struct Ceil { double operator()(double x) { return std::ceil(x); } };
620
621 #if PY_MAJOR_VERSION >= 3
622
623 template <typename T>
624 PyNumberMethods Array<T>::as_number = {
625 Binary_op<Add>::apply, // nb_add
626 Binary_op<Subtract>::apply, // nb_subtract
627 Binary_op<Multiply>::apply, // nb_multiply
628 Binary_op<Remainder>::apply, // nb_remainder
629 (binaryfunc)0, // nb_divmod
630 (ternaryfunc)0, // nb_power
631 apply_unary_ufunc<Negative<T> >, // nb_negative
632 apply_unary_ufunc<Positive<T> >, // nb_positive
633 apply_unary_ufunc<Absolute<T> >, // nb_absolute
634 (inquiry)0, // nb_bool
635 (unaryfunc)0, // nb_invert
636 (binaryfunc)0, // nb_lshift
637 (binaryfunc)0, // nb_rshift
638 (binaryfunc)0, // nb_and
639 (binaryfunc)0, // nb_xor
640 (binaryfunc)0, // nb_or
641 (unaryfunc)0, // nb_int
642 (void*)0, // *nb_reserved
643 (unaryfunc)0, // nb_float
644
645 (binaryfunc)0, // nb_inplace_add
646 (binaryfunc)0, // nb_inplace_subtract
647 (binaryfunc)0, // nb_inplace_multiply
648 (binaryfunc)0, // nb_inplace_remainder
649 (ternaryfunc)0, // nb_inplace_power
650 (binaryfunc)0, // nb_inplace_lshift
651 (binaryfunc)0, // nb_inplace_rshift
652 (binaryfunc)0, // nb_inplace_and
653 (binaryfunc)0, // nb_inplace_xor
654 (binaryfunc)0, // nb_inplace_or
655
656 Binary_op<Floor_divide>::apply, // nb_floor_divide
657 Binary_op<True_divide>::apply, // nb_true_divide
658 (binaryfunc)0, // nb_inplace_floor_divide
659 (binaryfunc)0, // nb_inplace_true_divide
660
661 (unaryfunc)0 // nb_index
662 };
663
664 #else // Python 2.x
665
666 template <typename T>
667 PyNumberMethods Array<T>::as_number = {
668 Binary_op<Add>::apply, // nb_add
669 Binary_op<Subtract>::apply, // nb_subtract
670 Binary_op<Multiply>::apply, // nb_multiply
671 Binary_op<Divide>::apply, // nb_divide
672 Binary_op<Remainder>::apply, // nb_remainder
673 (binaryfunc)0, // nb_divmod
674 (ternaryfunc)0, // nb_power
675 apply_unary_ufunc<Negative<T> >, // nb_negative
676 apply_unary_ufunc<Positive<T> >, // nb_positive
677 apply_unary_ufunc<Absolute<T> >, // nb_absolute
678 (inquiry)0, // nb_nonzero
679 (unaryfunc)0, // nb_invert
680 (binaryfunc)0, // nb_lshift
681 (binaryfunc)0, // nb_rshift
682 (binaryfunc)0, // nb_and
683 (binaryfunc)0, // nb_xor
684 (binaryfunc)0, // nb_or
685 (coercion)0, // nb_coerce
686 (unaryfunc)0, // nb_int
687 (unaryfunc)0, // nb_long
688 (unaryfunc)0, // nb_float
689 (unaryfunc)0, // nb_oct
690 (unaryfunc)0, // nb_hex
691
692 (binaryfunc)0, // nb_inplace_add
693 (binaryfunc)0, // nb_inplace_subtract
694 (binaryfunc)0, // nb_inplace_multiply
695 (binaryfunc)0, // nb_inplace_divide
696 (binaryfunc)0, // nb_inplace_remainder
697 (ternaryfunc)0, // nb_inplace_power
698 (binaryfunc)0, // nb_inplace_lshift
699 (binaryfunc)0, // nb_inplace_rshift
700 (binaryfunc)0, // nb_inplace_and
701 (binaryfunc)0, // nb_inplace_xor
702 (binaryfunc)0, // nb_inplace_or
703
704 Binary_op<Floor_divide>::apply, // nb_floor_divide
705 Binary_op<True_divide>::apply, // nb_true_divide
706 (binaryfunc)0, // nb_inplace_floor_divide
707 (binaryfunc)0, // nb_inplace_true_divide
708
709 (unaryfunc)0 // nb_index
710 };
711
712 #endif // Python 3 check
713
714 // Explicit instantiations.
715 template PyNumberMethods Array<long>::as_number;
716 template PyNumberMethods Array<double>::as_number;
717 template PyNumberMethods Array<Complex>::as_number;
718
719 template PyObject *apply_unary_ufunc<Conjugate<long> >(PyObject*);
720 template PyObject *apply_unary_ufunc<Conjugate<double> >(PyObject*);
721 template PyObject *apply_unary_ufunc<Conjugate<Complex> >(PyObject*);
722
723 template PyObject *apply_unary_ufunc<Round<Nearest, long> >(PyObject*);
724 template PyObject *apply_unary_ufunc<Round<Nearest, double> >(PyObject*);
725 template PyObject *apply_unary_ufunc<Round<Nearest, Complex> >(PyObject*);
726
727 template PyObject *apply_unary_ufunc<Round<Floor, long> >(PyObject*);
728 template PyObject *apply_unary_ufunc<Round<Floor, double> >(PyObject*);
729 template PyObject *apply_unary_ufunc<Round<Floor, Complex> >(PyObject*);
730
731 template PyObject *apply_unary_ufunc<Round<Ceil, long> >(PyObject*);
732 template PyObject *apply_unary_ufunc<Round<Ceil, double> >(PyObject*);
733 template PyObject *apply_unary_ufunc<Round<Ceil, Complex> >(PyObject*);
734