diff options
Diffstat (limited to 'numpy')
-rw-r--r-- | numpy/core/code_generators/numpy_api.py | 1 | ||||
-rw-r--r-- | numpy/core/include/numpy/npy_math.h | 53 | ||||
-rw-r--r-- | numpy/core/include/numpy/ufuncobject.h | 2 | ||||
-rw-r--r-- | numpy/core/numeric.py | 4 | ||||
-rw-r--r-- | numpy/core/setup.py | 13 | ||||
-rw-r--r-- | numpy/core/setup_common.py | 9 | ||||
-rw-r--r-- | numpy/core/src/multiarray/ctors.c | 27 | ||||
-rw-r--r-- | numpy/core/src/umath/operand_flag_tests.c.src | 1 | ||||
-rw-r--r-- | numpy/core/src/umath/struct_ufunc_test.c.src | 122 | ||||
-rw-r--r-- | numpy/core/src/umath/test_rational.c.src | 358 | ||||
-rw-r--r-- | numpy/core/src/umath/ufunc_object.c | 163 | ||||
-rw-r--r-- | numpy/core/src/umath/ufunc_type_resolution.c | 53 | ||||
-rw-r--r-- | numpy/core/tests/test_numeric.py | 6 | ||||
-rw-r--r-- | numpy/core/tests/test_ufunc.py | 20 | ||||
-rw-r--r-- | numpy/distutils/misc_util.py | 20 | ||||
-rw-r--r-- | numpy/linalg/umath_linalg.c.src | 4 |
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++; |