summaryrefslogtreecommitdiff
path: root/numpy
diff options
context:
space:
mode:
Diffstat (limited to 'numpy')
-rw-r--r--numpy/core/code_generators/numpy_api.py1
-rw-r--r--numpy/core/include/numpy/npy_math.h53
-rw-r--r--numpy/core/include/numpy/ufuncobject.h2
-rw-r--r--numpy/core/numeric.py4
-rw-r--r--numpy/core/setup.py13
-rw-r--r--numpy/core/setup_common.py9
-rw-r--r--numpy/core/src/multiarray/ctors.c27
-rw-r--r--numpy/core/src/umath/operand_flag_tests.c.src1
-rw-r--r--numpy/core/src/umath/struct_ufunc_test.c.src122
-rw-r--r--numpy/core/src/umath/test_rational.c.src358
-rw-r--r--numpy/core/src/umath/ufunc_object.c163
-rw-r--r--numpy/core/src/umath/ufunc_type_resolution.c53
-rw-r--r--numpy/core/tests/test_numeric.py6
-rw-r--r--numpy/core/tests/test_ufunc.py20
-rw-r--r--numpy/distutils/misc_util.py20
-rw-r--r--numpy/linalg/umath_linalg.c.src4
16 files changed, 660 insertions, 196 deletions
diff --git a/numpy/core/code_generators/numpy_api.py b/numpy/core/code_generators/numpy_api.py
index 07a87f98d..152d0f948 100644
--- a/numpy/core/code_generators/numpy_api.py
+++ b/numpy/core/code_generators/numpy_api.py
@@ -384,6 +384,7 @@ ufunc_funcs_api = {
# End 1.6 API
'PyUFunc_DefaultTypeResolver': 39,
'PyUFunc_ValidateCasting': 40,
+ 'PyUFunc_RegisterLoopForDescr': 41,
}
# List of all the dicts which define the C API
diff --git a/numpy/core/include/numpy/npy_math.h b/numpy/core/include/numpy/npy_math.h
index a7c50f6e6..625999022 100644
--- a/numpy/core/include/numpy/npy_math.h
+++ b/numpy/core/include/numpy/npy_math.h
@@ -6,6 +6,9 @@ extern "C" {
#endif
#include <math.h>
+#ifdef NPY_HAVE_CONFIG_H
+#include <npy_config.h>
+#endif
#include <numpy/npy_common.h>
/*
@@ -148,33 +151,51 @@ double npy_spacing(double x);
/*
* IEEE 754 fpu handling. Those are guaranteed to be macros
*/
-#ifndef NPY_HAVE_DECL_ISNAN
- #define npy_isnan(x) ((x) != (x))
+
+/* use builtins to avoid function calls in tight loops
+ * only available if npy_config.h is available (= numpys own build) */
+#if HAVE___BUILTIN_ISNAN
+ #define npy_isnan(x) __builtin_isnan(x)
#else
- #ifdef _MSC_VER
- #define npy_isnan(x) _isnan((x))
+ #ifndef NPY_HAVE_DECL_ISNAN
+ #define npy_isnan(x) ((x) != (x))
#else
- #define npy_isnan(x) isnan((x))
+ #ifdef _MSC_VER
+ #define npy_isnan(x) _isnan((x))
+ #else
+ #define npy_isnan(x) isnan(x)
+ #endif
#endif
#endif
-#ifndef NPY_HAVE_DECL_ISFINITE
- #ifdef _MSC_VER
- #define npy_isfinite(x) _finite((x))
+
+/* only available if npy_config.h is available (= numpys own build) */
+#if HAVE___BUILTIN_ISFINITE
+ #define npy_isfinite(x) __builtin_isfinite(x)
+#else
+ #ifndef NPY_HAVE_DECL_ISFINITE
+ #ifdef _MSC_VER
+ #define npy_isfinite(x) _finite((x))
+ #else
+ #define npy_isfinite(x) !npy_isnan((x) + (-x))
+ #endif
#else
- #define npy_isfinite(x) !npy_isnan((x) + (-x))
+ #define npy_isfinite(x) isfinite((x))
#endif
-#else
- #define npy_isfinite(x) isfinite((x))
#endif
-#ifndef NPY_HAVE_DECL_ISINF
- #define npy_isinf(x) (!npy_isfinite(x) && !npy_isnan(x))
+/* only available if npy_config.h is available (= numpys own build) */
+#if HAVE___BUILTIN_ISINF
+ #define npy_isinf(x) __builtin_isinf(x)
#else
- #ifdef _MSC_VER
- #define npy_isinf(x) (!_finite((x)) && !_isnan((x)))
+ #ifndef NPY_HAVE_DECL_ISINF
+ #define npy_isinf(x) (!npy_isfinite(x) && !npy_isnan(x))
#else
- #define npy_isinf(x) isinf((x))
+ #ifdef _MSC_VER
+ #define npy_isinf(x) (!_finite((x)) && !_isnan((x)))
+ #else
+ #define npy_isinf(x) isinf((x))
+ #endif
#endif
#endif
diff --git a/numpy/core/include/numpy/ufuncobject.h b/numpy/core/include/numpy/ufuncobject.h
index 686d12c38..75611426c 100644
--- a/numpy/core/include/numpy/ufuncobject.h
+++ b/numpy/core/include/numpy/ufuncobject.h
@@ -319,6 +319,8 @@ typedef struct _loop1d_info {
void *data;
int *arg_types;
struct _loop1d_info *next;
+ int nargs;
+ PyArray_Descr **arg_dtypes;
} PyUFunc_Loop1d;
diff --git a/numpy/core/numeric.py b/numpy/core/numeric.py
index d689982db..a187d7c5b 100644
--- a/numpy/core/numeric.py
+++ b/numpy/core/numeric.py
@@ -2137,7 +2137,7 @@ def array_equal(a1, a2):
return False
if a1.shape != a2.shape:
return False
- return bool(equal(a1,a2).all())
+ return bool(asarray(a1 == a2).all())
def array_equiv(a1, a2):
"""
@@ -2179,7 +2179,7 @@ def array_equiv(a1, a2):
except:
return False
try:
- return bool(equal(a1,a2).all())
+ return bool(asarray(a1 == a2).all())
except ValueError:
return False
diff --git a/numpy/core/setup.py b/numpy/core/setup.py
index 3b08d6edd..5a1e6cf6e 100644
--- a/numpy/core/setup.py
+++ b/numpy/core/setup.py
@@ -161,6 +161,10 @@ def check_math_capabilities(config, moredefs, mathlibs):
check_funcs(OPTIONAL_STDFUNCS)
+ for f, args in OPTIONAL_INTRINSICS:
+ if config.check_func(f, decl=False, call=True, call_args=args):
+ moredefs.append((fname2def(f), 1))
+
# C99 functions: float and long double versions
check_funcs(C99_FUNCS_SINGLE)
check_funcs(C99_FUNCS_EXTENDED)
@@ -602,6 +606,8 @@ def configuration(parent_package='',top_path=None):
config.add_include_dirs(join('src', 'umath'))
config.add_include_dirs(join('src', 'npysort'))
+ config.add_define_macros([("HAVE_NPY_CONFIG_H", "1")])
+
config.numpy_include_dirs.extend(config.paths('include'))
deps = [join('src','npymath','_signbit.c'),
@@ -929,6 +935,13 @@ def configuration(parent_package='',top_path=None):
sources = [join('src','umath', 'test_rational.c.src')])
#######################################################################
+ # struct_ufunc_test module #
+ #######################################################################
+
+ config.add_extension('struct_ufunc_test',
+ sources = [join('src','umath', 'struct_ufunc_test.c.src')])
+
+ #######################################################################
# multiarray_tests module #
#######################################################################
diff --git a/numpy/core/setup_common.py b/numpy/core/setup_common.py
index 3f705cbe4..e778e507b 100644
--- a/numpy/core/setup_common.py
+++ b/numpy/core/setup_common.py
@@ -97,6 +97,15 @@ OPTIONAL_STDFUNCS = ["expm1", "log1p", "acosh", "asinh", "atanh",
"rint", "trunc", "exp2", "log2", "hypot", "atan2", "pow",
"copysign", "nextafter"]
+# optional gcc compiler builtins and their call arguments
+# call arguments are required as the compiler will do strict signature checking
+OPTIONAL_INTRINSICS = [("__builtin_isnan", '5.'),
+ ("__builtin_isinf", '5.'),
+ ("__builtin_isfinite", '5.'),
+ ("__builtin_bswap32", '5u'),
+ ("__builtin_bswap64", '5u'),
+ ]
+
# Subset of OPTIONAL_STDFUNCS which may alreay have HAVE_* defined by Python.h
OPTIONAL_STDFUNCS_MAYBE = ["expm1", "log1p", "acosh", "atanh", "asinh", "hypot",
"copysign"]
diff --git a/numpy/core/src/multiarray/ctors.c b/numpy/core/src/multiarray/ctors.c
index f366a34b1..b1a9d9859 100644
--- a/numpy/core/src/multiarray/ctors.c
+++ b/numpy/core/src/multiarray/ctors.c
@@ -311,25 +311,38 @@ _strided_byte_swap(void *p, npy_intp stride, npy_intp n, int size)
case 1: /* no byteswap necessary */
break;
case 4:
- for (a = (char*)p; n > 0; n--, a += stride - 1) {
- b = a + 3;
- c = *a; *a++ = *b; *b-- = c;
- c = *a; *a = *b; *b = c;
+ for (a = (char*)p; n > 0; n--, a += stride) {
+ npy_uint32 * a_ = (npy_uint32 *)a;
+#ifdef HAVE___BUILTIN_BSWAP32
+ *a_ = __builtin_bswap32(*a_);
+#else
+ /* a decent compiler can convert this to bswap too */
+ *a_ = ((*a_ & 0xff000000u) >> 24) | ((*a_ & 0x00ff0000u) >> 8) |
+ ((*a_ & 0x0000ff00u) << 8) | ((*a_ & 0x000000ffu) << 24);
+#endif
}
break;
case 8:
- for (a = (char*)p; n > 0; n--, a += stride - 3) {
+ for (a = (char*)p; n > 0; n--) {
+#ifdef HAVE___BUILTIN_BSWAP64
+ npy_uint64 * a_ = (npy_uint64 *)a;
+ *a_ = __builtin_bswap64(*a_);
+ a += stride;
+#else
+ /* mask version would be faster but requires C99 */
b = a + 7;
c = *a; *a++ = *b; *b-- = c;
c = *a; *a++ = *b; *b-- = c;
c = *a; *a++ = *b; *b-- = c;
c = *a; *a = *b; *b = c;
+ a += stride - 3;
+#endif
}
break;
case 2:
for (a = (char*)p; n > 0; n--, a += stride) {
- b = a + 1;
- c = *a; *a = *b; *b = c;
+ npy_uint16 * a_ = (npy_uint16 *)a;
+ *a_ = (((*a_ >> 8) & 0xffu) | ((*a_ & 0xffu) << 8));
}
break;
default:
diff --git a/numpy/core/src/umath/operand_flag_tests.c.src b/numpy/core/src/umath/operand_flag_tests.c.src
index 0cae4db36..7eaf1fbfc 100644
--- a/numpy/core/src/umath/operand_flag_tests.c.src
+++ b/numpy/core/src/umath/operand_flag_tests.c.src
@@ -1,6 +1,5 @@
#define NPY_NO_DEPRECATED_API NPY_API_VERSION
-#include <stdint.h>
#include <math.h>
#include <Python.h>
#include <structmember.h>
diff --git a/numpy/core/src/umath/struct_ufunc_test.c.src b/numpy/core/src/umath/struct_ufunc_test.c.src
new file mode 100644
index 000000000..4bd24559f
--- /dev/null
+++ b/numpy/core/src/umath/struct_ufunc_test.c.src
@@ -0,0 +1,122 @@
+#include "Python.h"
+#include "math.h"
+#include "numpy/ndarraytypes.h"
+#include "numpy/ufuncobject.h"
+#include "numpy/npy_3kcompat.h"
+
+
+/*
+ * struct_ufunc_test.c
+ * This is the C code for creating your own
+ * Numpy ufunc for a structured array dtype.
+ *
+ * Details explaining the Python-C API can be found under
+ * 'Extending and Embedding' and 'Python/C API' at
+ * docs.python.org .
+ */
+
+static PyMethodDef StructUfuncTestMethods[] = {
+ {NULL, NULL, 0, NULL}
+};
+
+/* The loop definition must precede the PyMODINIT_FUNC. */
+
+static void add_uint64_triplet(char **args, npy_intp *dimensions,
+ npy_intp* steps, void* data)
+{
+ npy_intp i;
+ npy_intp is1=steps[0];
+ npy_intp is2=steps[1];
+ npy_intp os=steps[2];
+ npy_intp n=dimensions[0];
+ uint64_t *x, *y, *z;
+
+ char *i1=args[0];
+ char *i2=args[1];
+ char *op=args[2];
+
+ for (i = 0; i < n; i++) {
+
+ x = (uint64_t*)i1;
+ y = (uint64_t*)i2;
+ z = (uint64_t*)op;
+
+ z[0] = x[0] + y[0];
+ z[1] = x[1] + y[1];
+ z[2] = x[2] + y[2];
+
+ i1 += is1;
+ i2 += is2;
+ op += os;
+ }
+}
+
+#if defined(NPY_PY3K)
+static struct PyModuleDef moduledef = {
+ PyModuleDef_HEAD_INIT,
+ "struct_ufunc_test",
+ NULL,
+ -1,
+ StructUfuncTestMethods,
+ NULL,
+ NULL,
+ NULL,
+ NULL
+};
+#endif
+
+#if defined(NPY_PY3K)
+PyMODINIT_FUNC PyInit_struct_ufunc_test(void)
+#else
+PyMODINIT_FUNC initstruct_ufunc_test(void)
+#endif
+{
+ PyObject *m, *add_triplet, *d;
+ PyObject *dtype_dict;
+ PyArray_Descr *dtype;
+ PyArray_Descr *dtypes[3];
+
+#if defined(NPY_PY3K)
+ m = PyModule_Create(&moduledef);
+#else
+ m = Py_InitModule("struct_ufunc_test", StructUfuncTestMethods);
+#endif
+
+ if (m == NULL) {
+#if defined(NPY_PY3K)
+ return NULL;
+#else
+ return;
+#endif
+ }
+
+ import_array();
+ import_umath();
+
+ add_triplet = PyUFunc_FromFuncAndData(NULL, NULL, NULL, 0, 2, 1,
+ PyUFunc_None, "add_triplet",
+ "add_triplet_docstring", 0);
+
+ dtype_dict = Py_BuildValue("[(s, s), (s, s), (s, s)]",
+ "f0", "u8", "f1", "u8", "f2", "u8");
+ PyArray_DescrConverter(dtype_dict, &dtype);
+ Py_DECREF(dtype_dict);
+
+ dtypes[0] = dtype;
+ dtypes[1] = dtype;
+ dtypes[2] = dtype;
+
+ PyUFunc_RegisterLoopForDescr(add_triplet,
+ dtype,
+ &add_uint64_triplet,
+ dtypes,
+ NULL);
+
+ d = PyModule_GetDict(m);
+
+ PyDict_SetItemString(d, "add_triplet", add_triplet);
+ Py_DECREF(add_triplet);
+#if defined(NPY_PY3K)
+ return m;
+#endif
+}
diff --git a/numpy/core/src/umath/test_rational.c.src b/numpy/core/src/umath/test_rational.c.src
index aca3d21f3..f9153b87c 100644
--- a/numpy/core/src/umath/test_rational.c.src
+++ b/numpy/core/src/umath/test_rational.c.src
@@ -2,13 +2,12 @@
#define NPY_NO_DEPRECATED_API NPY_API_VERSION
-#include <stdint.h>
#include <math.h>
#include <Python.h>
#include <structmember.h>
#include <numpy/arrayobject.h>
#include <numpy/ufuncobject.h>
-#include "numpy/npy_3kcompat.h"
+#include <numpy/npy_3kcompat.h>
/* Relevant arithmetic exceptions */
@@ -47,63 +46,67 @@ set_zero_divide(void) {
/* Integer arithmetic utilities */
-static NPY_INLINE int32_t
-safe_neg(int32_t x) {
- if (x==(int32_t)1<<31) {
+static NPY_INLINE npy_int32
+safe_neg(npy_int32 x) {
+ if (x==(npy_int32)1<<31) {
set_overflow();
}
return -x;
}
-static NPY_INLINE int32_t
-safe_abs32(int32_t x) {
+static NPY_INLINE npy_int32
+safe_abs32(npy_int32 x) {
+ npy_int32 nx;
if (x>=0) {
return x;
}
- int32_t nx = -x;
+ nx = -x;
if (nx<0) {
set_overflow();
}
return nx;
}
-static NPY_INLINE int64_t
-safe_abs64(int64_t x) {
+static NPY_INLINE npy_int64
+safe_abs64(npy_int64 x) {
+ npy_int64 nx;
if (x>=0) {
return x;
}
- int64_t nx = -x;
+ nx = -x;
if (nx<0) {
set_overflow();
}
return nx;
}
-static NPY_INLINE int64_t
-gcd(int64_t x, int64_t y) {
+static NPY_INLINE npy_int64
+gcd(npy_int64 x, npy_int64 y) {
x = safe_abs64(x);
y = safe_abs64(y);
if (x < y) {
- int64_t t = x;
+ npy_int64 t = x;
x = y;
y = t;
}
while (y) {
+ npy_int64 t;
x = x%y;
- int64_t t = x;
+ t = x;
x = y;
y = t;
}
return x;
}
-static NPY_INLINE int64_t
-lcm(int64_t x, int64_t y) {
+static NPY_INLINE npy_int64
+lcm(npy_int64 x, npy_int64 y) {
+ npy_int64 lcm;
if (!x || !y) {
return 0;
}
x /= gcd(x,y);
- int64_t lcm = x*y;
+ lcm = x*y;
if (lcm/y!=x) {
set_overflow();
}
@@ -114,17 +117,17 @@ lcm(int64_t x, int64_t y) {
typedef struct {
/* numerator */
- int32_t n;
+ npy_int32 n;
/*
* denominator minus one: numpy.zeros() uses memset(0) for non-object
* types, so need to ensure that rational(0) has all zero bytes
*/
- int32_t dmm;
+ npy_int32 dmm;
} rational;
static NPY_INLINE rational
-make_rational_int(int64_t n) {
- rational r = {n,0};
+make_rational_int(npy_int64 n) {
+ rational r = {(npy_int32)n,0};
if (r.n != n) {
set_overflow();
}
@@ -132,17 +135,18 @@ make_rational_int(int64_t n) {
}
static rational
-make_rational_slow(int64_t n_, int64_t d_) {
+make_rational_slow(npy_int64 n_, npy_int64 d_) {
rational r = {0};
if (!d_) {
set_zero_divide();
}
else {
- int64_t g = gcd(n_,d_);
+ npy_int64 g = gcd(n_,d_);
+ npy_int32 d;
n_ /= g;
d_ /= g;
- r.n = n_;
- int32_t d = d_;
+ r.n = (npy_int32)n_;
+ d = (npy_int32)d_;
if (r.n!=n_ || d!=d_) {
set_overflow();
}
@@ -157,20 +161,20 @@ make_rational_slow(int64_t n_, int64_t d_) {
return r;
}
-static NPY_INLINE int32_t
+static NPY_INLINE npy_int32
d(rational r) {
return r.dmm+1;
}
/* Assumes d_ > 0 */
static rational
-make_rational_fast(int64_t n_, int64_t d_) {
- int64_t g = gcd(n_,d_);
+make_rational_fast(npy_int64 n_, npy_int64 d_) {
+ npy_int64 g = gcd(n_,d_);
+ rational r;
n_ /= g;
d_ /= g;
- rational r;
- r.n = n_;
- r.dmm = d_-1;
+ r.n = (npy_int32)n_;
+ r.dmm = (npy_int32)(d_-1);
if (r.n!=n_ || r.dmm+1!=d_) {
set_overflow();
}
@@ -191,29 +195,29 @@ rational_add(rational x, rational y) {
* Note that the numerator computation can never overflow int128_t,
* since each term is strictly under 2**128/4 (since d > 0).
*/
- return make_rational_fast((int64_t)x.n*d(y)+(int64_t)d(x)*y.n,
- (int64_t)d(x)*d(y));
+ return make_rational_fast((npy_int64)x.n*d(y)+(npy_int64)d(x)*y.n,
+ (npy_int64)d(x)*d(y));
}
static NPY_INLINE rational
rational_subtract(rational x, rational y) {
/* We're safe from overflow as with + */
- return make_rational_fast((int64_t)x.n*d(y)-(int64_t)d(x)*y.n,
- (int64_t)d(x)*d(y));
+ return make_rational_fast((npy_int64)x.n*d(y)-(npy_int64)d(x)*y.n,
+ (npy_int64)d(x)*d(y));
}
static NPY_INLINE rational
rational_multiply(rational x, rational y) {
/* We're safe from overflow as with + */
- return make_rational_fast((int64_t)x.n*y.n,(int64_t)d(x)*d(y));
+ return make_rational_fast((npy_int64)x.n*y.n,(npy_int64)d(x)*d(y));
}
static NPY_INLINE rational
rational_divide(rational x, rational y) {
- return make_rational_slow((int64_t)x.n*d(y),(int64_t)d(x)*y.n);
+ return make_rational_slow((npy_int64)x.n*d(y),(npy_int64)d(x)*y.n);
}
-static NPY_INLINE int64_t
+static NPY_INLINE npy_int64
rational_floor(rational x) {
/* Always round down */
if (x.n>=0) {
@@ -223,10 +227,10 @@ rational_floor(rational x) {
* This can be done without casting up to 64 bits, but it requires
* working out all the sign cases
*/
- return -((-(int64_t)x.n+d(x)-1)/d(x));
+ return -((-(npy_int64)x.n+d(x)-1)/d(x));
}
-static NPY_INLINE int64_t
+static NPY_INLINE npy_int64
rational_ceil(rational x) {
return -rational_floor(rational_negative(x));
}
@@ -245,14 +249,14 @@ rational_abs(rational x) {
return y;
}
-static NPY_INLINE int64_t
+static NPY_INLINE npy_int64
rational_rint(rational x) {
/*
* Round towards nearest integer, moving exact half integers towards
* zero
*/
- int32_t d_ = d(x);
- return (2*(int64_t)x.n+(x.n<0?-d_:d_))/(2*(int64_t)d_);
+ npy_int32 d_ = d(x);
+ return (2*(npy_int64)x.n+(x.n<0?-d_:d_))/(2*(npy_int64)d_);
}
static NPY_INLINE int
@@ -267,13 +271,14 @@ rational_inverse(rational x) {
set_zero_divide();
}
else {
+ npy_int32 d_;
y.n = d(x);
- int32_t d = x.n;
- if (d <= 0) {
- d = safe_neg(d);
+ d_ = x.n;
+ if (d_ <= 0) {
+ d_ = safe_neg(d_);
y.n = -y.n;
}
- y.dmm = d-1;
+ y.dmm = d_-1;
}
return y;
}
@@ -294,7 +299,7 @@ rational_ne(rational x, rational y) {
static NPY_INLINE int
rational_lt(rational x, rational y) {
- return (int64_t)x.n*d(y) < (int64_t)y.n*d(x);
+ return (npy_int64)x.n*d(y) < (npy_int64)y.n*d(x);
}
static NPY_INLINE int
@@ -312,7 +317,7 @@ rational_ge(rational x, rational y) {
return !rational_lt(x,y);
}
-static NPY_INLINE int32_t
+static NPY_INLINE npy_int32
rational_int(rational x) {
return x.n/d(x);
}
@@ -331,10 +336,11 @@ static int
scan_rational(const char** s, rational* x) {
long n,d;
int offset;
+ const char* ss;
if (sscanf(*s,"%ld%n",&n,&offset)<=0) {
return 0;
}
- const char* ss = *s+offset;
+ ss = *s+offset;
if (*ss!='/') {
*s = ss;
*x = make_rational_int(n);
@@ -352,7 +358,7 @@ scan_rational(const char** s, rational* x) {
/* Expose rational to Python as a numpy scalar */
typedef struct {
- PyObject_HEAD;
+ PyObject_HEAD
rational r;
} PyRational;
@@ -374,18 +380,24 @@ PyRational_FromRational(rational x) {
static PyObject*
pyrational_new(PyTypeObject* type, PyObject* args, PyObject* kwds) {
+ Py_ssize_t size;
+ PyObject* x[2];
+ long n[2]={0,1};
+ int i;
+ rational r;
if (kwds && PyDict_Size(kwds)) {
PyErr_SetString(PyExc_TypeError,
"constructor takes no keyword arguments");
return 0;
}
- Py_ssize_t size = PyTuple_GET_SIZE(args);
+ size = PyTuple_GET_SIZE(args);
if (size>2) {
PyErr_SetString(PyExc_TypeError,
"expected rational or numerator and optional denominator");
return 0;
}
- PyObject* x[2] = {PyTuple_GET_ITEM(args,0),PyTuple_GET_ITEM(args,1)};
+ x[0] = PyTuple_GET_ITEM(args,0);
+ x[1] = PyTuple_GET_ITEM(args,1);
if (size==1) {
if (PyRational_Check(x[0])) {
Py_INCREF(x[0]);
@@ -409,9 +421,9 @@ pyrational_new(PyTypeObject* type, PyObject* args, PyObject* kwds) {
return 0;
}
}
- long n[2]={0,1};
- int i;
for (i=0;i<size;i++) {
+ PyObject* y;
+ int eq;
n[i] = PyInt_AsLong(x[i]);
if (n[i]==-1 && PyErr_Occurred()) {
if (PyErr_ExceptionMatches(PyExc_TypeError)) {
@@ -423,11 +435,11 @@ pyrational_new(PyTypeObject* type, PyObject* args, PyObject* kwds) {
return 0;
}
/* Check that we had an exact integer */
- PyObject* y = PyInt_FromLong(n[i]);
+ y = PyInt_FromLong(n[i]);
if (!y) {
return 0;
}
- int eq = PyObject_RichCompareBool(x[i],y,Py_EQ);
+ eq = PyObject_RichCompareBool(x[i],y,Py_EQ);
Py_DECREF(y);
if (eq<0) {
return 0;
@@ -440,7 +452,7 @@ pyrational_new(PyTypeObject* type, PyObject* args, PyObject* kwds) {
return 0;
}
}
- rational r = make_rational_slow(n[0],n[1]);
+ r = make_rational_slow(n[0],n[1]);
if (PyErr_Occurred()) {
return 0;
}
@@ -452,41 +464,46 @@ pyrational_new(PyTypeObject* type, PyObject* args, PyObject* kwds) {
* overflow error for too long ints
*/
#define AS_RATIONAL(dst,object) \
- rational dst = {0}; \
- if (PyRational_Check(object)) { \
- dst = ((PyRational*)object)->r; \
- } \
- else { \
- long n_ = PyInt_AsLong(object); \
- if (n_==-1 && PyErr_Occurred()) { \
- if (PyErr_ExceptionMatches(PyExc_TypeError)) { \
- PyErr_Clear(); \
+ { \
+ dst.n = 0; \
+ if (PyRational_Check(object)) { \
+ dst = ((PyRational*)object)->r; \
+ } \
+ else { \
+ PyObject* y_; \
+ int eq_; \
+ long n_ = PyInt_AsLong(object); \
+ if (n_==-1 && PyErr_Occurred()) { \
+ if (PyErr_ExceptionMatches(PyExc_TypeError)) { \
+ PyErr_Clear(); \
+ Py_INCREF(Py_NotImplemented); \
+ return Py_NotImplemented; \
+ } \
+ return 0; \
+ } \
+ y_ = PyInt_FromLong(n_); \
+ if (!y_) { \
+ return 0; \
+ } \
+ eq_ = PyObject_RichCompareBool(object,y_,Py_EQ); \
+ Py_DECREF(y_); \
+ if (eq_<0) { \
+ return 0; \
+ } \
+ if (!eq_) { \
Py_INCREF(Py_NotImplemented); \
return Py_NotImplemented; \
} \
- return 0; \
- } \
- PyObject* y_ = PyInt_FromLong(n_); \
- if (!y_) { \
- return 0; \
+ dst = make_rational_int(n_); \
} \
- int eq_ = PyObject_RichCompareBool(object,y_,Py_EQ); \
- Py_DECREF(y_); \
- if (eq_<0) { \
- return 0; \
- } \
- if (!eq_) { \
- Py_INCREF(Py_NotImplemented); \
- return Py_NotImplemented; \
- } \
- dst = make_rational_int(n_); \
}
static PyObject*
pyrational_richcompare(PyObject* a, PyObject* b, int op) {
+ rational x, y;
+ int result = 0;
AS_RATIONAL(x,a);
AS_RATIONAL(y,b);
- int result = 0;
#define OP(py,op) case py: result = rational_##op(x,y); break;
switch (op) {
OP(Py_LT,lt)
@@ -538,9 +555,10 @@ pyrational_hash(PyObject* self) {
#define RATIONAL_BINOP_2(name,exp) \
static PyObject* \
pyrational_##name(PyObject* a, PyObject* b) { \
+ rational x, y, z; \
AS_RATIONAL(x,a); \
AS_RATIONAL(y,b); \
- rational z = exp; \
+ z = exp; \
if (PyErr_Occurred()) { \
return 0; \
} \
@@ -644,9 +662,9 @@ static PyGetSetDef pyrational_getset[] = {
static PyTypeObject PyRational_Type = {
#if defined(NPY_PY3K)
- PyVarObject_HEAD_INIT(&PyType_Type, 0)
+ PyVarObject_HEAD_INIT(NULL, 0)
#else
- PyObject_HEAD_INIT(&PyType_Type)
+ PyObject_HEAD_INIT(NULL)
0, /* ob_size */
#endif
"rational", /* tp_name */
@@ -720,14 +738,16 @@ npyrational_setitem(PyObject* item, void* data, void* arr) {
}
else {
long n = PyInt_AsLong(item);
+ PyObject* y;
+ int eq;
if (n==-1 && PyErr_Occurred()) {
return -1;
}
- PyObject* y = PyInt_FromLong(n);
+ y = PyInt_FromLong(n);
if (!y) {
return -1;
}
- int eq = PyObject_RichCompareBool(item,y,Py_EQ);
+ eq = PyObject_RichCompareBool(item,y,Py_EQ);
Py_DECREF(y);
if (eq<0) {
return -1;
@@ -744,11 +764,11 @@ npyrational_setitem(PyObject* item, void* data, void* arr) {
}
static NPY_INLINE void
-byteswap(int32_t* x) {
+byteswap(npy_int32* x) {
char* p = (char*)x;
size_t i;
for (i = 0; i < sizeof(*x)/2; i++) {
- int j = sizeof(*x)-1-i;
+ size_t j = sizeof(*x)-1-i;
char t = p[i];
p[i] = p[j];
p[j] = t;
@@ -759,10 +779,10 @@ static void
npyrational_copyswapn(void* dst_, npy_intp dstride, void* src_,
npy_intp sstride, npy_intp n, int swap, void* arr) {
char *dst = (char*)dst_, *src = (char*)src_;
+ npy_intp i;
if (!src) {
return;
}
- npy_intp i;
if (swap) {
for (i = 0; i < n; i++) {
rational* r = (rational*)(dst+dstride*i);
@@ -783,10 +803,11 @@ npyrational_copyswapn(void* dst_, npy_intp dstride, void* src_,
static void
npyrational_copyswap(void* dst, void* src, int swap, void* arr) {
+ rational* r;
if (!src) {
return;
}
- rational* r = (rational*)dst;
+ r = (rational*)dst;
memcpy(r,src,sizeof(rational));
if (swap) {
byteswap(&r->n);
@@ -805,13 +826,17 @@ npyrational_compare(const void* d0, const void* d1, void* arr) {
static int \
npyrational_##name(void* data_, npy_intp n, \
npy_intp* max_ind, void* arr) { \
+ const rational* data; \
+ npy_intp best_i; \
+ rational best_r; \
+ npy_intp i; \
if (!n) { \
return 0; \
} \
- const rational* data = (rational*)data_; \
- npy_intp best_i = 0; \
- rational best_r = data[0]; \
- npy_intp i; \
+ data = (rational*)data_; \
+ best_i = 0; \
+ best_r = data[0]; \
+ i; \
for (i = 1; i < n; i++) { \
if (rational_##op(data[i],best_r)) { \
best_i = i; \
@@ -910,9 +935,9 @@ PyArray_Descr npyrational_descr = {
} \
}
#define DEFINE_INT_CAST(bits) \
- DEFINE_CAST(int##bits##_t,rational,rational y = make_rational_int(x);) \
- DEFINE_CAST(rational,int##bits##_t,int32_t z = rational_int(x); \
- int##bits##_t y = z; if (y != z) set_overflow();)
+ DEFINE_CAST(npy_int##bits,rational,rational y = make_rational_int(x);) \
+ DEFINE_CAST(rational,npy_int##bits,npy_int32 z = rational_int(x); \
+ npy_int##bits y = z; if (y != z) set_overflow();)
DEFINE_INT_CAST(8)
DEFINE_INT_CAST(16)
DEFINE_INT_CAST(32)
@@ -955,8 +980,8 @@ RATIONAL_BINARY_UFUNC(greater,npy_bool,rational_gt(x,y))
RATIONAL_BINARY_UFUNC(less_equal,npy_bool,rational_le(x,y))
RATIONAL_BINARY_UFUNC(greater_equal,npy_bool,rational_ge(x,y))
-BINARY_UFUNC(gcd_ufunc,int64_t,int64_t,int64_t,gcd(x,y))
-BINARY_UFUNC(lcm_ufunc,int64_t,int64_t,int64_t,lcm(x,y))
+BINARY_UFUNC(gcd_ufunc,npy_int64,npy_int64,npy_int64,gcd(x,y))
+BINARY_UFUNC(lcm_ufunc,npy_int64,npy_int64,npy_int64,lcm(x,y))
#define UNARY_UFUNC(name,type,exp) \
void rational_ufunc_##name(char** args, npy_intp* dimensions, \
@@ -979,8 +1004,8 @@ UNARY_UFUNC(square,rational,rational_multiply(x,x))
UNARY_UFUNC(rint,rational,make_rational_int(rational_rint(x)))
UNARY_UFUNC(sign,rational,make_rational_int(rational_sign(x)))
UNARY_UFUNC(reciprocal,rational,rational_inverse(x))
-UNARY_UFUNC(numerator,int64_t,x.n)
-UNARY_UFUNC(denominator,int64_t,d(x))
+UNARY_UFUNC(numerator,npy_int64,x.n)
+UNARY_UFUNC(denominator,npy_int64,d(x))
static NPY_INLINE void
rational_matrix_multiply(char **args, npy_intp *dimensions, npy_intp *steps)
@@ -1059,8 +1084,8 @@ rational_ufunc_test_add(char** args, npy_intp* dimensions,
char *i0 = args[0], *i1 = args[1], *o = args[2];
int k;
for (k = 0; k < n; k++) {
- int64_t x = *(int64_t*)i0;
- int64_t y = *(int64_t*)i1;
+ npy_int64 x = *(npy_int64*)i0;
+ npy_int64 y = *(npy_int64*)i1;
*(rational*)o = rational_add(make_rational_fast(x, 1),
make_rational_fast(y, 1));
i0 += is0; i1 += is1; o += os;
@@ -1068,6 +1093,21 @@ rational_ufunc_test_add(char** args, npy_intp* dimensions,
}
+static void
+rational_ufunc_test_add_rationals(char** args, npy_intp* dimensions,
+ npy_intp* steps, void* data) {
+ npy_intp is0 = steps[0], is1 = steps[1], os = steps[2], n = *dimensions;
+ char *i0 = args[0], *i1 = args[1], *o = args[2];
+ int k;
+ for (k = 0; k < n; k++) {
+ rational x = *(rational*)i0;
+ rational y = *(rational*)i1;
+ *(rational*)o = rational_add(x, y);
+ i0 += is0; i1 += is1; o += os;
+ }
+}
+
+
PyMethodDef module_methods[] = {
{0} /* sentinel */
};
@@ -1095,6 +1135,10 @@ PyMODINIT_FUNC inittest_rational(void) {
#endif
PyObject *m = NULL;
+ PyObject* numpy_str;
+ PyObject* numpy;
+ int npy_rational;
+ PyObject* gufunc;
import_array();
if (PyErr_Occurred()) {
@@ -1104,11 +1148,11 @@ PyMODINIT_FUNC inittest_rational(void) {
if (PyErr_Occurred()) {
goto fail;
}
- PyObject* numpy_str = PyUString_FromString("numpy");
+ numpy_str = PyUString_FromString("numpy");
if (!numpy_str) {
goto fail;
}
- PyObject* numpy = PyImport_Import(numpy_str);
+ numpy = PyImport_Import(numpy_str);
Py_DECREF(numpy_str);
if (!numpy) {
goto fail;
@@ -1137,7 +1181,7 @@ PyMODINIT_FUNC inittest_rational(void) {
npyrational_arrfuncs.fillwithscalar = npyrational_fillwithscalar;
/* Left undefined: scanfunc, fromstr, sort, argsort */
Py_TYPE(&npyrational_descr) = &PyArrayDescr_Type;
- int npy_rational = PyArray_RegisterDataType(&npyrational_descr);
+ npy_rational = PyArray_RegisterDataType(&npyrational_descr);
if (npy_rational<0) {
goto fail;
}
@@ -1149,21 +1193,23 @@ PyMODINIT_FUNC inittest_rational(void) {
}
/* Register casts to and from rational */
- #define REGISTER_CAST(From,To,from_descr,to_typenum,safe) \
- PyArray_Descr* from_descr_##From##_##To = (from_descr); \
- if (PyArray_RegisterCastFunc(from_descr_##From##_##To, (to_typenum), \
- npycast_##From##_##To) < 0) { \
- goto fail; \
- } \
- if (safe && PyArray_RegisterCanCast(from_descr_##From##_##To, \
- (to_typenum), \
- NPY_NOSCALAR) < 0) { \
- goto fail; \
+ #define REGISTER_CAST(From,To,from_descr,to_typenum,safe) { \
+ PyArray_Descr* from_descr_##From##_##To = (from_descr); \
+ if (PyArray_RegisterCastFunc(from_descr_##From##_##To, \
+ (to_typenum), \
+ npycast_##From##_##To) < 0) { \
+ goto fail; \
+ } \
+ if (safe && PyArray_RegisterCanCast(from_descr_##From##_##To, \
+ (to_typenum), \
+ NPY_NOSCALAR) < 0) { \
+ goto fail; \
+ } \
}
#define REGISTER_INT_CASTS(bits) \
- REGISTER_CAST(int##bits##_t, rational, \
+ REGISTER_CAST(npy_int##bits, rational, \
PyArray_DescrFromType(NPY_INT##bits), npy_rational, 1) \
- REGISTER_CAST(rational, int##bits##_t, &npyrational_descr, \
+ REGISTER_CAST(rational, npy_int##bits, &npyrational_descr, \
NPY_INT##bits, 0)
REGISTER_INT_CASTS(8)
REGISTER_INT_CASTS(16)
@@ -1179,10 +1225,10 @@ PyMODINIT_FUNC inittest_rational(void) {
#define REGISTER_UFUNC(name,...) { \
PyUFuncObject* ufunc = \
(PyUFuncObject*)PyObject_GetAttrString(numpy, #name); \
+ int _types[] = __VA_ARGS__; \
if (!ufunc) { \
goto fail; \
} \
- int _types[] = __VA_ARGS__; \
if (sizeof(_types)/sizeof(int)!=ufunc->nargs) { \
PyErr_Format(PyExc_AssertionError, \
"ufunc %s takes %d arguments, our loop takes %ld", \
@@ -1244,42 +1290,64 @@ PyMODINIT_FUNC inittest_rational(void) {
PyModule_AddObject(m,"rational",(PyObject*)&PyRational_Type);
/* Create matrix multiply generalized ufunc */
- PyObject* gufunc = PyUFunc_FromFuncAndDataAndSignature(0,0,0,0,2,1,
- PyUFunc_None,(char*)"matrix_multiply",
- (char*)"return result of multiplying two matrices of rationals",
- 0,"(m,n),(n,p)->(m,p)");
- if (!gufunc) {
- goto fail;
- }
- int types2[3] = {npy_rational,npy_rational,npy_rational};
- if (PyUFunc_RegisterLoopForType((PyUFuncObject*)gufunc, npy_rational,
- rational_gufunc_matrix_multiply, types2, 0) < 0) {
- goto fail;
+ {
+ int types2[3] = {npy_rational,npy_rational,npy_rational};
+ PyObject* gufunc = PyUFunc_FromFuncAndDataAndSignature(0,0,0,0,2,1,
+ PyUFunc_None,(char*)"matrix_multiply",
+ (char*)"return result of multiplying two matrices of rationals",
+ 0,"(m,n),(n,p)->(m,p)");
+ if (!gufunc) {
+ goto fail;
+ }
+ if (PyUFunc_RegisterLoopForType((PyUFuncObject*)gufunc, npy_rational,
+ rational_gufunc_matrix_multiply, types2, 0) < 0) {
+ goto fail;
+ }
+ PyModule_AddObject(m,"matrix_multiply",(PyObject*)gufunc);
}
- PyModule_AddObject(m,"matrix_multiply",(PyObject*)gufunc);
/* Create test ufunc with built in input types and rational output type */
- PyObject* ufunc = PyUFunc_FromFuncAndData(0,0,0,0,2,1,
- PyUFunc_None,(char*)"test_add",
- (char*)"add two matrices of int64 and return rational matrix",0);
- if (!ufunc) {
- goto fail;
+ {
+ int types3[3] = {NPY_INT64,NPY_INT64,npy_rational};
+ PyObject* ufunc = PyUFunc_FromFuncAndData(0,0,0,0,2,1,
+ PyUFunc_None,(char*)"test_add",
+ (char*)"add two matrices of int64 and return rational matrix",0);
+ if (!ufunc) {
+ goto fail;
+ }
+ if (PyUFunc_RegisterLoopForType((PyUFuncObject*)ufunc, npy_rational,
+ rational_ufunc_test_add, types3, 0) < 0) {
+ goto fail;
+ }
+ PyModule_AddObject(m,"test_add",(PyObject*)ufunc);
}
- int types3[3] = {NPY_INT64,NPY_INT64,npy_rational};
- if (PyUFunc_RegisterLoopForType((PyUFuncObject*)ufunc, npy_rational,
- rational_ufunc_test_add, types3, 0) < 0) {
- goto fail;
+
+ /* Create test ufunc with rational types using RegisterLoopForDescr */
+ {
+ PyObject* ufunc = PyUFunc_FromFuncAndData(0,0,0,0,2,1,
+ PyUFunc_None,(char*)"test_add_rationals",
+ (char*)"add two matrices of rationals and return rational matrix",0);
+ if (!ufunc) {
+ goto fail;
+ }
+ PyArray_Descr* types[3] = {&npyrational_descr,
+ &npyrational_descr,
+ &npyrational_descr};
+ if (PyUFunc_RegisterLoopForDescr((PyUFuncObject*)ufunc, &npyrational_descr,
+ rational_ufunc_test_add_rationals, types, 0) < 0) {
+ goto fail;
+ }
+ PyModule_AddObject(m,"test_add_rationals",(PyObject*)ufunc);
}
- PyModule_AddObject(m,"test_add",(PyObject*)ufunc);
/* Create numerator and denominator ufuncs */
#define NEW_UNARY_UFUNC(name,type,doc) { \
+ int types[2] = {npy_rational,type}; \
PyObject* ufunc = PyUFunc_FromFuncAndData(0,0,0,0,1,1, \
PyUFunc_None,(char*)#name,(char*)doc,0); \
if (!ufunc) { \
goto fail; \
} \
- int types[2] = {npy_rational,type}; \
if (PyUFunc_RegisterLoopForType((PyUFuncObject*)ufunc, \
npy_rational,rational_ufunc_##name,types,0)<0) { \
goto fail; \
diff --git a/numpy/core/src/umath/ufunc_object.c b/numpy/core/src/umath/ufunc_object.c
index a3a164731..8a028096a 100644
--- a/numpy/core/src/umath/ufunc_object.c
+++ b/numpy/core/src/umath/ufunc_object.c
@@ -724,8 +724,9 @@ static int get_ufunc_arguments(PyUFuncObject *ufunc,
PyObject *obj, *context;
PyObject *str_key_obj = NULL;
char *ufunc_name;
+ int type_num;
- int any_flexible = 0, any_object = 0;
+ int any_flexible = 0, any_object = 0, any_flexible_userloops = 0;
ufunc_name = ufunc->name ? ufunc->name : "<unnamed ufunc>";
@@ -764,23 +765,55 @@ static int get_ufunc_arguments(PyUFuncObject *ufunc,
if (out_op[i] == NULL) {
return -1;
}
+
+ type_num = PyArray_DESCR(out_op[i])->type_num;
if (!any_flexible &&
- PyTypeNum_ISFLEXIBLE(PyArray_DESCR(out_op[i])->type_num)) {
+ PyTypeNum_ISFLEXIBLE(type_num)) {
any_flexible = 1;
}
if (!any_object &&
- PyTypeNum_ISOBJECT(PyArray_DESCR(out_op[i])->type_num)) {
+ PyTypeNum_ISOBJECT(type_num)) {
any_object = 1;
}
+
+ /*
+ * If any operand is a flexible dtype, check to see if any
+ * struct dtype ufuncs are registered. A ufunc has been registered
+ * for a struct dtype if ufunc's arg_dtypes array is not NULL.
+ */
+ if (PyTypeNum_ISFLEXIBLE(type_num) &&
+ !any_flexible_userloops &&
+ ufunc->userloops != NULL) {
+ PyUFunc_Loop1d *funcdata;
+ PyObject *key, *obj;
+ key = PyInt_FromLong(type_num);
+ if (key == NULL) {
+ continue;
+ }
+ obj = PyDict_GetItem(ufunc->userloops, key);
+ Py_DECREF(key);
+ if (obj == NULL) {
+ continue;
+ }
+ funcdata = (PyUFunc_Loop1d *)NpyCapsule_AsVoidPtr(obj);
+ while (funcdata != NULL) {
+ if (funcdata->arg_dtypes != NULL) {
+ any_flexible_userloops = 1;
+ break;
+ }
+ funcdata = funcdata->next;
+ }
+ }
}
/*
* Indicate not implemented if there are flexible objects (structured
- * type or string) but no object types.
+ * type or string) but no object types and no registered struct
+ * dtype ufuncs.
*
* Not sure - adding this increased to 246 errors, 150 failures.
*/
- if (any_flexible && !any_object) {
+ if (any_flexible && !any_flexible_userloops && !any_object) {
return -2;
}
@@ -4356,9 +4389,19 @@ cmp_arg_types(int *arg1, int *arg2, int n)
static NPY_INLINE void
_free_loop1d_list(PyUFunc_Loop1d *data)
{
+ int i;
+
while (data != NULL) {
PyUFunc_Loop1d *next = data->next;
PyArray_free(data->arg_types);
+
+ if (data->arg_dtypes != NULL) {
+ for (i = 0; i < data->nargs; i++) {
+ Py_DECREF(data->arg_dtypes[i]);
+ }
+ PyArray_free(data->arg_dtypes);
+ }
+
PyArray_free(data);
data = next;
}
@@ -4381,6 +4424,112 @@ _loop1d_list_free(void *ptr)
#endif
+/*
+ * This function allows the user to register a 1-d loop with an already
+ * created ufunc. This function is similar to RegisterLoopForType except
+ * that it allows a 1-d loop to be registered with PyArray_Descr objects
+ * instead of dtype type num values. This allows a 1-d loop to be registered
+ * for a structured array dtype or a custom dtype. The ufunc is called
+ * whenever any of it's input arguments match the user_dtype argument.
+ * ufunc - ufunc object created from call to PyUFunc_FromFuncAndData
+ * user_dtype - dtype that ufunc will be registered with
+ * function - 1-d loop function pointer
+ * arg_dtypes - array of dtype objects describing the ufunc operands
+ * data - arbitrary data pointer passed in to loop function
+ */
+/*UFUNC_API*/
+NPY_NO_EXPORT int
+PyUFunc_RegisterLoopForDescr(PyUFuncObject *ufunc,
+ PyArray_Descr *user_dtype,
+ PyUFuncGenericFunction function,
+ PyArray_Descr **arg_dtypes,
+ void *data)
+{
+ int i;
+ int result = 0;
+ int *arg_typenums;
+ PyObject *key, *cobj;
+
+ if (user_dtype == NULL) {
+ PyErr_SetString(PyExc_TypeError,
+ "unknown user defined struct dtype");
+ return -1;
+ }
+
+ key = PyInt_FromLong((long) user_dtype->type_num);
+ if (key == NULL) {
+ return -1;
+ }
+
+ arg_typenums = PyArray_malloc(ufunc->nargs * sizeof(int));
+ if (arg_typenums == NULL) {
+ PyErr_NoMemory();
+ return -1;
+ }
+ if (arg_dtypes != NULL) {
+ for (i = 0; i < ufunc->nargs; i++) {
+ arg_typenums[i] = arg_dtypes[i]->type_num;
+ }
+ }
+ else {
+ for (i = 0; i < ufunc->nargs; i++) {
+ arg_typenums[i] = user_dtype->type_num;
+ }
+ }
+
+ result = PyUFunc_RegisterLoopForType(ufunc, user_dtype->type_num,
+ function, arg_typenums, data);
+
+ if (result == 0) {
+ cobj = PyDict_GetItem(ufunc->userloops, key);
+ if (cobj == NULL) {
+ PyErr_SetString(PyExc_KeyError,
+ "userloop for user dtype not found");
+ result = -1;
+ }
+ else {
+ PyUFunc_Loop1d *current, *prev = NULL;
+ int cmp = 1;
+ current = (PyUFunc_Loop1d *)NpyCapsule_AsVoidPtr(cobj);
+ while (current != NULL) {
+ cmp = cmp_arg_types(current->arg_types,
+ arg_typenums, ufunc->nargs);
+ if (cmp >= 0 && current->arg_dtypes == NULL) {
+ break;
+ }
+ prev = current;
+ current = current->next;
+ }
+ if (cmp == 0 && current->arg_dtypes == NULL) {
+ current->arg_dtypes = PyArray_malloc(ufunc->nargs *
+ sizeof(PyArray_Descr*));
+ if (arg_dtypes != NULL) {
+ for (i = 0; i < ufunc->nargs; i++) {
+ current->arg_dtypes[i] = arg_dtypes[i];
+ Py_INCREF(current->arg_dtypes[i]);
+ }
+ }
+ else {
+ for (i = 0; i < ufunc->nargs; i++) {
+ current->arg_dtypes[i] = user_dtype;
+ Py_INCREF(current->arg_dtypes[i]);
+ }
+ }
+ current->nargs = ufunc->nargs;
+ }
+ else {
+ result = -1;
+ }
+ }
+ }
+
+ PyArray_free(arg_typenums);
+
+ Py_DECREF(key);
+
+ return result;
+}
+
/*UFUNC_API*/
NPY_NO_EXPORT int
PyUFunc_RegisterLoopForType(PyUFuncObject *ufunc,
@@ -4396,7 +4545,7 @@ PyUFunc_RegisterLoopForType(PyUFuncObject *ufunc,
int *newtypes=NULL;
descr=PyArray_DescrFromType(usertype);
- if ((usertype < NPY_USERDEF) || (descr==NULL)) {
+ if ((usertype < NPY_USERDEF && usertype != NPY_VOID) || (descr==NULL)) {
PyErr_SetString(PyExc_TypeError, "unknown user-defined type");
return -1;
}
@@ -4432,6 +4581,8 @@ PyUFunc_RegisterLoopForType(PyUFuncObject *ufunc,
funcdata->arg_types = newtypes;
funcdata->data = data;
funcdata->next = NULL;
+ funcdata->arg_dtypes = NULL;
+ funcdata->nargs = 0;
/* Get entry for this user-defined type*/
cobj = PyDict_GetItem(ufunc->userloops, key);
diff --git a/numpy/core/src/umath/ufunc_type_resolution.c b/numpy/core/src/umath/ufunc_type_resolution.c
index 8344d73e5..6a16692b0 100644
--- a/numpy/core/src/umath/ufunc_type_resolution.c
+++ b/numpy/core/src/umath/ufunc_type_resolution.c
@@ -1180,14 +1180,16 @@ find_userloop(PyUFuncObject *ufunc,
int last_userdef = -1;
for (i = 0; i < nargs; ++i) {
+ int type_num;
/* no more ufunc arguments to check */
if (dtypes[i] == NULL) {
break;
}
- int type_num = dtypes[i]->type_num;
- if (type_num != last_userdef && PyTypeNum_ISUSERDEF(type_num)) {
+ type_num = dtypes[i]->type_num;
+ if (type_num != last_userdef &&
+ (PyTypeNum_ISUSERDEF(type_num) || type_num == NPY_VOID)) {
PyObject *key, *obj;
last_userdef = type_num;
@@ -1435,7 +1437,7 @@ ufunc_loop_matches(PyUFuncObject *self,
NPY_CASTING output_casting,
int any_object,
int use_min_scalar,
- int *types,
+ int *types, PyArray_Descr **dtypes,
int *out_no_castable_output,
char *out_err_src_typecode,
char *out_err_dst_typecode)
@@ -1462,7 +1464,18 @@ ufunc_loop_matches(PyUFuncObject *self,
return 0;
}
- tmp = PyArray_DescrFromType(types[i]);
+ /*
+ * If type num is NPY_VOID and struct dtypes have been passed in,
+ * use struct dtype object. Otherwise create new dtype object
+ * from type num.
+ */
+ if (types[i] == NPY_VOID && dtypes != NULL) {
+ tmp = dtypes[i];
+ Py_INCREF(tmp);
+ }
+ else {
+ tmp = PyArray_DescrFromType(types[i]);
+ }
if (tmp == NULL) {
return -1;
}
@@ -1524,7 +1537,7 @@ ufunc_loop_matches(PyUFuncObject *self,
static int
set_ufunc_loop_data_types(PyUFuncObject *self, PyArrayObject **op,
PyArray_Descr **out_dtypes,
- int *type_nums)
+ int *type_nums, PyArray_Descr **dtypes)
{
int i, nin = self->nin, nop = nin + self->nout;
@@ -1535,11 +1548,16 @@ set_ufunc_loop_data_types(PyUFuncObject *self, PyArrayObject **op,
* instead of creating a new one, similarly to preserve metadata.
**/
for (i = 0; i < nop; ++i) {
+ if (dtypes != NULL) {
+ out_dtypes[i] = dtypes[i];
+ Py_XINCREF(out_dtypes[i]);
/*
* Copy the dtype from 'op' if the type_num matches,
* to preserve metadata.
*/
- if (op[i] != NULL && PyArray_DESCR(op[i])->type_num == type_nums[i]) {
+ }
+ else if (op[i] != NULL &&
+ PyArray_DESCR(op[i])->type_num == type_nums[i]) {
out_dtypes[i] = ensure_dtype_nbo(PyArray_DESCR(op[i]));
Py_XINCREF(out_dtypes[i]);
}
@@ -1594,14 +1612,16 @@ linear_search_userloop_type_resolver(PyUFuncObject *self,
int last_userdef = -1;
for (i = 0; i < nop; ++i) {
+ int type_num;
/* no more ufunc arguments to check */
if (op[i] == NULL) {
break;
}
- int type_num = PyArray_DESCR(op[i])->type_num;
- if (type_num != last_userdef && PyTypeNum_ISUSERDEF(type_num)) {
+ type_num = PyArray_DESCR(op[i])->type_num;
+ if (type_num != last_userdef &&
+ (PyTypeNum_ISUSERDEF(type_num) || type_num == NPY_VOID)) {
PyObject *key, *obj;
last_userdef = type_num;
@@ -1621,7 +1641,7 @@ linear_search_userloop_type_resolver(PyUFuncObject *self,
switch (ufunc_loop_matches(self, op,
input_casting, output_casting,
any_object, use_min_scalar,
- types,
+ types, funcdata->arg_dtypes,
out_no_castable_output, out_err_src_typecode,
out_err_dst_typecode)) {
/* Error */
@@ -1629,7 +1649,7 @@ linear_search_userloop_type_resolver(PyUFuncObject *self,
return -1;
/* Found a match */
case 1:
- set_ufunc_loop_data_types(self, op, out_dtype, types);
+ set_ufunc_loop_data_types(self, op, out_dtype, types, funcdata->arg_dtypes);
return 1;
}
@@ -1705,12 +1725,13 @@ type_tuple_userloop_type_resolver(PyUFuncObject *self,
switch (ufunc_loop_matches(self, op,
casting, casting,
any_object, use_min_scalar,
- types,
+ types, NULL,
&no_castable_output, &err_src_typecode,
&err_dst_typecode)) {
/* It works */
case 1:
- set_ufunc_loop_data_types(self, op, out_dtype, types);
+ set_ufunc_loop_data_types(self, op,
+ out_dtype, types, NULL);
return 1;
/* Didn't match */
case 0:
@@ -1873,7 +1894,7 @@ linear_search_type_resolver(PyUFuncObject *self,
switch (ufunc_loop_matches(self, op,
input_casting, output_casting,
any_object, use_min_scalar,
- types,
+ types, NULL,
&no_castable_output, &err_src_typecode,
&err_dst_typecode)) {
/* Error */
@@ -1881,7 +1902,7 @@ linear_search_type_resolver(PyUFuncObject *self,
return -1;
/* Found a match */
case 1:
- set_ufunc_loop_data_types(self, op, out_dtype, types);
+ set_ufunc_loop_data_types(self, op, out_dtype, types, NULL);
return 0;
}
}
@@ -2079,7 +2100,7 @@ type_tuple_type_resolver(PyUFuncObject *self,
switch (ufunc_loop_matches(self, op,
casting, casting,
any_object, use_min_scalar,
- types,
+ types, NULL,
&no_castable_output, &err_src_typecode,
&err_dst_typecode)) {
/* Error */
@@ -2087,7 +2108,7 @@ type_tuple_type_resolver(PyUFuncObject *self,
return -1;
/* It worked */
case 1:
- set_ufunc_loop_data_types(self, op, out_dtype, types);
+ set_ufunc_loop_data_types(self, op, out_dtype, types, NULL);
return 0;
/* Didn't work */
case 0:
diff --git a/numpy/core/tests/test_numeric.py b/numpy/core/tests/test_numeric.py
index 3a6118f06..5c8de3734 100644
--- a/numpy/core/tests/test_numeric.py
+++ b/numpy/core/tests/test_numeric.py
@@ -656,6 +656,12 @@ class TestArrayComparisons(TestCase):
res = array_equal(array([1,2]), array([1,3]))
assert_(not res)
assert_(type(res) is bool)
+ res = array_equal(array(['a'], dtype='S1'), array(['a'], dtype='S1'))
+ assert_(res)
+ assert_(type(res) is bool)
+ res = array_equal(array([('a',1)], dtype='S1,u4'), array([('a',1)], dtype='S1,u4'))
+ assert_(res)
+ assert_(type(res) is bool)
def test_array_equiv(self):
res = array_equiv(array([1,2]), array([1,2]))
diff --git a/numpy/core/tests/test_ufunc.py b/numpy/core/tests/test_ufunc.py
index 3005da8da..ad489124e 100644
--- a/numpy/core/tests/test_ufunc.py
+++ b/numpy/core/tests/test_ufunc.py
@@ -813,6 +813,26 @@ class TestUfunc(TestCase):
assert_equal(a, 3)
opflag_tests.inplace_add(a, [3, 4])
assert_equal(a, 10)
+
+ def test_struct_ufunc(self):
+ import numpy.core.struct_ufunc_test as struct_ufunc
+
+ a = np.array([(1,2,3)], dtype='u8,u8,u8')
+ b = np.array([(1,2,3)], dtype='u8,u8,u8')
+
+ result = struct_ufunc.add_triplet(a, b)
+ assert_equal(result, np.array([(2, 4, 6)], dtype='u8,u8,u8'))
+
+ def test_custom_ufunc(self):
+ a = np.array([rational(1,2), rational(1,3), rational(1,4)],
+ dtype=rational);
+ b = np.array([rational(1,2), rational(1,3), rational(1,4)],
+ dtype=rational);
+
+ result = test_add_rationals(a, b)
+ expected = np.array([rational(1), rational(2,3), rational(1,2)],
+ dtype=rational);
+ assert_equal(result, expected);
if __name__ == "__main__":
run_module_suite()
diff --git a/numpy/distutils/misc_util.py b/numpy/distutils/misc_util.py
index 5bd3a9086..38690aec3 100644
--- a/numpy/distutils/misc_util.py
+++ b/numpy/distutils/misc_util.py
@@ -671,7 +671,7 @@ class Configuration(object):
_list_keys = ['packages', 'ext_modules', 'data_files', 'include_dirs',
'libraries', 'headers', 'scripts', 'py_modules',
- 'installed_libraries']
+ 'installed_libraries', 'define_macros']
_dict_keys = ['package_dir', 'installed_pkg_config']
_extra_keys = ['name', 'version']
@@ -1273,6 +1273,22 @@ class Configuration(object):
### XXX Implement add_py_modules
+ def add_define_macros(self, macros):
+ """Add define macros to configuration
+
+ Add the given sequence of macro name and value duples to the beginning
+ of the define_macros list This list will be visible to all extension
+ modules of the current package.
+ """
+ dist = self.get_distribution()
+ if dist is not None:
+ if not hasattr(dist, 'define_macros'):
+ dist.define_macros = []
+ dist.define_macros.extend(macros)
+ else:
+ self.define_macros.extend(macros)
+
+
def add_include_dirs(self,*paths):
"""Add paths to configuration include directories.
@@ -1440,6 +1456,8 @@ class Configuration(object):
libnames.append(libname)
ext_args['libraries'] = libnames + ext_args['libraries']
+ ext_args['define_macros'] = \
+ self.define_macros + ext_args.get('define_macros', [])
from numpy.distutils.core import Extension
ext = Extension(**ext_args)
diff --git a/numpy/linalg/umath_linalg.c.src b/numpy/linalg/umath_linalg.c.src
index eadbde8e7..796f76778 100644
--- a/numpy/linalg/umath_linalg.c.src
+++ b/numpy/linalg/umath_linalg.c.src
@@ -1196,11 +1196,11 @@ init_gemm_params(GEMM_PARAMS_t *params,
npy_intp* steps,
size_t sot)
{
+ npy_uint8 *mem_buff = NULL;
matrix_desc a, b, c;
matrix_desc_init(&a, steps + 0, sot, m, k);
matrix_desc_init(&b, steps + 2, sot, k, n);
matrix_desc_init(&c, steps + 4, sot, m, n);
- npy_uint8 *mem_buff = NULL;
if (a.size + b.size + c.size)
{
@@ -3029,7 +3029,7 @@ static inline void
npy_intp* dimensions,
npy_intp* steps)
{
- ptrdiff_t outer_steps[3];
+ ptrdiff_t outer_steps[4];
int error_occurred = get_fp_invalid_and_clear();
size_t iter;
size_t outer_dim = *dimensions++;