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