diff options
Diffstat (limited to 'numpy')
-rw-r--r-- | numpy/core/arrayprint.py | 31 | ||||
-rw-r--r-- | numpy/core/function_base.py | 17 | ||||
-rw-r--r-- | numpy/core/src/multiarray/cblasfuncs.c | 37 | ||||
-rw-r--r-- | numpy/core/src/multiarray/multiarraymodule.c | 58 | ||||
-rw-r--r-- | numpy/core/src/multiarray/scalartypes.c.src | 60 | ||||
-rw-r--r-- | numpy/core/tests/test_arrayprint.py | 4 | ||||
-rw-r--r-- | numpy/core/tests/test_multiarray.py | 12 |
7 files changed, 132 insertions, 87 deletions
diff --git a/numpy/core/arrayprint.py b/numpy/core/arrayprint.py index e0da9f81e..e1df556ef 100644 --- a/numpy/core/arrayprint.py +++ b/numpy/core/arrayprint.py @@ -309,13 +309,7 @@ def _get_format_function(data, **options): """ dtype_ = data.dtype if dtype_.fields is not None: - format_functions = [] - for field_name in dtype_.names: - format_function = _get_format_function(data[field_name], **options) - if dtype_[field_name].shape != (): - format_function = SubArrayFormat(format_function) - format_functions.append(format_function) - return StructureFormat(format_functions) + return StructureFormat.from_data(data, **options) dtypeobj = dtype_.type formatdict = _get_formatdict(data, **options) @@ -873,6 +867,20 @@ class StructureFormat(object): self.format_functions = format_functions self.num_fields = len(format_functions) + @classmethod + def from_data(cls, data, **options): + """ + This is a second way to initialize StructureFormat, using the raw data + as input. Added to avoid changing the signature of __init__. + """ + format_functions = [] + for field_name in data.dtype.names: + format_function = _get_format_function(data[field_name], **options) + if data.dtype[field_name].shape != (): + format_function = SubArrayFormat(format_function) + format_functions.append(format_function) + return cls(format_functions) + def __call__(self, x): s = "(" for field, format_function in zip(x, self.format_functions): @@ -880,6 +888,15 @@ class StructureFormat(object): return (s[:-2] if 1 < self.num_fields else s[:-1]) + ")" +def _void_scalar_repr(x): + """ + Implements the repr for structured-void scalars. It is called from the + scalartypes.c.src code, and is placed here because it uses the elementwise + formatters defined above. + """ + return StructureFormat.from_data(array(x), **_format_options)(x) + + _typelessdata = [int_, float_, complex_] if issubclass(intc, int): _typelessdata.append(intc) diff --git a/numpy/core/function_base.py b/numpy/core/function_base.py index 0415e16ac..82de1a36e 100644 --- a/numpy/core/function_base.py +++ b/numpy/core/function_base.py @@ -115,17 +115,24 @@ def linspace(start, stop, num=50, endpoint=True, retstep=False, dtype=None): y = _nx.arange(0, num, dtype=dt) delta = stop - start + # In-place multiplication y *= delta/div is faster, but prevents the multiplicant + # from overriding what class is produced, and thus prevents, e.g. use of Quantities, + # see gh-7142. Hence, we multiply in place only for standard scalar types. + _mult_inplace = _nx.isscalar(delta) if num > 1: step = delta / div if step == 0: # Special handling for denormal numbers, gh-5437 y /= div - y = y * delta + if _mult_inplace: + y *= delta + else: + y = y * delta else: - # One might be tempted to use faster, in-place multiplication here, - # but this prevents step from overriding what class is produced, - # and thus prevents, e.g., use of Quantities; see gh-7142. - y = y * step + if _mult_inplace: + y *= step + else: + y = y * step else: # 0 and 1 item long sequences have an undefined step step = NaN diff --git a/numpy/core/src/multiarray/cblasfuncs.c b/numpy/core/src/multiarray/cblasfuncs.c index 8432ae5cf..7cb1652bb 100644 --- a/numpy/core/src/multiarray/cblasfuncs.c +++ b/numpy/core/src/multiarray/cblasfuncs.c @@ -250,8 +250,6 @@ cblas_matrixproduct(int typenum, PyArrayObject *ap1, PyArrayObject *ap2, npy_intp ap1stride = 0; npy_intp dimensions[NPY_MAXDIMS]; npy_intp numbytes; - double prior1, prior2; - PyTypeObject *subtype; MatrixShape ap1shape, ap2shape; if (_bad_strides(ap1)) { @@ -381,29 +379,17 @@ cblas_matrixproduct(int typenum, PyArrayObject *ap1, PyArrayObject *ap2, } } - /* Choose which subtype to return */ - if (Py_TYPE(ap1) != Py_TYPE(ap2)) { - prior2 = PyArray_GetPriority((PyObject *)ap2, 0.0); - prior1 = PyArray_GetPriority((PyObject *)ap1, 0.0); - subtype = (prior2 > prior1 ? Py_TYPE(ap2) : Py_TYPE(ap1)); - } - else { - prior1 = prior2 = 0.0; - subtype = Py_TYPE(ap1); - } - if (out != NULL) { int d; /* verify that out is usable */ - if (Py_TYPE(out) != subtype || - PyArray_NDIM(out) != nd || + if (PyArray_NDIM(out) != nd || PyArray_TYPE(out) != typenum || !PyArray_ISCARRAY(out)) { PyErr_SetString(PyExc_ValueError, - "output array is not acceptable " - "(must have the right type, nr dimensions, and be a C-Array)"); + "output array is not acceptable (must have the right datatype, " + "number of dimensions, and be a C-Array)"); goto fail; } for (d = 0; d < nd; ++d) { @@ -439,7 +425,22 @@ cblas_matrixproduct(int typenum, PyArrayObject *ap1, PyArrayObject *ap2, result = out; } else { - PyObject *tmp = (PyObject *)(prior2 > prior1 ? ap2 : ap1); + double prior1, prior2; + PyTypeObject *subtype; + PyObject *tmp; + + /* Choose which subtype to return */ + if (Py_TYPE(ap1) != Py_TYPE(ap2)) { + prior2 = PyArray_GetPriority((PyObject *)ap2, 0.0); + prior1 = PyArray_GetPriority((PyObject *)ap1, 0.0); + subtype = (prior2 > prior1 ? Py_TYPE(ap2) : Py_TYPE(ap1)); + } + else { + prior1 = prior2 = 0.0; + subtype = Py_TYPE(ap1); + } + + tmp = (PyObject *)(prior2 > prior1 ? ap2 : ap1); out_buf = (PyArrayObject *)PyArray_New(subtype, nd, dimensions, typenum, NULL, NULL, 0, 0, tmp); diff --git a/numpy/core/src/multiarray/multiarraymodule.c b/numpy/core/src/multiarray/multiarraymodule.c index 66a076dc6..210882ff0 100644 --- a/numpy/core/src/multiarray/multiarraymodule.c +++ b/numpy/core/src/multiarray/multiarraymodule.c @@ -796,32 +796,17 @@ new_array_for_sum(PyArrayObject *ap1, PyArrayObject *ap2, PyArrayObject* out, int nd, npy_intp dimensions[], int typenum, PyArrayObject **result) { PyArrayObject *out_buf; - PyTypeObject *subtype; - double prior1, prior2; - /* - * Need to choose an output array that can hold a sum - * -- use priority to determine which subtype. - */ - if (Py_TYPE(ap2) != Py_TYPE(ap1)) { - prior2 = PyArray_GetPriority((PyObject *)ap2, 0.0); - prior1 = PyArray_GetPriority((PyObject *)ap1, 0.0); - subtype = (prior2 > prior1 ? Py_TYPE(ap2) : Py_TYPE(ap1)); - } - else { - prior1 = prior2 = 0.0; - subtype = Py_TYPE(ap1); - } + if (out) { int d; /* verify that out is usable */ - if (Py_TYPE(out) != subtype || - PyArray_NDIM(out) != nd || + if (PyArray_NDIM(out) != nd || PyArray_TYPE(out) != typenum || !PyArray_ISCARRAY(out)) { PyErr_SetString(PyExc_ValueError, - "output array is not acceptable " - "(must have the right type, nr dimensions, and be a C-Array)"); + "output array is not acceptable (must have the right datatype, " + "number of dimensions, and be a C-Array)"); return 0; } for (d = 0; d < nd; ++d) { @@ -862,18 +847,35 @@ new_array_for_sum(PyArrayObject *ap1, PyArrayObject *ap2, PyArrayObject* out, return out_buf; } + else { + PyTypeObject *subtype; + double prior1, prior2; + /* + * Need to choose an output array that can hold a sum + * -- use priority to determine which subtype. + */ + if (Py_TYPE(ap2) != Py_TYPE(ap1)) { + prior2 = PyArray_GetPriority((PyObject *)ap2, 0.0); + prior1 = PyArray_GetPriority((PyObject *)ap1, 0.0); + subtype = (prior2 > prior1 ? Py_TYPE(ap2) : Py_TYPE(ap1)); + } + else { + prior1 = prior2 = 0.0; + subtype = Py_TYPE(ap1); + } - out_buf = (PyArrayObject *)PyArray_New(subtype, nd, dimensions, - typenum, NULL, NULL, 0, 0, - (PyObject *) - (prior2 > prior1 ? ap2 : ap1)); + out_buf = (PyArrayObject *)PyArray_New(subtype, nd, dimensions, + typenum, NULL, NULL, 0, 0, + (PyObject *) + (prior2 > prior1 ? ap2 : ap1)); - if (out_buf != NULL && result) { - Py_INCREF(out_buf); - *result = out_buf; - } + if (out_buf != NULL && result) { + Py_INCREF(out_buf); + *result = out_buf; + } - return out_buf; + return out_buf; + } } /* Could perhaps be redone to not make contiguous arrays */ diff --git a/numpy/core/src/multiarray/scalartypes.c.src b/numpy/core/src/multiarray/scalartypes.c.src index 7a6ed6a86..c92d835ed 100644 --- a/numpy/core/src/multiarray/scalartypes.c.src +++ b/numpy/core/src/multiarray/scalartypes.c.src @@ -25,6 +25,7 @@ #include "_datetime.h" #include "datetime_strings.h" #include "alloc.h" +#include "npy_import.h" #include <stdlib.h> @@ -339,33 +340,6 @@ gentype_nonzero_number(PyObject *m1) } static PyObject * -gentype_str(PyObject *self) -{ - PyObject *arr, *ret = NULL; - - arr = PyArray_FromScalar(self, NULL); - if (arr != NULL) { - ret = PyObject_Str((PyObject *)arr); - Py_DECREF(arr); - } - return ret; -} - -static PyObject * -gentype_repr(PyObject *self) -{ - PyObject *arr, *ret = NULL; - - arr = PyArray_FromScalar(self, NULL); - if (arr != NULL) { - /* XXX: Why are we using str here? */ - ret = PyObject_Str((PyObject *)arr); - Py_DECREF(arr); - } - return ret; -} - -static PyObject * genint_type_str(PyObject *self) { PyObject *item, *item_str; @@ -634,6 +608,34 @@ static PyObject * /**end repeat**/ static PyObject * +voidtype_str(PyObject *self) +{ + if (PyDataType_HASFIELDS(((PyVoidScalarObject*)self)->descr)) { + static PyObject *reprfunc = NULL; + + npy_cache_import("numpy.core.arrayprint", + "_void_scalar_repr", &reprfunc); + if (reprfunc == NULL) { + return NULL; + } + + return PyObject_CallFunction(reprfunc, "O", self); + } + else { + PyObject *item, *item_str; + + item = gentype_generic_method(self, NULL, NULL, "item"); + if (item == NULL) { + return NULL; + } + + item_str = PyObject_Str(item); + Py_DECREF(item); + return item_str; + } +} + +static PyObject * datetimetype_repr(PyObject *self) { PyDatetimeScalarObject *scal; @@ -4073,8 +4075,6 @@ initialize_numeric_types(void) PyGenericArrType_Type.tp_new = NULL; PyGenericArrType_Type.tp_alloc = gentype_alloc; PyGenericArrType_Type.tp_free = (freefunc)gentype_free; - PyGenericArrType_Type.tp_repr = gentype_repr; - PyGenericArrType_Type.tp_str = gentype_str; PyGenericArrType_Type.tp_richcompare = gentype_richcompare; PyBoolArrType_Type.tp_as_number = &bool_arrtype_as_number; @@ -4122,6 +4122,8 @@ initialize_numeric_types(void) PyVoidArrType_Type.tp_getset = voidtype_getsets; PyVoidArrType_Type.tp_as_mapping = &voidtype_as_mapping; PyVoidArrType_Type.tp_as_sequence = &voidtype_as_sequence; + PyVoidArrType_Type.tp_repr = voidtype_str; + PyVoidArrType_Type.tp_str = voidtype_str; PyIntegerArrType_Type.tp_getset = inttype_getsets; diff --git a/numpy/core/tests/test_arrayprint.py b/numpy/core/tests/test_arrayprint.py index b03229447..26faabfb8 100644 --- a/numpy/core/tests/test_arrayprint.py +++ b/numpy/core/tests/test_arrayprint.py @@ -60,6 +60,10 @@ class TestArrayRepr(object): assert_equal(repr(arr1d), 'array([list([1, 2]), list([3])], dtype=object)') + def test_void_scalar_recursion(self): + # gh-9345 + repr(np.void(b'test')) # RecursionError ? + class TestComplexArray(object): def test_str(self): diff --git a/numpy/core/tests/test_multiarray.py b/numpy/core/tests/test_multiarray.py index ea5421ec2..c28a72150 100644 --- a/numpy/core/tests/test_multiarray.py +++ b/numpy/core/tests/test_multiarray.py @@ -2501,6 +2501,18 @@ class TestMethods(object): assert_raises(ValueError, np.dot, a, b, out=b[::2]) assert_raises(ValueError, np.dot, a, b, out=b.T) + def test_dot_matmul_out(self): + # gh-9641 + class Sub(np.ndarray): + pass + a = np.ones((2, 2)).view(Sub) + b = np.ones((2, 2)).view(Sub) + out = np.ones((2, 2)) + + # make sure out can be any ndarray (not only subclass of inputs) + np.dot(a, b, out=out) + np.matmul(a, b, out=out) + def test_diagonal(self): a = np.arange(12).reshape((3, 4)) assert_equal(a.diagonal(), [0, 5, 10]) |