summaryrefslogtreecommitdiff
path: root/numpy/core
diff options
context:
space:
mode:
authorTravis Oliphant <oliphant@enthought.com>2006-04-24 20:44:33 +0000
committerTravis Oliphant <oliphant@enthought.com>2006-04-24 20:44:33 +0000
commit448bb44cca09075c0281f0857109db3925908098 (patch)
treed840339bb1f55de400b89db0c5170ca86c53ff34 /numpy/core
parent9867cad08e60ed9232a721dc9a95b7951455bfc1 (diff)
downloadnumpy-448bb44cca09075c0281f0857109db3925908098.tar.gz
Fix so USE_USE_DEFAULTS code works in multi-threaded case. Speed up 1-d array indexing by an integer.
Diffstat (limited to 'numpy/core')
-rw-r--r--numpy/core/numeric.py15
-rw-r--r--numpy/core/src/arrayobject.c31
-rw-r--r--numpy/core/src/ufuncobject.c99
-rw-r--r--numpy/core/tests/test_numeric.py50
4 files changed, 99 insertions, 96 deletions
diff --git a/numpy/core/numeric.py b/numpy/core/numeric.py
index f57527990..557c8e7f4 100644
--- a/numpy/core/numeric.py
+++ b/numpy/core/numeric.py
@@ -395,13 +395,6 @@ def allclose (a, b, rtol=1.e-5, atol=1.e-8):
return d.ravel().all()
-class ufunc_values_obj(object):
- def __init__(self, obj):
- self._val_obj = obj
- def __del__(self):
- umath.seterrobj(self._val_obj)
- del self._val_obj
-
_errdict = {"ignore":ERR_IGNORE,
"warn":ERR_WARN,
@@ -413,11 +406,11 @@ for key in _errdict.keys():
_errdict_rev[_errdict[key]] = key
del key
-def seterr(divide=None, over=None, under=None, invalid=None):
-
+def seterr(divide=None, over=None, under=None, invalid=None):
+
pyvals = umath.geterrobj()
- old = geterr()
-
+ old = geterr()
+
if divide is None: divide = old['divide']
if over is None: over = old['over']
if under is None: under = old['under']
diff --git a/numpy/core/src/arrayobject.c b/numpy/core/src/arrayobject.c
index 0bd14c251..d4b4bb83f 100644
--- a/numpy/core/src/arrayobject.c
+++ b/numpy/core/src/arrayobject.c
@@ -1468,10 +1468,22 @@ array_big_item(PyArrayObject *self, intp i)
return (PyObject *)r;
}
+/* contains optimization for 1-d arrays */
static PyObject *
array_item_nice(PyArrayObject *self, _int_or_ssize_t i)
{
- return PyArray_Return((PyArrayObject *)array_big_item(self, (intp) i));
+ if (self->nd == 1) {
+ char *item;
+ if (i < 0) {
+ i += self->dimensions[0];
+ }
+ if ((item = index2ptr(self, i)) == NULL) return NULL;
+ return PyArray_Scalar(item, self->descr, (PyObject *)self);
+ }
+ else {
+ return PyArray_Return((PyArrayObject *)\
+ array_big_item(self, (intp) i));
+ }
}
static int
@@ -2344,7 +2356,22 @@ array_subscript_nice(PyArrayObject *self, PyObject *op)
implementation may be possible by refactoring
array_subscript */
- PyArrayObject *mp = (PyArrayObject *)array_subscript(self, op);
+ PyArrayObject *mp;
+
+ /* optimization for integer select and 1-d */
+ if (self->nd == 1 && (PyInt_Check(op) || PyLong_Check(op))) {
+ intp value;
+ char *item;
+ value = PyArray_PyIntAsIntp(op);
+ if (PyErr_Occurred())
+ return NULL;
+ else if (value < 0) {
+ value += self->dimensions[0];
+ }
+ if ((item = index2ptr(self, value)) == NULL) return NULL;
+ return PyArray_Scalar(item, self->descr, (PyObject *)self);
+ }
+ mp = (PyArrayObject *)array_subscript(self, op);
if (mp == NULL) return NULL;
diff --git a/numpy/core/src/ufuncobject.c b/numpy/core/src/ufuncobject.c
index bc439b61c..40cf40735 100644
--- a/numpy/core/src/ufuncobject.c
+++ b/numpy/core/src/ufuncobject.c
@@ -35,9 +35,9 @@ typedef void (CdoubleBinaryFunc)(cdouble *x, cdouble *y, cdouble *res);
typedef void (CfloatBinaryFunc)(cfloat *x, cfloat *y, cfloat *res);
typedef void (ClongdoubleBinaryFunc)(clongdouble *x, clongdouble *y, \
clongdouble *res);
-
-#define USE_USE_DEFAULTS 0
-
+
+#define USE_USE_DEFAULTS 1
+
/*UFUNC_API*/
static void
@@ -699,11 +699,11 @@ select_types(PyUFuncObject *self, int *arg_types,
return 0;
}
-
-#if USE_USE_DEFAULTS
-static int PyUFunc_USEDEFAULTS=0;
+
+#if USE_USE_DEFAULTS==1
+static int PyUFunc_NUM_NODEFAULTS=0;
#endif
-static PyObject *PyUFunc_PYVALS_NAME=NULL;
+static PyObject *PyUFunc_PYVALS_NAME=NULL;
/*UFUNC_API*/
@@ -713,20 +713,21 @@ PyUFunc_GetPyValues(char *name, int *bufsize, int *errmask, PyObject **errobj)
PyObject *thedict;
PyObject *ref=NULL;
PyObject *retval;
-
- #if USE_USE_DEFAULTS
- if (!PyUFunc_USEDEFAULTS) {
+
+ #if USE_USE_DEFAULTS==1
+ if (PyUFunc_NUM_NODEFAULTS != 0) {
#endif
if (PyUFunc_PYVALS_NAME == NULL) {
- PyUFunc_PYVALS_NAME = PyString_InternFromString(UFUNC_PYVALS_NAME);
+ PyUFunc_PYVALS_NAME = \
+ PyString_InternFromString(UFUNC_PYVALS_NAME);
}
thedict = PyThreadState_GetDict();
if (thedict == NULL) {
thedict = PyEval_GetBuiltins();
}
- ref = PyDict_GetItem(thedict, PyUFunc_PYVALS_NAME);
- #if USE_USE_DEFAULTS
- }
+ ref = PyDict_GetItem(thedict, PyUFunc_PYVALS_NAME);
+ #if USE_USE_DEFAULTS==1
+ }
#endif
if (ref == NULL) {
*errmask = UFUNC_ERR_DEFAULT;
@@ -2768,7 +2769,6 @@ ufunc_geterr(PyObject *dummy, PyObject *args)
return res;
}
/* Construct list of defaults */
- fprintf(stderr, "Nothing found... return defaults.\n");
res = PyList_New(3);
if (res == NULL) return NULL;
PyList_SET_ITEM(res, 0, PyInt_FromLong(PyArray_BUFSIZE));
@@ -2776,43 +2776,39 @@ ufunc_geterr(PyObject *dummy, PyObject *args)
PyList_SET_ITEM(res, 2, Py_None); Py_INCREF(Py_None);
return res;
}
-
-#if USE_USE_DEFAULTS
-/*
-This doesn't look it will work in the presence of threads. It updates
-PyUFunc_USEDEFAULTS based on the current thread. If some other thread is
-around, it will see an incorrect value for use_defaults.
-
-I think the following strategy would fix this:
- 1. Change PyUFunc_USEDEFAULTS to PyUFunc_NONDEFAULTCOUNT or similar
- 2. Increment PyUFunc_NONDEFAULTCOUNT whenever a value is set to a nondefault
- value
- 3. Only use defaults when PyUFunc_NONDEFAULTCOUNT is nonzero.
-
-However, I'm not sure that it's worth the trouble. I've done a few small
-benchmarks and I see at most marginal speed improvements with the
-default values. So, for the time being, I'm simply ifdefing out the
-nonworking code and not worrying about it. If those benchmarks hold up, we
-should go ahead and rip the code out so as not to confuse future generations.
-
+
+#if USE_USE_DEFAULTS==1
+/*
+This is a strategy to buy a little speed up and avoid the dictionary
+look-up in the default case. It should work in the presence of
+threads. If it is deemed too complicated or it doesn't actually work
+it could be taken out.
*/
static int
ufunc_update_use_defaults(void)
{
PyObject *errobj;
int errmask, bufsize;
-
- PyUFunc_USEDEFAULTS = 0;
- if (PyUFunc_GetPyValues("test", &bufsize, &errmask, &errobj) < 0) return -1;
+ int res;
- if ((errmask == UFUNC_ERR_DEFAULT) && \
- (bufsize == PyArray_BUFSIZE) && \
- (PyTuple_GET_ITEM(errobj, 1) == Py_None)) {
- PyUFunc_USEDEFAULTS = 1;
+ PyUFunc_NUM_NODEFAULTS += 1;
+ res = PyUFunc_GetPyValues("test", &bufsize, &errmask,
+ &errobj);
+ PyUFunc_NUM_NODEFAULTS -= 1;
+
+ if (res < 0) return -1;
+
+ if ((errmask != UFUNC_ERR_DEFAULT) || \
+ (bufsize != PyArray_BUFSIZE) || \
+ (PyTuple_GET_ITEM(errobj, 1) != Py_None)) {
+ PyUFunc_NUM_NODEFAULTS += 1;
+ }
+ else if (PyUFunc_NUM_NODEFAULTS > 0) {
+ PyUFunc_NUM_NODEFAULTS -= 1;
}
return 0;
}
-#endif
+#endif
static PyObject *
ufunc_seterr(PyObject *dummy, PyObject *args)
@@ -2823,21 +2819,9 @@ ufunc_seterr(PyObject *dummy, PyObject *args)
static char *msg = "Error object must be a list of length 3";
if (!PyArg_ParseTuple(args, "O", &val)) return NULL;
-
- if (!PyList_CheckExact(val)) {
- PyObject *new;
- new = PyObject_GetAttrString(val, "_val_obj");
- if (new == NULL) {
- PyErr_SetString(PyExc_ValueError, msg);
- return NULL;
- }
- val = new;
- }
- else Py_INCREF(val);
if (!PyList_CheckExact(val) || PyList_GET_SIZE(val) != 3) {
PyErr_SetString(PyExc_ValueError, msg);
- Py_DECREF(val);
return NULL;
}
if (PyUFunc_PYVALS_NAME == NULL) {
@@ -2848,10 +2832,9 @@ ufunc_seterr(PyObject *dummy, PyObject *args)
thedict = PyEval_GetBuiltins();
}
res = PyDict_SetItem(thedict, PyUFunc_PYVALS_NAME, val);
- Py_DECREF(val);
- if (res < 0) return NULL;
-#if USE_USE_DEFAULTS
- if (ufunc_update_use_defaults() < 0) return NULL;
+ if (res < 0) return NULL;
+#if USE_USE_DEFAULTS==1
+ if (ufunc_update_use_defaults() < 0) return NULL;
#endif
Py_INCREF(Py_None);
return Py_None;
diff --git a/numpy/core/tests/test_numeric.py b/numpy/core/tests/test_numeric.py
index 45204e3bf..000879b96 100644
--- a/numpy/core/tests/test_numeric.py
+++ b/numpy/core/tests/test_numeric.py
@@ -134,31 +134,31 @@ class test_bool_scalar(ScipyTestCase):
self.failUnless((t ^ t) is f)
self.failUnless((f ^ t) is t)
self.failUnless((t ^ f) is t)
- self.failUnless((f ^ f) is f)
-
-
-class test_seterr(ScipyTestCase):
- def test_set(self):
- err = seterr()
- old = seterr(divide='warn')
- self.failUnless(err == old)
- new = seterr()
- self.failUnless(new['divide'] == 'warn')
- seterr(over='raise')
- self.failUnless(geterr()['over'] == 'raise')
- self.failUnless(new['divide'] == 'warn')
- seterr(**old)
- self.failUnless(geterr() == old)
- def test_divideerr(self):
- seterr(divide='raise')
- try:
- array([1.]) / array([0.])
- except FloatingPointError:
- pass
- else:
- self.fail()
- seterr(divide='ignore')
+ self.failUnless((f ^ f) is f)
+
+
+class test_seterr(ScipyTestCase):
+ def test_set(self):
+ err = seterr()
+ old = seterr(divide='warn')
+ self.failUnless(err == old)
+ new = seterr()
+ self.failUnless(new['divide'] == 'warn')
+ seterr(over='raise')
+ self.failUnless(geterr()['over'] == 'raise')
+ self.failUnless(new['divide'] == 'warn')
+ seterr(**old)
+ self.failUnless(geterr() == old)
+ def test_divideerr(self):
+ seterr(divide='raise')
+ try:
+ array([1.]) / array([0.])
+ except FloatingPointError:
+ pass
+ else:
+ self.fail()
+ seterr(divide='ignore')
array([1.]) / array([0.])
-if __name__ == '__main__':
+if __name__ == '__main__':
NumpyTest().run() \ No newline at end of file