diff options
-rw-r--r-- | numpy/core/code_generators/generate_umath.py | 36 | ||||
-rw-r--r-- | numpy/core/code_generators/ufunc_docstrings.py | 6 | ||||
-rw-r--r-- | numpy/core/include/numpy/npy_math.h | 10 | ||||
-rw-r--r-- | numpy/core/setup.py | 5 | ||||
-rw-r--r-- | numpy/core/src/multiarray/multiarray_tests.c.src | 42 | ||||
-rw-r--r-- | numpy/core/src/npymath/npy_math.c.src | 35 | ||||
-rw-r--r-- | numpy/core/src/umath/loops.c.src | 28 | ||||
-rw-r--r-- | numpy/core/src/umath/loops.h.src | 4 | ||||
-rw-r--r-- | numpy/core/src/umath/simd.inc.src | 4 | ||||
-rw-r--r-- | numpy/core/src/umath/umathmodule.c | 183 | ||||
-rw-r--r-- | numpy/core/tests/test_multiarray.py | 60 | ||||
-rw-r--r-- | numpy/core/tests/test_scalarmath.py | 12 | ||||
-rw-r--r-- | numpy/core/tests/test_umath.py | 18 | ||||
-rw-r--r-- | numpy/distutils/command/autodist.py | 34 | ||||
-rw-r--r-- | numpy/distutils/command/config.py | 11 | ||||
-rw-r--r-- | numpy/lib/tests/test_twodim_base.py | 12 | ||||
-rw-r--r-- | numpy/lib/twodim_base.py | 9 |
17 files changed, 290 insertions, 219 deletions
diff --git a/numpy/core/code_generators/generate_umath.py b/numpy/core/code_generators/generate_umath.py index e3c9cf28b..9f8d4c688 100644 --- a/numpy/core/code_generators/generate_umath.py +++ b/numpy/core/code_generators/generate_umath.py @@ -20,6 +20,12 @@ ReorderableNone = "PyUFunc_ReorderableNone" class FullTypeDescr(object): pass +class FuncNameSuffix(object): + """Stores the suffix to append when generating functions names. + """ + def __init__(self, suffix): + self.suffix = suffix + class TypeDescription(object): """Type signature for a ufunc. @@ -795,6 +801,30 @@ defdict = { None, TD(flts), ), +'ldexp' : + Ufunc(2, 1, None, + docstrings.get('numpy.core.umath.ldexp'), + None, + [TypeDescription('e', None, 'ei', 'e'), + TypeDescription('f', None, 'fi', 'f'), + TypeDescription('e', FuncNameSuffix('long'), 'el', 'e'), + TypeDescription('f', FuncNameSuffix('long'), 'fl', 'f'), + TypeDescription('d', None, 'di', 'd'), + TypeDescription('d', FuncNameSuffix('long'), 'dl', 'd'), + TypeDescription('g', None, 'gi', 'g'), + TypeDescription('g', FuncNameSuffix('long'), 'gl', 'g'), + ], + ), +'frexp' : + Ufunc(1, 2, None, + docstrings.get('numpy.core.umath.frexp'), + None, + [TypeDescription('e', None, 'e', 'ei'), + TypeDescription('f', None, 'f', 'fi'), + TypeDescription('d', None, 'd', 'di'), + TypeDescription('g', None, 'g', 'gi'), + ], + ) } if sys.version_info[0] >= 3: @@ -854,7 +884,7 @@ def make_arrays(funcdict): thedict = chartotype1 # one input and one output for t in uf.type_descriptions: - if t.func_data not in (None, FullTypeDescr): + if t.func_data not in (None, FullTypeDescr) and not isinstance(t.func_data, FuncNameSuffix): funclist.append('NULL') astype = '' if not t.astype is None: @@ -880,6 +910,10 @@ def make_arrays(funcdict): tname = english_upper(chartoname[t.type]) datalist.append('(void *)NULL') funclist.append('%s_%s_%s_%s' % (tname, t.in_, t.out, name)) + elif isinstance(t.func_data, FuncNameSuffix): + datalist.append('(void *)NULL') + tname = english_upper(chartoname[t.type]) + funclist.append('%s_%s_%s' % (tname, name, t.func_data.suffix)) else: datalist.append('(void *)NULL') tname = english_upper(chartoname[t.type]) diff --git a/numpy/core/code_generators/ufunc_docstrings.py b/numpy/core/code_generators/ufunc_docstrings.py index 4d302969e..804108397 100644 --- a/numpy/core/code_generators/ufunc_docstrings.py +++ b/numpy/core/code_generators/ufunc_docstrings.py @@ -3324,9 +3324,6 @@ add_newdoc('numpy.core.umath', 'true_divide', """) -# This doc is not currently used, but has been converted to a C string -# that can be found in numpy/core/src/umath/umathmodule.c where the -# frexp ufunc is constructed. add_newdoc('numpy.core.umath', 'frexp', """ Decompose the elements of x into mantissa and twos exponent. @@ -3372,9 +3369,6 @@ add_newdoc('numpy.core.umath', 'frexp', """) -# This doc is not currently used, but has been converted to a C string -# that can be found in numpy/core/src/umath/umathmodule.c where the -# ldexp ufunc is constructed. add_newdoc('numpy.core.umath', 'ldexp', """ Returns x1 * 2**x2, element-wise. diff --git a/numpy/core/include/numpy/npy_math.h b/numpy/core/include/numpy/npy_math.h index b7920460d..855ddf7fa 100644 --- a/numpy/core/include/numpy/npy_math.h +++ b/numpy/core/include/numpy/npy_math.h @@ -118,10 +118,6 @@ double npy_tanh(double x); double npy_asin(double x); double npy_acos(double x); double npy_atan(double x); -double npy_aexp(double x); -double npy_alog(double x); -double npy_asqrt(double x); -double npy_afabs(double x); double npy_log(double x); double npy_log10(double x); @@ -147,6 +143,8 @@ double npy_log2(double x); double npy_atan2(double x, double y); double npy_pow(double x, double y); double npy_modf(double x, double* y); +double npy_frexp(double x, int* y); +double npy_ldexp(double n, int y); double npy_copysign(double x, double y); double npy_nextafter(double x, double y); @@ -251,6 +249,8 @@ float npy_powf(float x, float y); float npy_fmodf(float x, float y); float npy_modff(float x, float* y); +float npy_frexpf(float x, int* y); +float npy_ldexpf(float x, int y); float npy_copysignf(float x, float y); float npy_nextafterf(float x, float y); @@ -292,6 +292,8 @@ npy_longdouble npy_powl(npy_longdouble x, npy_longdouble y); npy_longdouble npy_fmodl(npy_longdouble x, npy_longdouble y); npy_longdouble npy_modfl(npy_longdouble x, npy_longdouble* y); +npy_longdouble npy_frexpl(npy_longdouble x, int* y); +npy_longdouble npy_ldexpl(npy_longdouble x, int y); npy_longdouble npy_copysignl(npy_longdouble x, npy_longdouble y); npy_longdouble npy_nextafterl(npy_longdouble x, npy_longdouble y); diff --git a/numpy/core/setup.py b/numpy/core/setup.py index dcad0d914..15f66fa6c 100644 --- a/numpy/core/setup.py +++ b/numpy/core/setup.py @@ -176,12 +176,11 @@ def check_math_capabilities(config, moredefs, mathlibs): moredefs.append((fname2def(f), 1)) for dec, fn in OPTIONAL_FUNCTION_ATTRIBUTES: - if config.check_func(fn, decl='int %s %s(void *);' % (dec, fn), - call=False): + if config.check_gcc_function_attribute(dec, fn): moredefs.append((fname2def(fn), 1)) for fn in OPTIONAL_VARIABLE_ATTRIBUTES: - if config.check_func(fn, decl='int %s a;' % (fn), call=False): + if config.check_gcc_variable_attribute(fn): m = fn.replace("(", "_").replace(")", "_") moredefs.append((fname2def(m), 1)) diff --git a/numpy/core/src/multiarray/multiarray_tests.c.src b/numpy/core/src/multiarray/multiarray_tests.c.src index bd0366bd5..a22319cfe 100644 --- a/numpy/core/src/multiarray/multiarray_tests.c.src +++ b/numpy/core/src/multiarray/multiarray_tests.c.src @@ -556,6 +556,42 @@ fail: return NULL; } +/* check no elison for avoided increfs */ +static PyObject * +incref_elide(PyObject *dummy, PyObject *args) +{ + PyObject *arg = NULL, *res, *tup; + if (!PyArg_ParseTuple(args, "O", &arg)) { + return NULL; + } + + /* refcount 1 array but should not be elided */ + arg = PyArray_NewCopy((PyArrayObject*)arg, NPY_KEEPORDER); + res = PyNumber_Add(arg, arg); + + /* return original copy, should be equal to input */ + tup = PyTuple_Pack(2, arg, res); + Py_DECREF(arg); + Py_DECREF(res); + return tup; +} + +/* check no elison for get from list without incref */ +static PyObject * +incref_elide_l(PyObject *dummy, PyObject *args) +{ + PyObject *arg = NULL, *r, *res; + if (!PyArg_ParseTuple(args, "O", &arg)) { + return NULL; + } + /* get item without increasing refcount, item may still be on the python + * stack but above the inaccessible top */ + r = PyList_GetItem(arg, 4); + res = PyNumber_Add(r, r); + + return res; +} + #if !defined(NPY_PY3K) static PyObject * @@ -839,6 +875,12 @@ static PyMethodDef Multiarray_TestsMethods[] = { {"test_inplace_increment", inplace_increment, METH_VARARGS, NULL}, + {"incref_elide", + incref_elide, + METH_VARARGS, NULL}, + {"incref_elide_l", + incref_elide_l, + METH_VARARGS, NULL}, #if !defined(NPY_PY3K) {"test_int_subclass", int_subclass, diff --git a/numpy/core/src/npymath/npy_math.c.src b/numpy/core/src/npymath/npy_math.c.src index 05af0b132..3a1be3745 100644 --- a/numpy/core/src/npymath/npy_math.c.src +++ b/numpy/core/src/npymath/npy_math.c.src @@ -343,6 +343,7 @@ double npy_log2(double x) * asinh, acosh, atanh * * hypot, atan2, pow, fmod, modf + * ldexp, frexp * * We assume the above are always available in their double versions. * @@ -405,6 +406,26 @@ double npy_log2(double x) } #endif +#ifdef ldexp@c@ +#undef ldexp@c@ +#endif +#ifndef HAVE_LDEXP@C@ +@type@ npy_ldexp@c@(@type@ x, int exp) +{ + return (@type@) npy_ldexp((double)x, exp); +} +#endif + +#ifdef frexp@c@ +#undef frexp@c@ +#endif +#ifndef HAVE_FREXP@C@ +@type@ npy_frexp@c@(@type@ x, int* exp) +{ + return (@type@) npy_frexp(x, exp); +} +#endif + /**end repeat**/ @@ -451,6 +472,20 @@ double npy_log2(double x) } #endif +#ifdef HAVE_LDEXP@C@ +@type@ npy_ldexp@c@(@type@ x, int exp) +{ + return ldexp@c@(x, exp); +} +#endif + +#ifdef HAVE_FREXP@C@ +@type@ npy_frexp@c@(@type@ x, int* exp) +{ + return frexp@c@(x, exp); +} +#endif + /**end repeat**/ diff --git a/numpy/core/src/umath/loops.c.src b/numpy/core/src/umath/loops.c.src index 035a27fd2..d747864f8 100644 --- a/numpy/core/src/umath/loops.c.src +++ b/numpy/core/src/umath/loops.c.src @@ -1743,25 +1743,22 @@ NPY_NO_EXPORT void } } -#ifdef HAVE_FREXP@C@ NPY_NO_EXPORT void @TYPE@_frexp(char **args, npy_intp *dimensions, npy_intp *steps, void *NPY_UNUSED(func)) { UNARY_LOOP_TWO_OUT { const @type@ in1 = *(@type@ *)ip1; - *((@type@ *)op1) = frexp@c@(in1, (int *)op2); + *((@type@ *)op1) = npy_frexp@c@(in1, (int *)op2); } } -#endif -#ifdef HAVE_LDEXP@C@ NPY_NO_EXPORT void @TYPE@_ldexp(char **args, npy_intp *dimensions, npy_intp *steps, void *NPY_UNUSED(func)) { BINARY_LOOP { const @type@ in1 = *(@type@ *)ip1; const int in2 = *(int *)ip2; - *((@type@ *)op1) = ldexp@c@(in1, in2); + *((@type@ *)op1) = npy_ldexp@c@(in1, in2); } } @@ -1778,7 +1775,7 @@ NPY_NO_EXPORT void const long in2 = *(long *)ip2; if (((int)in2) == in2) { /* Range OK */ - *((@type@ *)op1) = ldexp@c@(in1, ((int)in2)); + *((@type@ *)op1) = npy_ldexp@c@(in1, ((int)in2)); } else { /* @@ -1786,15 +1783,14 @@ NPY_NO_EXPORT void * given that exponent has less bits than npy_int. */ if (in2 > 0) { - *((@type@ *)op1) = ldexp@c@(in1, NPY_MAX_INT); + *((@type@ *)op1) = npy_ldexp@c@(in1, NPY_MAX_INT); } else { - *((@type@ *)op1) = ldexp@c@(in1, NPY_MIN_INT); + *((@type@ *)op1) = npy_ldexp@c@(in1, NPY_MIN_INT); } } } } -#endif #define @TYPE@_true_divide @TYPE@_divide @@ -2059,25 +2055,22 @@ HALF_modf(char **args, npy_intp *dimensions, npy_intp *steps, void *NPY_UNUSED(f } } -#ifdef HAVE_FREXPF NPY_NO_EXPORT void HALF_frexp(char **args, npy_intp *dimensions, npy_intp *steps, void *NPY_UNUSED(func)) { UNARY_LOOP_TWO_OUT { const float in1 = npy_half_to_float(*(npy_half *)ip1); - *((npy_half *)op1) = npy_float_to_half(frexpf(in1, (int *)op2)); + *((npy_half *)op1) = npy_float_to_half(npy_frexpf(in1, (int *)op2)); } } -#endif -#ifdef HAVE_LDEXPF NPY_NO_EXPORT void HALF_ldexp(char **args, npy_intp *dimensions, npy_intp *steps, void *NPY_UNUSED(func)) { BINARY_LOOP { const float in1 = npy_half_to_float(*(npy_half *)ip1); const int in2 = *(int *)ip2; - *((npy_half *)op1) = npy_float_to_half(ldexpf(in1, in2)); + *((npy_half *)op1) = npy_float_to_half(npy_ldexpf(in1, in2)); } } @@ -2094,7 +2087,7 @@ HALF_ldexp_long(char **args, npy_intp *dimensions, npy_intp *steps, void *NPY_UN const long in2 = *(long *)ip2; if (((int)in2) == in2) { /* Range OK */ - *((npy_half *)op1) = npy_float_to_half(ldexpf(in1, ((int)in2))); + *((npy_half *)op1) = npy_float_to_half(npy_ldexpf(in1, ((int)in2))); } else { /* @@ -2102,15 +2095,14 @@ HALF_ldexp_long(char **args, npy_intp *dimensions, npy_intp *steps, void *NPY_UN * given that exponent has less bits than npy_int. */ if (in2 > 0) { - *((npy_half *)op1) = npy_float_to_half(ldexpf(in1, NPY_MAX_INT)); + *((npy_half *)op1) = npy_float_to_half(npy_ldexpf(in1, NPY_MAX_INT)); } else { - *((npy_half *)op1) = npy_float_to_half(ldexpf(in1, NPY_MIN_INT)); + *((npy_half *)op1) = npy_float_to_half(npy_ldexpf(in1, NPY_MIN_INT)); } } } } -#endif #define HALF_true_divide HALF_divide diff --git a/numpy/core/src/umath/loops.h.src b/numpy/core/src/umath/loops.h.src index fdc9230de..a6e775a3a 100644 --- a/numpy/core/src/umath/loops.h.src +++ b/numpy/core/src/umath/loops.h.src @@ -248,17 +248,13 @@ NPY_NO_EXPORT void NPY_NO_EXPORT void @TYPE@_modf(char **args, npy_intp *dimensions, npy_intp *steps, void *NPY_UNUSED(func)); -#ifdef HAVE_FREXP@C@ NPY_NO_EXPORT void @TYPE@_frexp(char **args, npy_intp *dimensions, npy_intp *steps, void *NPY_UNUSED(func)); -#endif -#ifdef HAVE_LDEXP@C@ NPY_NO_EXPORT void @TYPE@_ldexp(char **args, npy_intp *dimensions, npy_intp *steps, void *NPY_UNUSED(func)); NPY_NO_EXPORT void @TYPE@_ldexp_long(char **args, npy_intp *dimensions, npy_intp *steps, void *NPY_UNUSED(func)); -#endif #define @TYPE@_true_divide @TYPE@_divide diff --git a/numpy/core/src/umath/simd.inc.src b/numpy/core/src/umath/simd.inc.src index 7944d5f47..5b111eb0d 100644 --- a/numpy/core/src/umath/simd.inc.src +++ b/numpy/core/src/umath/simd.inc.src @@ -37,7 +37,9 @@ ((abs(args[1] - args[0]) >= (vsize)) || ((abs(args[1] - args[0]) == 0)))) #define IS_BLOCKABLE_REDUCE(esize, vsize) \ - (steps[1] == (esize) && abs(args[1] - args[0]) >= (vsize)) + (steps[1] == (esize) && abs(args[1] - args[0]) >= (vsize) && \ + npy_is_aligned(args[1], (esize)) && \ + npy_is_aligned(args[0], (esize))) #define IS_BLOCKABLE_BINARY(esize, vsize) \ (steps[0] == steps[1] && steps[1] == steps[2] && steps[2] == (esize) && \ diff --git a/numpy/core/src/umath/umathmodule.c b/numpy/core/src/umath/umathmodule.c index 52aa2e48d..57b2bb239 100644 --- a/numpy/core/src/umath/umathmodule.c +++ b/numpy/core/src/umath/umathmodule.c @@ -201,182 +201,6 @@ ufunc_frompyfunc(PyObject *NPY_UNUSED(dummy), PyObject *args, PyObject *NPY_UNUS ***************************************************************************** */ -/* Less automated additions to the ufuncs */ - -static PyUFuncGenericFunction frexp_functions[] = { -#ifdef HAVE_FREXPF - HALF_frexp, - FLOAT_frexp, -#endif - DOUBLE_frexp -#ifdef HAVE_FREXPL - ,LONGDOUBLE_frexp -#endif -}; - -static char frexp_signatures[] = { -#ifdef HAVE_FREXPF - NPY_HALF, NPY_HALF, NPY_INT, - NPY_FLOAT, NPY_FLOAT, NPY_INT, -#endif - NPY_DOUBLE, NPY_DOUBLE, NPY_INT -#ifdef HAVE_FREXPL - ,NPY_LONGDOUBLE, NPY_LONGDOUBLE, NPY_INT -#endif -}; -static void * blank_data[12]; - -#if NPY_SIZEOF_LONG == NPY_SIZEOF_INT -#define LDEXP_LONG(typ) typ##_ldexp -#else -#define LDEXP_LONG(typ) typ##_ldexp_long -#endif - -static PyUFuncGenericFunction ldexp_functions[] = { -#ifdef HAVE_LDEXPF - HALF_ldexp, - FLOAT_ldexp, - LDEXP_LONG(HALF), - LDEXP_LONG(FLOAT), -#endif - DOUBLE_ldexp, - LDEXP_LONG(DOUBLE) -#ifdef HAVE_LDEXPL - , - LONGDOUBLE_ldexp, - LDEXP_LONG(LONGDOUBLE) -#endif -}; - -static const char frdoc[] = - " Decompose the elements of x into mantissa and twos exponent.\n" - "\n" - " Returns (`mantissa`, `exponent`), where `x = mantissa * 2**exponent``.\n" - " The mantissa is lies in the open interval(-1, 1), while the twos\n" - " exponent is a signed integer.\n" - "\n" - " Parameters\n" - " ----------\n" - " x : array_like\n" - " Array of numbers to be decomposed.\n" - " out1: ndarray, optional\n" - " Output array for the mantissa. Must have the same shape as `x`.\n" - " out2: ndarray, optional\n" - " Output array for the exponent. Must have the same shape as `x`.\n" - "\n" - " Returns\n" - " -------\n" - " (mantissa, exponent) : tuple of ndarrays, (float, int)\n" - " `mantissa` is a float array with values between -1 and 1.\n" - " `exponent` is an int array which represents the exponent of 2.\n" - "\n" - " See Also\n" - " --------\n" - " ldexp : Compute ``y = x1 * 2**x2``, the inverse of `frexp`.\n" - "\n" - " Notes\n" - " -----\n" - " Complex dtypes are not supported, they will raise a TypeError.\n" - "\n" - " Examples\n" - " --------\n" - " >>> x = np.arange(9)\n" - " >>> y1, y2 = np.frexp(x)\n" - " >>> y1\n" - " array([ 0. , 0.5 , 0.5 , 0.75 , 0.5 , 0.625, 0.75 , 0.875,\n" - " 0.5 ])\n" - " >>> y2\n" - " array([0, 1, 2, 2, 3, 3, 3, 3, 4])\n" - " >>> y1 * 2**y2\n" - " array([ 0., 1., 2., 3., 4., 5., 6., 7., 8.])\n" - "\n"; - - -static char ldexp_signatures[] = { -#ifdef HAVE_LDEXPF - NPY_HALF, NPY_INT, NPY_HALF, - NPY_FLOAT, NPY_INT, NPY_FLOAT, - NPY_HALF, NPY_LONG, NPY_HALF, - NPY_FLOAT, NPY_LONG, NPY_FLOAT, -#endif - NPY_DOUBLE, NPY_INT, NPY_DOUBLE, - NPY_DOUBLE, NPY_LONG, NPY_DOUBLE -#ifdef HAVE_LDEXPL - ,NPY_LONGDOUBLE, NPY_INT, NPY_LONGDOUBLE - ,NPY_LONGDOUBLE, NPY_LONG, NPY_LONGDOUBLE -#endif -}; - -static const char lddoc[] = - " Returns x1 * 2**x2, element-wise.\n" - "\n" - " The mantissas `x1` and twos exponents `x2` are used to construct\n" - " floating point numbers ``x1 * 2**x2``.\n" - "\n" - " Parameters\n" - " ----------\n" - " x1 : array_like\n" - " Array of multipliers.\n" - " x2 : array_like, int\n" - " Array of twos exponents.\n" - " out : ndarray, optional\n" - " Output array for the result.\n" - "\n" - " Returns\n" - " -------\n" - " y : ndarray or scalar\n" - " The result of ``x1 * 2**x2``.\n" - "\n" - " See Also\n" - " --------\n" - " frexp : Return (y1, y2) from ``x = y1 * 2**y2``, inverse to `ldexp`.\n" - "\n" - " Notes\n" - " -----\n" - " Complex dtypes are not supported, they will raise a TypeError.\n" - "\n" - " `ldexp` is useful as the inverse of `frexp`, if used by itself it is\n" - " more clear to simply use the expression ``x1 * 2**x2``.\n" - "\n" - " Examples\n" - " --------\n" - " >>> np.ldexp(5, np.arange(4))\n" - " array([ 5., 10., 20., 40.], dtype=float32)\n" - "\n" - " >>> x = np.arange(6)\n" - " >>> np.ldexp(*np.frexp(x))\n" - " array([ 0., 1., 2., 3., 4., 5.])\n" - "\n"; - - -static void -InitOtherOperators(PyObject *dictionary) { - PyObject *f; - int num; - - num = sizeof(frexp_functions) / sizeof(frexp_functions[0]); - assert(sizeof(blank_data) / sizeof(blank_data[0]) >= num); - f = PyUFunc_FromFuncAndData(frexp_functions, blank_data, - frexp_signatures, num, - 1, 2, PyUFunc_None, "frexp", frdoc, 0); - PyDict_SetItemString(dictionary, "frexp", f); - Py_DECREF(f); - - num = sizeof(ldexp_functions) / sizeof(ldexp_functions[0]); - assert(sizeof(blank_data) / sizeof(blank_data[0]) >= num); - f = PyUFunc_FromFuncAndData(ldexp_functions, blank_data, - ldexp_signatures, num, - 2, 1, PyUFunc_None, "ldexp", lddoc, 0); - PyDict_SetItemString(dictionary, "ldexp", f); - Py_DECREF(f); - -#if defined(NPY_PY3K) - f = PyDict_GetItemString(dictionary, "true_divide"); - PyDict_SetItemString(dictionary, "divide", f); -#endif - return; -} - NPY_VISIBILITY_HIDDEN PyObject * npy_um_str_out = NULL; NPY_VISIBILITY_HIDDEN PyObject * npy_um_str_subok = NULL; NPY_VISIBILITY_HIDDEN PyObject * npy_um_str_array_prepare = NULL; @@ -492,8 +316,6 @@ PyMODINIT_FUNC initumath(void) /* Load the ufunc operators into the array module's namespace */ InitOperators(d); - InitOtherOperators(d); - PyDict_SetItemString(d, "pi", s = PyFloat_FromDouble(NPY_PI)); Py_DECREF(s); PyDict_SetItemString(d, "e", s = PyFloat_FromDouble(NPY_E)); @@ -536,6 +358,11 @@ PyMODINIT_FUNC initumath(void) PyModule_AddObject(m, "NZERO", PyFloat_FromDouble(NPY_NZERO)); PyModule_AddObject(m, "NAN", PyFloat_FromDouble(NPY_NAN)); +#if defined(NPY_PY3K) + s = PyDict_GetItemString(d, "true_divide"); + PyDict_SetItemString(d, "divide", s); +#endif + s = PyDict_GetItemString(d, "conjugate"); s2 = PyDict_GetItemString(d, "remainder"); /* Setup the array object's numerical structures with appropriate diff --git a/numpy/core/tests/test_multiarray.py b/numpy/core/tests/test_multiarray.py index cb5c0095c..57fae23aa 100644 --- a/numpy/core/tests/test_multiarray.py +++ b/numpy/core/tests/test_multiarray.py @@ -1695,6 +1695,66 @@ class TestMethods(TestCase): class TestBinop(object): + def test_inplace(self): + # test refcount 1 inplace conversion + assert_array_almost_equal(np.array([0.5]) * np.array([1.0, 2.0]), + [0.5, 1.0]) + + d = np.array([0.5, 0.5])[::2] + assert_array_almost_equal(d * (d * np.array([1.0, 2.0])), + [0.25, 0.5]) + + a = np.array([0.5]) + b = np.array([0.5]) + c = a + b + c = a - b + c = a * b + c = a / b + assert_equal(a, b) + assert_almost_equal(c, 1.) + + c = a + b * 2. / b * a - a / b + assert_equal(a, b) + assert_equal(c, 0.5) + + # true divide + a = np.array([5]) + b = np.array([3]) + c = (a * a) / b + + assert_almost_equal(c, 25 / 3) + assert_equal(a, 5) + assert_equal(b, 3) + + def test_extension_incref_elide(self): + # test extension (e.g. cython) calling PyNumber_* slots without + # increasing the reference counts + # + # def incref_elide(a): + # d = input.copy() # refcount 1 + # return d, d + d # PyNumber_Add without increasing refcount + from numpy.core.multiarray_tests import incref_elide + d = np.ones(5) + orig, res = incref_elide(d) + # the return original should not be changed to an inplace operation + assert_array_equal(orig, d) + assert_array_equal(res, d + d) + + def test_extension_incref_elide_stack(self): + # scanning if the refcount == 1 object is on the python stack to check + # that we are called directly from python is flawed as object may still + # be above the stack pointer and we have no access to the top of it + # + # def incref_elide_l(d): + # return l[4] + l[4] # PyNumber_Add without increasing refcount + from numpy.core.multiarray_tests import incref_elide_l + # padding with 1 makes sure the object on the stack is not overwriten + l = [1, 1, 1, 1, np.ones(5)] + res = incref_elide_l(l) + # the return original should not be changed to an inplace operation + assert_array_equal(l[4], np.ones(5)) + assert_array_equal(res, l[4] + l[4]) + def test_ufunc_override_rop_precedence(self): # Check that __rmul__ and other right-hand operations have # precedence over __numpy_ufunc__ diff --git a/numpy/core/tests/test_scalarmath.py b/numpy/core/tests/test_scalarmath.py index d823e963f..afdc06c03 100644 --- a/numpy/core/tests/test_scalarmath.py +++ b/numpy/core/tests/test_scalarmath.py @@ -83,6 +83,18 @@ class TestBaseMath(TestCase): np.add(1, inp2, out=out) assert_almost_equal(out, exp1, err_msg=msg) + def test_lower_align(self): + # check data that is not aligned to element size + # i.e doubles are aligned to 4 bytes on i386 + d = np.zeros(23 * 8, dtype=np.int8)[4:-4].view(np.float64) + o = np.zeros(23 * 8, dtype=np.int8)[4:-4].view(np.float64) + assert_almost_equal(d + d, d * 2) + np.add(d, d, out=o) + np.add(np.ones_like(d), d, out=o) + np.add(d, np.ones_like(d), out=o) + np.add(np.ones_like(d), d) + np.add(d, np.ones_like(d)) + class TestPower(TestCase): def test_small_types(self): diff --git a/numpy/core/tests/test_umath.py b/numpy/core/tests/test_umath.py index b3ddc2398..483dcb04b 100644 --- a/numpy/core/tests/test_umath.py +++ b/numpy/core/tests/test_umath.py @@ -753,6 +753,13 @@ class TestMinMax(TestCase): inp[i] = -1e10 assert_equal(inp.min(), -1e10, err_msg=msg) + def test_lower_align(self): + # check data that is not aligned to element size + # i.e doubles are aligned to 4 bytes on i386 + d = np.zeros(23 * 8, dtype=np.int8)[4:-4].view(np.float64) + assert_equal(d.max(), d[0]) + assert_equal(d.min(), d[0]) + class TestAbsoluteNegative(TestCase): def test_abs_neg_blocked(self): @@ -785,6 +792,17 @@ class TestAbsoluteNegative(TestCase): np.negative(inp, out=out) assert_array_equal(out, -1*inp, err_msg=msg) + def test_lower_align(self): + # check data that is not aligned to element size + # i.e doubles are aligned to 4 bytes on i386 + d = np.zeros(23 * 8, dtype=np.int8)[4:-4].view(np.float64) + assert_equal(np.abs(d), d) + assert_equal(np.negative(d), -d) + np.negative(d, out=d) + np.negative(np.ones_like(d), out=d) + np.abs(d, out=d) + np.abs(np.ones_like(d), out=d) + class TestSpecialMethods(TestCase): def test_wrap(self): diff --git a/numpy/distutils/command/autodist.py b/numpy/distutils/command/autodist.py index 1b9b1dd57..5a9470b9b 100644 --- a/numpy/distutils/command/autodist.py +++ b/numpy/distutils/command/autodist.py @@ -41,3 +41,37 @@ main() } """ return cmd.try_compile(body, None, None) + + +def check_gcc_function_attribute(cmd, attribute, name): + """Return True if the given function attribute is supported.""" + cmd._check_compiler() + body = """ +#pragma GCC diagnostic error "-Wattributes" +#pragma clang diagnostic error "-Wattributes" + +int %s %s(void*); + +int +main() +{ +} +""" % (attribute, name) + return cmd.try_compile(body, None, None) != 0 + +def check_gcc_variable_attribute(cmd, attribute): + """Return True if the given variable attribute is supported.""" + cmd._check_compiler() + body = """ +#pragma GCC diagnostic error "-Wattributes" +#pragma clang diagnostic error "-Wattributes" + +int %s foo; + +int +main() +{ + return 0; +} +""" % (attribute, ) + return cmd.try_compile(body, None, None) != 0 diff --git a/numpy/distutils/command/config.py b/numpy/distutils/command/config.py index 0086e3632..fce4fc791 100644 --- a/numpy/distutils/command/config.py +++ b/numpy/distutils/command/config.py @@ -16,7 +16,10 @@ from distutils.ccompiler import CompileError, LinkError import distutils from numpy.distutils.exec_command import exec_command from numpy.distutils.mingw32ccompiler import generate_manifest -from numpy.distutils.command.autodist import check_inline, check_compiler_gcc4 +from numpy.distutils.command.autodist import (check_gcc_function_attribute, + check_gcc_variable_attribute, + check_inline, + check_compiler_gcc4) from numpy.distutils.compat import get_exception LANG_EXT['f77'] = '.f' @@ -402,6 +405,12 @@ int main () """Return True if the C compiler is gcc >= 4.""" return check_compiler_gcc4(self) + def check_gcc_function_attribute(self, attribute, name): + return check_gcc_function_attribute(self, attribute, name) + + def check_gcc_variable_attribute(self, attribute): + return check_gcc_variable_attribute(self, attribute) + def get_output(self, body, headers=None, include_dirs=None, libraries=None, library_dirs=None, lang="c", use_tee=None): diff --git a/numpy/lib/tests/test_twodim_base.py b/numpy/lib/tests/test_twodim_base.py index f5b8fab4a..c9a220920 100644 --- a/numpy/lib/tests/test_twodim_base.py +++ b/numpy/lib/tests/test_twodim_base.py @@ -311,6 +311,18 @@ def test_tril_triu_ndim3(): yield assert_equal, a_triu_observed.dtype, a.dtype yield assert_equal, a_tril_observed.dtype, a.dtype +def test_tril_triu_with_inf(): + # Issue 4859 + arr = np.array([[1, 1, np.inf], + [1, 1, 1], + [np.inf, 1, 1]]) + out_tril = np.array([[1, 0, 0], + [1, 1, 0], + [np.inf, 1, 1]]) + out_triu = out_tril.T + assert_array_equal(np.triu(arr), out_triu) + assert_array_equal(np.tril(arr), out_tril) + def test_mask_indices(): # simple test without offset diff --git a/numpy/lib/twodim_base.py b/numpy/lib/twodim_base.py index a8925592a..f26ff0619 100644 --- a/numpy/lib/twodim_base.py +++ b/numpy/lib/twodim_base.py @@ -387,7 +387,6 @@ def tri(N, M=None, k=0, dtype=float): dtype : dtype, optional Data type of the returned array. The default is float. - Returns ------- tri : ndarray of shape (N, M) @@ -452,7 +451,9 @@ def tril(m, k=0): """ m = asanyarray(m) - return multiply(tri(*m.shape[-2:], k=k, dtype=bool), m, dtype=m.dtype) + mask = tri(*m.shape[-2:], k=k, dtype=bool) + + return where(mask, m, 0) def triu(m, k=0): @@ -478,7 +479,9 @@ def triu(m, k=0): """ m = asanyarray(m) - return multiply(~tri(*m.shape[-2:], k=k-1, dtype=bool), m, dtype=m.dtype) + mask = tri(*m.shape[-2:], k=k-1, dtype=bool) + + return where(mask, 0, m) # Originally borrowed from John Hunter and matplotlib |