summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--benchmarks/benchmarks/bench_ufunc.py52
-rw-r--r--numpy/core/src/multiarray/cblasfuncs.c105
-rw-r--r--numpy/core/src/multiarray/common.c100
-rw-r--r--numpy/core/src/multiarray/common.h13
-rw-r--r--numpy/core/src/multiarray/compiled_base.c8
-rw-r--r--numpy/core/src/multiarray/multiarraymodule.c98
-rw-r--r--numpy/lib/tests/test_arraypad.py15
-rw-r--r--numpy/lib/tests/test_function_base.py14
-rwxr-xr-xruntests.py38
9 files changed, 210 insertions, 233 deletions
diff --git a/benchmarks/benchmarks/bench_ufunc.py b/benchmarks/benchmarks/bench_ufunc.py
index 5d5eae251..a7e385f70 100644
--- a/benchmarks/benchmarks/bench_ufunc.py
+++ b/benchmarks/benchmarks/bench_ufunc.py
@@ -152,6 +152,18 @@ class Scalar(Benchmark):
(self.y + self.z)
+class ArgPack(object):
+ __slots__ = ['args', 'kwargs']
+ def __init__(self, *args, **kwargs):
+ self.args = args
+ self.kwargs = kwargs
+ def __repr__(self):
+ return '({})'.format(', '.join(
+ [repr(a) for a in self.args] +
+ ['{}={}'.format(k, repr(v)) for k, v in self.kwargs.items()]
+ ))
+
+
class ArgParsing(Benchmark):
# In order to benchmark the speed of argument parsing, all but the
# out arguments are chosen such that they have no effect on the
@@ -163,18 +175,18 @@ class ArgParsing(Benchmark):
out = np.array(3.)
param_names = ['arg_kwarg']
params = [[
- ((x, y), dict()),
- ((x, y, out), dict()),
- ((x, y), dict(out=out)),
- ((x, y), dict(out=(out,))),
- ((x, y), dict(out=out, subok=True, where=True)),
- ((x, y), dict(subok=True)),
- ((x, y), dict(subok=True, where=True)),
- ((x, y, out), dict(subok=True, where=True))
+ ArgPack(x, y),
+ ArgPack(x, y, out),
+ ArgPack(x, y, out=out),
+ ArgPack(x, y, out=(out,)),
+ ArgPack(x, y, out=out, subok=True, where=True),
+ ArgPack(x, y, subok=True),
+ ArgPack(x, y, subok=True, where=True),
+ ArgPack(x, y, out, subok=True, where=True)
]]
- def time_add_arg_parsing(self, arg_kwarg):
- np.add(*arg_kwarg[0], **arg_kwarg[1])
+ def time_add_arg_parsing(self, arg_pack):
+ np.add(*arg_pack.args, **arg_pack.kwargs)
class ArgParsingReduce(Benchmark):
@@ -185,15 +197,15 @@ class ArgParsingReduce(Benchmark):
out = np.array(0.)
param_names = ['arg_kwarg']
params = [[
- ((a,), dict()),
- ((a, 0), dict()),
- ((a,), dict(axis=0)),
- ((a, 0, None), dict()),
- ((a,), dict(axis=0, dtype=None)),
- ((a, 0, None, out), dict()),
- ((a,), dict(axis=0, dtype=None, out=out)),
- ((a,), dict(out=out))
+ ArgPack(a,),
+ ArgPack(a, 0),
+ ArgPack(a, axis=0),
+ ArgPack(a, 0, None),
+ ArgPack(a, axis=0, dtype=None),
+ ArgPack(a, 0, None, out),
+ ArgPack(a, axis=0, dtype=None, out=out),
+ ArgPack(a, out=out)
]]
- def time_add_reduce_arg_parsing(self, arg_kwarg):
- np.add.reduce(*arg_kwarg[0], **arg_kwarg[1])
+ def time_add_reduce_arg_parsing(self, arg_pack):
+ np.add.reduce(*arg_pack.args, **arg_pack.kwargs)
diff --git a/numpy/core/src/multiarray/cblasfuncs.c b/numpy/core/src/multiarray/cblasfuncs.c
index c941bb29b..6460c5db1 100644
--- a/numpy/core/src/multiarray/cblasfuncs.c
+++ b/numpy/core/src/multiarray/cblasfuncs.c
@@ -12,32 +12,6 @@
#include "npy_cblas.h"
#include "arraytypes.h"
#include "common.h"
-#include "mem_overlap.h"
-
-
-/*
- * Helper: call appropriate BLAS dot function for typenum.
- * Strides are NumPy strides.
- */
-static void
-blas_dot(int typenum, npy_intp n,
- void *a, npy_intp stridea, void *b, npy_intp strideb, void *res)
-{
- switch (typenum) {
- case NPY_DOUBLE:
- DOUBLE_dot(a, stridea, b, strideb, res, n, NULL);
- break;
- case NPY_FLOAT:
- FLOAT_dot(a, stridea, b, strideb, res, n, NULL);
- break;
- case NPY_CDOUBLE:
- CDOUBLE_dot(a, stridea, b, strideb, res, n, NULL);
- break;
- case NPY_CFLOAT:
- CFLOAT_dot(a, stridea, b, strideb, res, n, NULL);
- break;
- }
-}
static const double oneD[2] = {1.0, 0.0}, zeroD[2] = {0.0, 0.0};
@@ -227,6 +201,7 @@ _bad_strides(PyArrayObject *ap)
return 0;
}
+
/*
* dot(a,b)
* Returns the dot product of a and b for arrays of floating point types.
@@ -379,77 +354,9 @@ cblas_matrixproduct(int typenum, PyArrayObject *ap1, PyArrayObject *ap2,
}
}
- if (out != NULL) {
- int d;
-
- /* verify that out is usable */
- 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 datatype, "
- "number of dimensions, and be a C-Array)");
- goto fail;
- }
- for (d = 0; d < nd; ++d) {
- if (dimensions[d] != PyArray_DIM(out, d)) {
- PyErr_SetString(PyExc_ValueError,
- "output array has wrong dimensions");
- goto fail;
- }
- }
-
- /* check for memory overlap */
- if (!(solve_may_share_memory(out, ap1, 1) == 0 &&
- solve_may_share_memory(out, ap2, 1) == 0)) {
- /* allocate temporary output array */
- out_buf = (PyArrayObject *)PyArray_NewLikeArray(out, NPY_CORDER,
- NULL, 0);
- if (out_buf == NULL) {
- goto fail;
- }
-
- /* set copy-back */
- Py_INCREF(out);
- if (PyArray_SetWritebackIfCopyBase(out_buf, out) < 0) {
- Py_DECREF(out);
- goto fail;
- }
- }
- else {
- Py_INCREF(out);
- out_buf = out;
- }
- Py_INCREF(out);
- result = out;
- }
- else {
- 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);
- if (out_buf == NULL) {
- goto fail;
- }
-
- Py_INCREF(out_buf);
- result = out_buf;
+ out_buf = new_array_for_sum(ap1, ap2, out, nd, dimensions, typenum, &result);
+ if (out_buf == NULL) {
+ goto fail;
}
numbytes = PyArray_NBYTES(out_buf);
@@ -617,10 +524,10 @@ cblas_matrixproduct(int typenum, PyArrayObject *ap1, PyArrayObject *ap2,
NPY_BEGIN_ALLOW_THREADS;
/* Dot product between two vectors -- Level 1 BLAS */
- blas_dot(typenum, l,
+ PyArray_DESCR(out_buf)->f->dotfunc(
PyArray_DATA(ap1), PyArray_STRIDE(ap1, (ap1shape == _row)),
PyArray_DATA(ap2), PyArray_STRIDE(ap2, 0),
- PyArray_DATA(out_buf));
+ PyArray_DATA(out_buf), l, NULL);
NPY_END_ALLOW_THREADS;
}
else if (ap1shape == _matrix && ap2shape != _matrix) {
diff --git a/numpy/core/src/multiarray/common.c b/numpy/core/src/multiarray/common.c
index c70f8526e..4f695fdc7 100644
--- a/numpy/core/src/multiarray/common.c
+++ b/numpy/core/src/multiarray/common.c
@@ -15,6 +15,7 @@
#include "buffer.h"
#include "get_attr_string.h"
+#include "mem_overlap.h"
/*
* The casting to use for implicit assignment operations resulting from
@@ -852,3 +853,102 @@ _may_have_objects(PyArray_Descr *dtype)
return (PyDataType_HASFIELDS(base) ||
PyDataType_FLAGCHK(base, NPY_ITEM_HASOBJECT) );
}
+
+/*
+ * Make a new empty array, of the passed size, of a type that takes the
+ * priority of ap1 and ap2 into account.
+ *
+ * If `out` is non-NULL, memory overlap is checked with ap1 and ap2, and an
+ * updateifcopy temporary array may be returned. If `result` is non-NULL, the
+ * output array to be returned (`out` if non-NULL and the newly allocated array
+ * otherwise) is incref'd and put to *result.
+ */
+NPY_NO_EXPORT PyArrayObject *
+new_array_for_sum(PyArrayObject *ap1, PyArrayObject *ap2, PyArrayObject* out,
+ int nd, npy_intp dimensions[], int typenum, PyArrayObject **result)
+{
+ PyArrayObject *out_buf;
+
+ if (out) {
+ int d;
+
+ /* verify that out is usable */
+ 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 datatype, "
+ "number of dimensions, and be a C-Array)");
+ return 0;
+ }
+ for (d = 0; d < nd; ++d) {
+ if (dimensions[d] != PyArray_DIM(out, d)) {
+ PyErr_SetString(PyExc_ValueError,
+ "output array has wrong dimensions");
+ return 0;
+ }
+ }
+
+ /* check for memory overlap */
+ if (!(solve_may_share_memory(out, ap1, 1) == 0 &&
+ solve_may_share_memory(out, ap2, 1) == 0)) {
+ /* allocate temporary output array */
+ out_buf = (PyArrayObject *)PyArray_NewLikeArray(out, NPY_CORDER,
+ NULL, 0);
+ if (out_buf == NULL) {
+ return NULL;
+ }
+
+ /* set copy-back */
+ Py_INCREF(out);
+ if (PyArray_SetWritebackIfCopyBase(out_buf, out) < 0) {
+ Py_DECREF(out);
+ Py_DECREF(out_buf);
+ return NULL;
+ }
+ }
+ else {
+ Py_INCREF(out);
+ out_buf = out;
+ }
+
+ if (result) {
+ Py_INCREF(out);
+ *result = 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));
+
+ if (out_buf != NULL && result) {
+ Py_INCREF(out_buf);
+ *result = out_buf;
+ }
+
+ return out_buf;
+ }
+}
+
+
+
diff --git a/numpy/core/src/multiarray/common.h b/numpy/core/src/multiarray/common.h
index ae9b960c8..db0a49920 100644
--- a/numpy/core/src/multiarray/common.h
+++ b/numpy/core/src/multiarray/common.h
@@ -283,4 +283,17 @@ blas_stride(npy_intp stride, unsigned itemsize)
#include "ucsnarrow.h"
+/*
+ * Make a new empty array, of the passed size, of a type that takes the
+ * priority of ap1 and ap2 into account.
+ *
+ * If `out` is non-NULL, memory overlap is checked with ap1 and ap2, and an
+ * updateifcopy temporary array may be returned. If `result` is non-NULL, the
+ * output array to be returned (`out` if non-NULL and the newly allocated array
+ * otherwise) is incref'd and put to *result.
+ */
+NPY_NO_EXPORT PyArrayObject *
+new_array_for_sum(PyArrayObject *ap1, PyArrayObject *ap2, PyArrayObject* out,
+ int nd, npy_intp dimensions[], int typenum, PyArrayObject **result);
+
#endif
diff --git a/numpy/core/src/multiarray/compiled_base.c b/numpy/core/src/multiarray/compiled_base.c
index bcb44f6d1..8c140f5e2 100644
--- a/numpy/core/src/multiarray/compiled_base.c
+++ b/numpy/core/src/multiarray/compiled_base.c
@@ -654,6 +654,10 @@ arr_interp(PyObject *NPY_UNUSED(self), PyObject *args, PyObject *kwdict)
else if (j == lenxp - 1) {
dres[i] = dy[j];
}
+ else if (dx[j] == x_val) {
+ /* Avoid potential non-finite interpolation */
+ dres[i] = dy[j];
+ }
else {
const npy_double slope = (slopes != NULL) ? slopes[j] :
(dy[j+1] - dy[j]) / (dx[j+1] - dx[j]);
@@ -822,6 +826,10 @@ arr_interp_complex(PyObject *NPY_UNUSED(self), PyObject *args, PyObject *kwdict)
else if (j == lenxp - 1) {
dres[i] = dy[j];
}
+ else if (dx[j] == x_val) {
+ /* Avoid potential non-finite interpolation */
+ dres[i] = dy[j];
+ }
else {
if (slopes!=NULL) {
dres[i].real = slopes[j].real*(x_val - dx[j]) + dy[j].real;
diff --git a/numpy/core/src/multiarray/multiarraymodule.c b/numpy/core/src/multiarray/multiarraymodule.c
index f78a748c0..e6af5a81e 100644
--- a/numpy/core/src/multiarray/multiarraymodule.c
+++ b/numpy/core/src/multiarray/multiarraymodule.c
@@ -800,102 +800,6 @@ PyArray_CanCoerceScalar(int thistype, int neededtype,
return 0;
}
-/*
- * Make a new empty array, of the passed size, of a type that takes the
- * priority of ap1 and ap2 into account.
- *
- * If `out` is non-NULL, memory overlap is checked with ap1 and ap2, and an
- * updateifcopy temporary array may be returned. If `result` is non-NULL, the
- * output array to be returned (`out` if non-NULL and the newly allocated array
- * otherwise) is incref'd and put to *result.
- */
-static PyArrayObject *
-new_array_for_sum(PyArrayObject *ap1, PyArrayObject *ap2, PyArrayObject* out,
- int nd, npy_intp dimensions[], int typenum, PyArrayObject **result)
-{
- PyArrayObject *out_buf;
-
- if (out) {
- int d;
-
- /* verify that out is usable */
- 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 datatype, "
- "number of dimensions, and be a C-Array)");
- return 0;
- }
- for (d = 0; d < nd; ++d) {
- if (dimensions[d] != PyArray_DIM(out, d)) {
- PyErr_SetString(PyExc_ValueError,
- "output array has wrong dimensions");
- return 0;
- }
- }
-
- /* check for memory overlap */
- if (!(solve_may_share_memory(out, ap1, 1) == 0 &&
- solve_may_share_memory(out, ap2, 1) == 0)) {
- /* allocate temporary output array */
- out_buf = (PyArrayObject *)PyArray_NewLikeArray(out, NPY_CORDER,
- NULL, 0);
- if (out_buf == NULL) {
- return NULL;
- }
-
- /* set copy-back */
- Py_INCREF(out);
- if (PyArray_SetWritebackIfCopyBase(out_buf, out) < 0) {
- Py_DECREF(out);
- Py_DECREF(out_buf);
- return NULL;
- }
- }
- else {
- Py_INCREF(out);
- out_buf = out;
- }
-
- if (result) {
- Py_INCREF(out);
- *result = 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));
-
- if (out_buf != NULL && result) {
- Py_INCREF(out_buf);
- *result = out_buf;
- }
-
- return out_buf;
- }
-}
-
/* Could perhaps be redone to not make contiguous arrays */
/*NUMPY_API
@@ -1101,7 +1005,7 @@ PyArray_MatrixProduct2(PyObject *op1, PyObject *op2, PyArrayObject* out)
NPY_BEGIN_THREADS_DESCR(PyArray_DESCR(ap2));
while (it1->index < it1->size) {
while (it2->index < it2->size) {
- dot(it1->dataptr, is1, it2->dataptr, is2, op, l, out_buf);
+ dot(it1->dataptr, is1, it2->dataptr, is2, op, l, NULL);
op += os;
PyArray_ITER_NEXT(it2);
}
diff --git a/numpy/lib/tests/test_arraypad.py b/numpy/lib/tests/test_arraypad.py
index 8ba0370b0..45d624781 100644
--- a/numpy/lib/tests/test_arraypad.py
+++ b/numpy/lib/tests/test_arraypad.py
@@ -1009,6 +1009,21 @@ class TestUnicodeInput(object):
assert_array_equal(a, b)
+class TestObjectInput(object):
+ def test_object_input(self):
+ # Regression test for issue gh-11395.
+ a = np.full((4, 3), None)
+ pad_amt = ((2, 3), (3, 2))
+ b = np.full((9, 8), None)
+ modes = ['edge',
+ 'symmetric',
+ 'reflect',
+ 'wrap',
+ ]
+ for mode in modes:
+ assert_array_equal(pad(a, pad_amt, mode=mode), b)
+
+
class TestValueError1(object):
def test_check_simple(self):
arr = np.arange(30)
diff --git a/numpy/lib/tests/test_function_base.py b/numpy/lib/tests/test_function_base.py
index 4103a9eb3..d2a9181db 100644
--- a/numpy/lib/tests/test_function_base.py
+++ b/numpy/lib/tests/test_function_base.py
@@ -2237,6 +2237,14 @@ class TestInterp(object):
x0 = np.nan
assert_almost_equal(np.interp(x0, x, y), x0)
+ def test_non_finite_behavior(self):
+ x = [1, 2, 2.5, 3, 4]
+ xp = [1, 2, 3, 4]
+ fp = [1, 2, np.inf, 4]
+ assert_almost_equal(np.interp(x, xp, fp), [1, 2, np.inf, np.inf, 4])
+ fp = [1, 2, np.nan, 4]
+ assert_almost_equal(np.interp(x, xp, fp), [1, 2, np.nan, np.nan, 4])
+
def test_complex_interp(self):
# test complex interpolation
x = np.linspace(0, 1, 5)
@@ -2251,6 +2259,12 @@ class TestInterp(object):
x0 = 2.0
right = 2 + 3.0j
assert_almost_equal(np.interp(x0, x, y, right=right), right)
+ # test complex non finite
+ x = [1, 2, 2.5, 3, 4]
+ xp = [1, 2, 3, 4]
+ fp = [1, 2+1j, np.inf, 4]
+ y = [1, 2+1j, np.inf+0.5j, np.inf, 4]
+ assert_almost_equal(np.interp(x, xp, fp), y)
# test complex periodic
x = [-180, -170, -185, 185, -10, -5, 0, 365]
xp = [190, -190, 350, -350]
diff --git a/runtests.py b/runtests.py
index 35717b319..355173326 100755
--- a/runtests.py
+++ b/runtests.py
@@ -384,23 +384,27 @@ def build_project(args):
with open(log_filename, 'w') as log:
p = subprocess.Popen(cmd, env=env, stdout=log, stderr=log,
cwd=ROOT_DIR)
-
- # Wait for it to finish, and print something to indicate the
- # process is alive, but only if the log file has grown (to
- # allow continuous integration environments kill a hanging
- # process accurately if it produces no output)
- last_blip = time.time()
- last_log_size = os.stat(log_filename).st_size
- while p.poll() is None:
- time.sleep(0.5)
- if time.time() - last_blip > 60:
- log_size = os.stat(log_filename).st_size
- if log_size > last_log_size:
- print(" ... build in progress")
- last_blip = time.time()
- last_log_size = log_size
-
- ret = p.wait()
+ try:
+ # Wait for it to finish, and print something to indicate the
+ # process is alive, but only if the log file has grown (to
+ # allow continuous integration environments kill a hanging
+ # process accurately if it produces no output)
+ last_blip = time.time()
+ last_log_size = os.stat(log_filename).st_size
+ while p.poll() is None:
+ time.sleep(0.5)
+ if time.time() - last_blip > 60:
+ log_size = os.stat(log_filename).st_size
+ if log_size > last_log_size:
+ print(" ... build in progress")
+ last_blip = time.time()
+ last_log_size = log_size
+
+ ret = p.wait()
+ except:
+ p.kill()
+ p.wait()
+ raise
if ret == 0:
print("Build OK")