summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJulian Taylor <jtaylor.debian@googlemail.com>2013-09-07 11:59:19 +0200
committerJulian Taylor <jtaylor.debian@googlemail.com>2013-09-07 13:22:22 +0200
commita486a6bae0580072b3b65771f30bf25c798dc38c (patch)
tree003cc104bbb7a41d8960afc39e94327b9a192dd2
parent1ec94198399e91baf562799548c443040532cd0b (diff)
downloadnumpy-a486a6bae0580072b3b65771f30bf25c798dc38c.tar.gz
ENH: copy ndarrays if they are encountered in setArrayFromSequence
By avoiding the elementwise copy array([a,b,c]) is now as fast as vstack([a,b,c])
-rw-r--r--numpy/core/src/multiarray/ctors.c74
-rw-r--r--numpy/core/tests/test_multiarray.py42
2 files changed, 96 insertions, 20 deletions
diff --git a/numpy/core/src/multiarray/ctors.c b/numpy/core/src/multiarray/ctors.c
index 70f63269e..ef0dca414 100644
--- a/numpy/core/src/multiarray/ctors.c
+++ b/numpy/core/src/multiarray/ctors.c
@@ -24,6 +24,7 @@
#include "_datetime.h"
#include "datetime_strings.h"
#include "array_assign.h"
+#include "mapping.h" /* for array_item_asarray */
/*
* Reading from a file or a string.
@@ -396,14 +397,26 @@ copy_and_swap(void *dst, void *src, int itemsize, npy_intp numitems,
}
}
-/* adapted from Numarray */
+/*
+ * adapted from Numarray,
+ * a: destination array
+ * s: source object, array or sequence
+ * dim: current recursion dimension, must be 0 on first call
+ * dst: must be NULL on first call
+ * it is a view on the destination array viewing the place where to put the
+ * data of the current recursion
+ */
static int
setArrayFromSequence(PyArrayObject *a, PyObject *s,
- int dim, npy_intp offset)
+ int dim, PyArrayObject * dst)
{
Py_ssize_t i, slen;
int res = 0;
+ /* first recursion, view equal destination */
+ if (dst == NULL)
+ dst = a;
+
/*
* This code is to ensure that the sequence access below will
* return a lower-dimensional sequence.
@@ -412,17 +425,26 @@ setArrayFromSequence(PyArrayObject *a, PyObject *s,
/* INCREF on entry DECREF on exit */
Py_INCREF(s);
- if (PyArray_Check(s) && !(PyArray_CheckExact(s))) {
- /*
- * FIXME: This could probably copy the entire subarray at once here using
- * a faster algorithm. Right now, just make sure a base-class array is
- * used so that the dimensionality reduction assumption is correct.
- */
- /* This will DECREF(s) if replaced */
- s = PyArray_EnsureArray(s);
- if (s == NULL) {
+ if (PyArray_Check(s)) {
+ if (!(PyArray_CheckExact(s))) {
+ /*
+ * make sure a base-class array is used so that the dimensionality
+ * reduction assumption is correct.
+ */
+ /* This will DECREF(s) if replaced */
+ s = PyArray_EnsureArray(s);
+ if (s == NULL) {
+ goto fail;
+ }
+ }
+
+ /* dst points to correct array subsection */
+ if (PyArray_CopyInto(dst, (PyArrayObject *)s) < 0) {
goto fail;
}
+
+ Py_DECREF(s);
+ return 0;
}
if (dim > PyArray_NDIM(a)) {
@@ -458,17 +480,23 @@ setArrayFromSequence(PyArrayObject *a, PyObject *s,
for (i = 0; i < alen; i++) {
if ((PyArray_NDIM(a) - dim) > 1) {
- res = setArrayFromSequence(a, o, dim+1, offset);
+ PyArrayObject * tmp =
+ (PyArrayObject *)array_item_asarray(dst, i);
+ if (tmp == NULL) {
+ goto fail;
+ }
+
+ res = setArrayFromSequence(a, o, dim+1, tmp);
+ Py_DECREF(tmp);
}
else {
- res = PyArray_DESCR(a)->f->setitem(o,
- (PyArray_BYTES(a) + offset), a);
+ char * b = (PyArray_BYTES(dst) + i * PyArray_STRIDES(dst)[0]);
+ res = PyArray_DESCR(dst)->f->setitem(o, b, dst);
}
if (res < 0) {
Py_DECREF(o);
goto fail;
}
- offset += PyArray_STRIDES(a)[dim];
}
Py_DECREF(o);
}
@@ -480,17 +508,23 @@ setArrayFromSequence(PyArrayObject *a, PyObject *s,
goto fail;
}
if ((PyArray_NDIM(a) - dim) > 1) {
- res = setArrayFromSequence(a, o, dim+1, offset);
+ PyArrayObject * tmp =
+ (PyArrayObject *)array_item_asarray(dst, i);
+ if (tmp == NULL) {
+ goto fail;
+ }
+
+ res = setArrayFromSequence(a, o, dim+1, tmp);
+ Py_DECREF(tmp);
}
else {
- res = PyArray_DESCR(a)->f->setitem(o,
- (PyArray_BYTES(a) + offset), a);
+ char * b = (PyArray_BYTES(dst) + i * PyArray_STRIDES(dst)[0]);
+ res = PyArray_DESCR(dst)->f->setitem(o, b, dst);
}
Py_DECREF(o);
if (res < 0) {
goto fail;
}
- offset += PyArray_STRIDES(a)[dim];
}
}
@@ -515,7 +549,7 @@ PyArray_AssignFromSequence(PyArrayObject *self, PyObject *v)
"assignment to 0-d array");
return -1;
}
- return setArrayFromSequence(self, v, 0, 0);
+ return setArrayFromSequence(self, v, 0, NULL);
}
/*
diff --git a/numpy/core/tests/test_multiarray.py b/numpy/core/tests/test_multiarray.py
index 0e7f6ec61..19d2810a2 100644
--- a/numpy/core/tests/test_multiarray.py
+++ b/numpy/core/tests/test_multiarray.py
@@ -176,6 +176,48 @@ class TestAttributes(TestCase):
assert_array_equal(x['a'], [3.5, 3.5])
assert_array_equal(x['b'], [-2, -2])
+
+class TestArrayConstruction(TestCase):
+ def test_array(self):
+ d = np.ones(6)
+ r = np.array([d, d])
+ assert_equal(r, np.ones((2, 6)))
+
+ d = np.ones(6)
+ tgt = np.ones((2, 6))
+ r = np.array([d, d])
+ assert_equal(r, tgt)
+ tgt[1] = 2
+ r = np.array([d, d + 1])
+ assert_equal(r, tgt)
+
+ d = np.ones(6)
+ r = np.array([[d, d]])
+ assert_equal(r, np.ones((1, 2, 6)))
+
+ d = np.ones(6)
+ r = np.array([[d, d], [d, d]])
+ assert_equal(r, np.ones((2, 2, 6)))
+
+ d = np.ones((6, 6))
+ r = np.array([d, d])
+ assert_equal(r, np.ones((2, 6, 6)))
+
+ d = np.ones((6, ))
+ r = np.array([[d, d + 1], d + 2])
+ assert_equal(len(r), 2)
+ assert_equal(r[0], [d, d + 1])
+ assert_equal(r[1], d + 2)
+
+ tgt = np.ones((2, 3), dtype=np.bool)
+ tgt[0, 2] = False
+ tgt[1, 0:2] = False
+ r = np.array([[True, True, False], [False, False, True]])
+ assert_equal(r, tgt)
+ r = np.array([[True, False], [True, False], [False, True]])
+ assert_equal(r, tgt.T)
+
+
class TestAssignment(TestCase):
def test_assignment_broadcasting(self):
a = np.arange(6).reshape(2, 3)