summaryrefslogtreecommitdiff
path: root/numpy
diff options
context:
space:
mode:
Diffstat (limited to 'numpy')
-rw-r--r--numpy/core/arrayprint.py31
-rw-r--r--numpy/core/function_base.py17
-rw-r--r--numpy/core/src/multiarray/cblasfuncs.c37
-rw-r--r--numpy/core/src/multiarray/multiarraymodule.c58
-rw-r--r--numpy/core/src/multiarray/scalartypes.c.src60
-rw-r--r--numpy/core/tests/test_arrayprint.py4
-rw-r--r--numpy/core/tests/test_multiarray.py12
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])