diff options
Diffstat (limited to 'numpy/core/src')
-rw-r--r-- | numpy/core/src/arraygetset.c | 882 | ||||
-rw-r--r-- | numpy/core/src/arraygetset.h | 6 | ||||
-rw-r--r-- | numpy/core/src/arraynumber.c | 807 | ||||
-rw-r--r-- | numpy/core/src/arraynumber.h | 19 | ||||
-rw-r--r-- | numpy/core/src/arrayobject.c | 1674 | ||||
-rw-r--r-- | numpy/core/src/arrayobject.h | 4 |
6 files changed, 1718 insertions, 1674 deletions
diff --git a/numpy/core/src/arraygetset.c b/numpy/core/src/arraygetset.c new file mode 100644 index 000000000..2d69f29ba --- /dev/null +++ b/numpy/core/src/arraygetset.c @@ -0,0 +1,882 @@ +/* Array Descr Object */ + +#define PY_SSIZE_T_CLEAN +#include <Python.h> +#include "structmember.h" + +#define _MULTIARRAYMODULE +#define NPY_NO_PREFIX +#include "numpy/arrayobject.h" + +#include "arrayobject.h" +#include "arraydescr.h" +#include "arraygetset.h" + +/******************* array attribute get and set routines ******************/ + +static PyObject * +array_ndim_get(PyArrayObject *self) +{ + return PyInt_FromLong(self->nd); +} + +static PyObject * +array_flags_get(PyArrayObject *self) +{ + return PyArray_NewFlagsObject((PyObject *)self); +} + +static PyObject * +array_shape_get(PyArrayObject *self) +{ + return PyArray_IntTupleFromIntp(self->nd, self->dimensions); +} + + +static int +array_shape_set(PyArrayObject *self, PyObject *val) +{ + int nd; + PyObject *ret; + + /* Assumes C-order */ + ret = PyArray_Reshape(self, val); + if (ret == NULL) { + return -1; + } + if (PyArray_DATA(ret) != PyArray_DATA(self)) { + Py_DECREF(ret); + PyErr_SetString(PyExc_AttributeError, + "incompatible shape for a non-contiguous "\ + "array"); + return -1; + } + + /* Free old dimensions and strides */ + PyDimMem_FREE(self->dimensions); + nd = PyArray_NDIM(ret); + self->nd = nd; + if (nd > 0) { + /* create new dimensions and strides */ + self->dimensions = PyDimMem_NEW(2*nd); + if (self->dimensions == NULL) { + Py_DECREF(ret); + PyErr_SetString(PyExc_MemoryError,""); + return -1; + } + self->strides = self->dimensions + nd; + memcpy(self->dimensions, PyArray_DIMS(ret), nd*sizeof(intp)); + memcpy(self->strides, PyArray_STRIDES(ret), nd*sizeof(intp)); + } + else { + self->dimensions = NULL; + self->strides = NULL; + } + Py_DECREF(ret); + PyArray_UpdateFlags(self, CONTIGUOUS | FORTRAN); + return 0; +} + + +static PyObject * +array_strides_get(PyArrayObject *self) +{ + return PyArray_IntTupleFromIntp(self->nd, self->strides); +} + +static int +array_strides_set(PyArrayObject *self, PyObject *obj) +{ + PyArray_Dims newstrides = {NULL, 0}; + PyArrayObject *new; + intp numbytes = 0; + intp offset = 0; + Py_ssize_t buf_len; + char *buf; + + if (!PyArray_IntpConverter(obj, &newstrides) || + newstrides.ptr == NULL) { + PyErr_SetString(PyExc_TypeError, "invalid strides"); + return -1; + } + if (newstrides.len != self->nd) { + PyErr_Format(PyExc_ValueError, "strides must be " \ + " same length as shape (%d)", self->nd); + goto fail; + } + new = self; + while(new->base && PyArray_Check(new->base)) { + new = (PyArrayObject *)(new->base); + } + /* + * Get the available memory through the buffer interface on + * new->base or if that fails from the current new + */ + if (new->base && PyObject_AsReadBuffer(new->base, + (const void **)&buf, + &buf_len) >= 0) { + offset = self->data - buf; + numbytes = buf_len + offset; + } + else { + PyErr_Clear(); + numbytes = PyArray_MultiplyList(new->dimensions, + new->nd)*new->descr->elsize; + offset = self->data - new->data; + } + + if (!PyArray_CheckStrides(self->descr->elsize, self->nd, numbytes, + offset, + self->dimensions, newstrides.ptr)) { + PyErr_SetString(PyExc_ValueError, "strides is not "\ + "compatible with available memory"); + goto fail; + } + memcpy(self->strides, newstrides.ptr, sizeof(intp)*newstrides.len); + PyArray_UpdateFlags(self, CONTIGUOUS | FORTRAN); + PyDimMem_FREE(newstrides.ptr); + return 0; + + fail: + PyDimMem_FREE(newstrides.ptr); + return -1; +} + + + +static PyObject * +array_priority_get(PyArrayObject *self) +{ + if (PyArray_CheckExact(self)) { + return PyFloat_FromDouble(PyArray_PRIORITY); + } + else { + return PyFloat_FromDouble(PyArray_SUBTYPE_PRIORITY); + } +} + +static PyObject * +array_typestr_get(PyArrayObject *self) +{ + return arraydescr_protocol_typestr_get(self->descr); +} + +static PyObject * +array_descr_get(PyArrayObject *self) +{ + Py_INCREF(self->descr); + return (PyObject *)self->descr; +} + +static PyObject * +array_protocol_descr_get(PyArrayObject *self) +{ + PyObject *res; + PyObject *dobj; + + res = arraydescr_protocol_descr_get(self->descr); + if (res) { + return res; + } + PyErr_Clear(); + + /* get default */ + dobj = PyTuple_New(2); + if (dobj == NULL) { + return NULL; + } + PyTuple_SET_ITEM(dobj, 0, PyString_FromString("")); + PyTuple_SET_ITEM(dobj, 1, array_typestr_get(self)); + res = PyList_New(1); + if (res == NULL) { + Py_DECREF(dobj); + return NULL; + } + PyList_SET_ITEM(res, 0, dobj); + return res; +} + +static PyObject * +array_protocol_strides_get(PyArrayObject *self) +{ + if PyArray_ISCONTIGUOUS(self) { + Py_INCREF(Py_None); + return Py_None; + } + return PyArray_IntTupleFromIntp(self->nd, self->strides); +} + + + +static PyObject * +array_dataptr_get(PyArrayObject *self) +{ + return Py_BuildValue("NO", + PyLong_FromVoidPtr(self->data), + (self->flags & WRITEABLE ? Py_False : + Py_True)); +} + +static PyObject * +array_ctypes_get(PyArrayObject *self) +{ + PyObject *_numpy_internal; + PyObject *ret; + _numpy_internal = PyImport_ImportModule("numpy.core._internal"); + if (_numpy_internal == NULL) { + return NULL; + } + ret = PyObject_CallMethod(_numpy_internal, "_ctypes", "ON", self, + PyLong_FromVoidPtr(self->data)); + Py_DECREF(_numpy_internal); + return ret; +} + +static PyObject * +array_interface_get(PyArrayObject *self) +{ + PyObject *dict; + PyObject *obj; + + dict = PyDict_New(); + if (dict == NULL) { + return NULL; + } + + /* dataptr */ + obj = array_dataptr_get(self); + PyDict_SetItemString(dict, "data", obj); + Py_DECREF(obj); + + obj = array_protocol_strides_get(self); + PyDict_SetItemString(dict, "strides", obj); + Py_DECREF(obj); + + obj = array_protocol_descr_get(self); + PyDict_SetItemString(dict, "descr", obj); + Py_DECREF(obj); + + obj = arraydescr_protocol_typestr_get(self->descr); + PyDict_SetItemString(dict, "typestr", obj); + Py_DECREF(obj); + + obj = array_shape_get(self); + PyDict_SetItemString(dict, "shape", obj); + Py_DECREF(obj); + + obj = PyInt_FromLong(3); + PyDict_SetItemString(dict, "version", obj); + Py_DECREF(obj); + + return dict; +} + +static PyObject * +array_data_get(PyArrayObject *self) +{ + intp nbytes; + if (!(PyArray_ISONESEGMENT(self))) { + PyErr_SetString(PyExc_AttributeError, "cannot get single-"\ + "segment buffer for discontiguous array"); + return NULL; + } + nbytes = PyArray_NBYTES(self); + if PyArray_ISWRITEABLE(self) { + return PyBuffer_FromReadWriteObject((PyObject *)self, 0, (Py_ssize_t) nbytes); + } + else { + return PyBuffer_FromObject((PyObject *)self, 0, (Py_ssize_t) nbytes); + } +} + +static int +array_data_set(PyArrayObject *self, PyObject *op) +{ + void *buf; + Py_ssize_t buf_len; + int writeable=1; + + if (PyObject_AsWriteBuffer(op, &buf, &buf_len) < 0) { + writeable = 0; + if (PyObject_AsReadBuffer(op, (const void **)&buf, &buf_len) < 0) { + PyErr_SetString(PyExc_AttributeError, + "object does not have single-segment " \ + "buffer interface"); + return -1; + } + } + if (!PyArray_ISONESEGMENT(self)) { + PyErr_SetString(PyExc_AttributeError, "cannot set single-" \ + "segment buffer for discontiguous array"); + return -1; + } + if (PyArray_NBYTES(self) > buf_len) { + PyErr_SetString(PyExc_AttributeError, "not enough data for array"); + return -1; + } + if (self->flags & OWNDATA) { + PyArray_XDECREF(self); + PyDataMem_FREE(self->data); + } + if (self->base) { + if (self->flags & UPDATEIFCOPY) { + ((PyArrayObject *)self->base)->flags |= WRITEABLE; + self->flags &= ~UPDATEIFCOPY; + } + Py_DECREF(self->base); + } + Py_INCREF(op); + self->base = op; + self->data = buf; + self->flags = CARRAY; + if (!writeable) { + self->flags &= ~WRITEABLE; + } + return 0; +} + + +static PyObject * +array_itemsize_get(PyArrayObject *self) +{ + return PyInt_FromLong((long) self->descr->elsize); +} + +static PyObject * +array_size_get(PyArrayObject *self) +{ + intp size=PyArray_SIZE(self); +#if SIZEOF_INTP <= SIZEOF_LONG + return PyInt_FromLong((long) size); +#else + if (size > MAX_LONG || size < MIN_LONG) { + return PyLong_FromLongLong(size); + } + else { + return PyInt_FromLong((long) size); + } +#endif +} + +static PyObject * +array_nbytes_get(PyArrayObject *self) +{ + intp nbytes = PyArray_NBYTES(self); +#if SIZEOF_INTP <= SIZEOF_LONG + return PyInt_FromLong((long) nbytes); +#else + if (nbytes > MAX_LONG || nbytes < MIN_LONG) { + return PyLong_FromLongLong(nbytes); + } + else { + return PyInt_FromLong((long) nbytes); + } +#endif +} + + +/* + * If the type is changed. + * Also needing change: strides, itemsize + * + * Either itemsize is exactly the same or the array is single-segment + * (contiguous or fortran) with compatibile dimensions The shape and strides + * will be adjusted in that case as well. + */ + +static int +array_descr_set(PyArrayObject *self, PyObject *arg) +{ + PyArray_Descr *newtype = NULL; + intp newdim; + int index; + char *msg = "new type not compatible with array."; + + if (!(PyArray_DescrConverter(arg, &newtype)) || + newtype == NULL) { + PyErr_SetString(PyExc_TypeError, "invalid data-type for array"); + return -1; + } + if (PyDataType_FLAGCHK(newtype, NPY_ITEM_HASOBJECT) || + PyDataType_FLAGCHK(newtype, NPY_ITEM_IS_POINTER) || + PyDataType_FLAGCHK(self->descr, NPY_ITEM_HASOBJECT) || + PyDataType_FLAGCHK(self->descr, NPY_ITEM_IS_POINTER)) { + PyErr_SetString(PyExc_TypeError, \ + "Cannot change data-type for object " \ + "array."); + Py_DECREF(newtype); + return -1; + } + + if (newtype->elsize == 0) { + PyErr_SetString(PyExc_TypeError, + "data-type must not be 0-sized"); + Py_DECREF(newtype); + return -1; + } + + + if ((newtype->elsize != self->descr->elsize) && + (self->nd == 0 || !PyArray_ISONESEGMENT(self) || + newtype->subarray)) { + goto fail; + } + if (PyArray_ISCONTIGUOUS(self)) { + index = self->nd - 1; + } + else { + index = 0; + } + if (newtype->elsize < self->descr->elsize) { + /* + * if it is compatible increase the size of the + * dimension at end (or at the front for FORTRAN) + */ + if (self->descr->elsize % newtype->elsize != 0) { + goto fail; + } + newdim = self->descr->elsize / newtype->elsize; + self->dimensions[index] *= newdim; + self->strides[index] = newtype->elsize; + } + else if (newtype->elsize > self->descr->elsize) { + /* + * Determine if last (or first if FORTRAN) dimension + * is compatible + */ + newdim = self->dimensions[index] * self->descr->elsize; + if ((newdim % newtype->elsize) != 0) { + goto fail; + } + self->dimensions[index] = newdim / newtype->elsize; + self->strides[index] = newtype->elsize; + } + + /* fall through -- adjust type*/ + Py_DECREF(self->descr); + if (newtype->subarray) { + /* + * create new array object from data and update + * dimensions, strides and descr from it + */ + PyArrayObject *temp; + /* + * We would decref newtype here. + * temp will steal a reference to it + */ + temp = (PyArrayObject *) + PyArray_NewFromDescr(&PyArray_Type, newtype, self->nd, + self->dimensions, self->strides, + self->data, self->flags, NULL); + if (temp == NULL) { + return -1; + } + PyDimMem_FREE(self->dimensions); + self->dimensions = temp->dimensions; + self->nd = temp->nd; + self->strides = temp->strides; + newtype = temp->descr; + Py_INCREF(temp->descr); + /* Fool deallocator not to delete these*/ + temp->nd = 0; + temp->dimensions = NULL; + Py_DECREF(temp); + } + + self->descr = newtype; + PyArray_UpdateFlags(self, UPDATE_ALL); + return 0; + + fail: + PyErr_SetString(PyExc_ValueError, msg); + Py_DECREF(newtype); + return -1; +} + +static PyObject * +array_struct_get(PyArrayObject *self) +{ + PyArrayInterface *inter; + + inter = (PyArrayInterface *)_pya_malloc(sizeof(PyArrayInterface)); + if (inter==NULL) { + return PyErr_NoMemory(); + } + inter->two = 2; + inter->nd = self->nd; + inter->typekind = self->descr->kind; + inter->itemsize = self->descr->elsize; + inter->flags = self->flags; + /* reset unused flags */ + inter->flags &= ~(UPDATEIFCOPY | OWNDATA); + if (PyArray_ISNOTSWAPPED(self)) inter->flags |= NOTSWAPPED; + /* + * Copy shape and strides over since these can be reset + *when the array is "reshaped". + */ + if (self->nd > 0) { + inter->shape = (intp *)_pya_malloc(2*sizeof(intp)*self->nd); + if (inter->shape == NULL) { + _pya_free(inter); + return PyErr_NoMemory(); + } + inter->strides = inter->shape + self->nd; + memcpy(inter->shape, self->dimensions, sizeof(intp)*self->nd); + memcpy(inter->strides, self->strides, sizeof(intp)*self->nd); + } + else { + inter->shape = NULL; + inter->strides = NULL; + } + inter->data = self->data; + if (self->descr->names) { + inter->descr = arraydescr_protocol_descr_get(self->descr); + if (inter->descr == NULL) { + PyErr_Clear(); + } + else { + inter->flags &= ARR_HAS_DESCR; + } + } + else { + inter->descr = NULL; + } + Py_INCREF(self); + return PyCObject_FromVoidPtrAndDesc(inter, self, gentype_struct_free); +} + +static PyObject * +array_base_get(PyArrayObject *self) +{ + if (self->base == NULL) { + Py_INCREF(Py_None); + return Py_None; + } + else { + Py_INCREF(self->base); + return self->base; + } +} + + +NPY_NO_EXPORT int +_zerofill(PyArrayObject *ret) +{ + if (PyDataType_REFCHK(ret->descr)) { + PyObject *zero = PyInt_FromLong(0); + PyArray_FillObjectArray(ret, zero); + Py_DECREF(zero); + if (PyErr_Occurred()) { + Py_DECREF(ret); + return -1; + } + } + else { + intp n = PyArray_NBYTES(ret); + memset(ret->data, 0, n); + } + return 0; +} + + +/* + * Create a view of a complex array with an equivalent data-type + * except it is real instead of complex. + */ +static PyArrayObject * +_get_part(PyArrayObject *self, int imag) +{ + PyArray_Descr *type; + PyArrayObject *ret; + int offset; + + type = PyArray_DescrFromType(self->descr->type_num - + PyArray_NUM_FLOATTYPE); + offset = (imag ? type->elsize : 0); + + if (!PyArray_ISNBO(self->descr->byteorder)) { + PyArray_Descr *new; + new = PyArray_DescrNew(type); + new->byteorder = self->descr->byteorder; + Py_DECREF(type); + type = new; + } + ret = (PyArrayObject *) + PyArray_NewFromDescr(self->ob_type, + type, + self->nd, + self->dimensions, + self->strides, + self->data + offset, + self->flags, (PyObject *)self); + if (ret == NULL) { + return NULL; + } + ret->flags &= ~CONTIGUOUS; + ret->flags &= ~FORTRAN; + Py_INCREF(self); + ret->base = (PyObject *)self; + return ret; +} + +static PyObject * +array_real_get(PyArrayObject *self) +{ + PyArrayObject *ret; + + if (PyArray_ISCOMPLEX(self)) { + ret = _get_part(self, 0); + return (PyObject *)ret; + } + else { + Py_INCREF(self); + return (PyObject *)self; + } +} + + +static int +array_real_set(PyArrayObject *self, PyObject *val) +{ + PyArrayObject *ret; + PyArrayObject *new; + int rint; + + if (PyArray_ISCOMPLEX(self)) { + ret = _get_part(self, 0); + if (ret == NULL) { + return -1; + } + } + else { + Py_INCREF(self); + ret = self; + } + new = (PyArrayObject *)PyArray_FromAny(val, NULL, 0, 0, 0, NULL); + if (new == NULL) { + Py_DECREF(ret); + return -1; + } + rint = PyArray_MoveInto(ret, new); + Py_DECREF(ret); + Py_DECREF(new); + return rint; +} + +static PyObject * +array_imag_get(PyArrayObject *self) +{ + PyArrayObject *ret; + + if (PyArray_ISCOMPLEX(self)) { + ret = _get_part(self, 1); + } + else { + Py_INCREF(self->descr); + ret = (PyArrayObject *)PyArray_NewFromDescr(self->ob_type, + self->descr, + self->nd, + self->dimensions, + NULL, NULL, + PyArray_ISFORTRAN(self), + (PyObject *)self); + if (ret == NULL) { + return NULL; + } + if (_zerofill(ret) < 0) { + return NULL; + } + ret->flags &= ~WRITEABLE; + } + return (PyObject *) ret; +} + +static int +array_imag_set(PyArrayObject *self, PyObject *val) +{ + if (PyArray_ISCOMPLEX(self)) { + PyArrayObject *ret; + PyArrayObject *new; + int rint; + + ret = _get_part(self, 1); + if (ret == NULL) { + return -1; + } + new = (PyArrayObject *)PyArray_FromAny(val, NULL, 0, 0, 0, NULL); + if (new == NULL) { + Py_DECREF(ret); + return -1; + } + rint = PyArray_MoveInto(ret, new); + Py_DECREF(ret); + Py_DECREF(new); + return rint; + } + else { + PyErr_SetString(PyExc_TypeError, "array does not have "\ + "imaginary part to set"); + return -1; + } +} + +static PyObject * +array_flat_get(PyArrayObject *self) +{ + return PyArray_IterNew((PyObject *)self); +} + +static int +array_flat_set(PyArrayObject *self, PyObject *val) +{ + PyObject *arr = NULL; + int retval = -1; + PyArrayIterObject *selfit = NULL, *arrit = NULL; + PyArray_Descr *typecode; + int swap; + PyArray_CopySwapFunc *copyswap; + + typecode = self->descr; + Py_INCREF(typecode); + arr = PyArray_FromAny(val, typecode, + 0, 0, FORCECAST | FORTRAN_IF(self), NULL); + if (arr == NULL) { + return -1; + } + arrit = (PyArrayIterObject *)PyArray_IterNew(arr); + if (arrit == NULL) { + goto exit; + } + selfit = (PyArrayIterObject *)PyArray_IterNew((PyObject *)self); + if (selfit == NULL) { + goto exit; + } + if (arrit->size == 0) { + retval = 0; + goto exit; + } + swap = PyArray_ISNOTSWAPPED(self) != PyArray_ISNOTSWAPPED(arr); + copyswap = self->descr->f->copyswap; + if (PyDataType_REFCHK(self->descr)) { + while (selfit->index < selfit->size) { + PyArray_Item_XDECREF(selfit->dataptr, self->descr); + PyArray_Item_INCREF(arrit->dataptr, PyArray_DESCR(arr)); + memmove(selfit->dataptr, arrit->dataptr, sizeof(PyObject **)); + if (swap) { + copyswap(selfit->dataptr, NULL, swap, self); + } + PyArray_ITER_NEXT(selfit); + PyArray_ITER_NEXT(arrit); + if (arrit->index == arrit->size) { + PyArray_ITER_RESET(arrit); + } + } + retval = 0; + goto exit; + } + + while(selfit->index < selfit->size) { + memmove(selfit->dataptr, arrit->dataptr, self->descr->elsize); + if (swap) { + copyswap(selfit->dataptr, NULL, swap, self); + } + PyArray_ITER_NEXT(selfit); + PyArray_ITER_NEXT(arrit); + if (arrit->index == arrit->size) { + PyArray_ITER_RESET(arrit); + } + } + retval = 0; + + exit: + Py_XDECREF(selfit); + Py_XDECREF(arrit); + Py_XDECREF(arr); + return retval; +} + +static PyObject * +array_transpose_get(PyArrayObject *self) +{ + return PyArray_Transpose(self, NULL); +} + +/* If this is None, no function call is made + --- default sub-class behavior +*/ +static PyObject * +array_finalize_get(PyArrayObject *NPY_UNUSED(self)) +{ + Py_INCREF(Py_None); + return Py_None; +} + +NPY_NO_EXPORT PyGetSetDef array_getsetlist[] = { + {"ndim", + (getter)array_ndim_get, + NULL, NULL, NULL}, + {"flags", + (getter)array_flags_get, + NULL, NULL, NULL}, + {"shape", + (getter)array_shape_get, + (setter)array_shape_set, + NULL, NULL}, + {"strides", + (getter)array_strides_get, + (setter)array_strides_set, + NULL, NULL}, + {"data", + (getter)array_data_get, + (setter)array_data_set, + NULL, NULL}, + {"itemsize", + (getter)array_itemsize_get, + NULL, NULL, NULL}, + {"size", + (getter)array_size_get, + NULL, NULL, NULL}, + {"nbytes", + (getter)array_nbytes_get, + NULL, NULL, NULL}, + {"base", + (getter)array_base_get, + NULL, NULL, NULL}, + {"dtype", + (getter)array_descr_get, + (setter)array_descr_set, + NULL, NULL}, + {"real", + (getter)array_real_get, + (setter)array_real_set, + NULL, NULL}, + {"imag", + (getter)array_imag_get, + (setter)array_imag_set, + NULL, NULL}, + {"flat", + (getter)array_flat_get, + (setter)array_flat_set, + NULL, NULL}, + {"ctypes", + (getter)array_ctypes_get, + NULL, NULL, NULL}, + {"T", + (getter)array_transpose_get, + NULL, NULL, NULL}, + {"__array_interface__", + (getter)array_interface_get, + NULL, NULL, NULL}, + {"__array_struct__", + (getter)array_struct_get, + NULL, NULL, NULL}, + {"__array_priority__", + (getter)array_priority_get, + NULL, NULL, NULL}, + {"__array_finalize__", + (getter)array_finalize_get, + NULL, NULL, NULL}, + {NULL, NULL, NULL, NULL, NULL}, /* Sentinel */ +}; + +/****************** end of attribute get and set routines *******************/ diff --git a/numpy/core/src/arraygetset.h b/numpy/core/src/arraygetset.h new file mode 100644 index 000000000..4f1209de5 --- /dev/null +++ b/numpy/core/src/arraygetset.h @@ -0,0 +1,6 @@ +#ifndef _NPY_ARRAY_GETSET_H_ +#define _NPY_ARRAY_GETSET_H_ + +extern NPY_NO_EXPORT PyGetSetDef array_getsetlist[]; + +#endif diff --git a/numpy/core/src/arraynumber.c b/numpy/core/src/arraynumber.c new file mode 100644 index 000000000..aa3e250cb --- /dev/null +++ b/numpy/core/src/arraynumber.c @@ -0,0 +1,807 @@ +#define PY_SSIZE_T_CLEAN +#include <Python.h> +#include "structmember.h" + +/*#include <stdio.h>*/ +#define _MULTIARRAYMODULE +#define NPY_NO_PREFIX +#include "numpy/arrayobject.h" + +#include "arrayobject.h" +#include "arraynumber.h" + +/************************************************************************* + **************** Implement Number Protocol **************************** + *************************************************************************/ + +NPY_NO_EXPORT NumericOps n_ops; /* NB: static objects initialized to zero */ + +/* Dictionary can contain any of the numeric operations, by name. + Those not present will not be changed +*/ + +#define SET(op) temp=PyDict_GetItemString(dict, #op); \ + if (temp != NULL) { \ + if (!(PyCallable_Check(temp))) return -1; \ + Py_XDECREF(n_ops.op); \ + n_ops.op = temp; \ + } + + +/*NUMPY_API + Set internal structure with number functions that all arrays will use +*/ +NPY_NO_EXPORT int +PyArray_SetNumericOps(PyObject *dict) +{ + PyObject *temp = NULL; + SET(add); + SET(subtract); + SET(multiply); + SET(divide); + SET(remainder); + SET(power); + SET(square); + SET(reciprocal); + SET(ones_like); + SET(sqrt); + SET(negative); + SET(absolute); + SET(invert); + SET(left_shift); + SET(right_shift); + SET(bitwise_and); + SET(bitwise_or); + SET(bitwise_xor); + SET(less); + SET(less_equal); + SET(equal); + SET(not_equal); + SET(greater); + SET(greater_equal); + SET(floor_divide); + SET(true_divide); + SET(logical_or); + SET(logical_and); + SET(floor); + SET(ceil); + SET(maximum); + SET(minimum); + SET(rint); + SET(conjugate); + return 0; +} + +#define GET(op) if (n_ops.op && \ + (PyDict_SetItemString(dict, #op, n_ops.op)==-1)) \ + goto fail; + +/*NUMPY_API + Get dictionary showing number functions that all arrays will use +*/ +NPY_NO_EXPORT PyObject * +PyArray_GetNumericOps(void) +{ + PyObject *dict; + if ((dict = PyDict_New())==NULL) + return NULL; + GET(add); + GET(subtract); + GET(multiply); + GET(divide); + GET(remainder); + GET(power); + GET(square); + GET(reciprocal); + GET(ones_like); + GET(sqrt); + GET(negative); + GET(absolute); + GET(invert); + GET(left_shift); + GET(right_shift); + GET(bitwise_and); + GET(bitwise_or); + GET(bitwise_xor); + GET(less); + GET(less_equal); + GET(equal); + GET(not_equal); + GET(greater); + GET(greater_equal); + GET(floor_divide); + GET(true_divide); + GET(logical_or); + GET(logical_and); + GET(floor); + GET(ceil); + GET(maximum); + GET(minimum); + GET(rint); + GET(conjugate); + return dict; + + fail: + Py_DECREF(dict); + return NULL; +} + +static PyObject * +_get_keywords(int rtype, PyArrayObject *out) +{ + PyObject *kwds = NULL; + if (rtype != PyArray_NOTYPE || out != NULL) { + kwds = PyDict_New(); + if (rtype != PyArray_NOTYPE) { + PyArray_Descr *descr; + descr = PyArray_DescrFromType(rtype); + if (descr) { + PyDict_SetItemString(kwds, "dtype", (PyObject *)descr); + Py_DECREF(descr); + } + } + if (out != NULL) { + PyDict_SetItemString(kwds, "out", (PyObject *)out); + } + } + return kwds; +} + +NPY_NO_EXPORT PyObject * +PyArray_GenericReduceFunction(PyArrayObject *m1, PyObject *op, int axis, + int rtype, PyArrayObject *out) +{ + PyObject *args, *ret = NULL, *meth; + PyObject *kwds; + if (op == NULL) { + Py_INCREF(Py_NotImplemented); + return Py_NotImplemented; + } + args = Py_BuildValue("(Oi)", m1, axis); + kwds = _get_keywords(rtype, out); + meth = PyObject_GetAttrString(op, "reduce"); + if (meth && PyCallable_Check(meth)) { + ret = PyObject_Call(meth, args, kwds); + } + Py_DECREF(args); + Py_DECREF(meth); + Py_XDECREF(kwds); + return ret; +} + + +NPY_NO_EXPORT PyObject * +PyArray_GenericAccumulateFunction(PyArrayObject *m1, PyObject *op, int axis, + int rtype, PyArrayObject *out) +{ + PyObject *args, *ret = NULL, *meth; + PyObject *kwds; + if (op == NULL) { + Py_INCREF(Py_NotImplemented); + return Py_NotImplemented; + } + args = Py_BuildValue("(Oi)", m1, axis); + kwds = _get_keywords(rtype, out); + meth = PyObject_GetAttrString(op, "accumulate"); + if (meth && PyCallable_Check(meth)) { + ret = PyObject_Call(meth, args, kwds); + } + Py_DECREF(args); + Py_DECREF(meth); + Py_XDECREF(kwds); + return ret; +} + + +NPY_NO_EXPORT PyObject * +PyArray_GenericBinaryFunction(PyArrayObject *m1, PyObject *m2, PyObject *op) +{ + if (op == NULL) { + Py_INCREF(Py_NotImplemented); + return Py_NotImplemented; + } + return PyObject_CallFunction(op, "OO", m1, m2); +} + +NPY_NO_EXPORT PyObject * +PyArray_GenericUnaryFunction(PyArrayObject *m1, PyObject *op) +{ + if (op == NULL) { + Py_INCREF(Py_NotImplemented); + return Py_NotImplemented; + } + return PyObject_CallFunction(op, "(O)", m1); +} + +static PyObject * +PyArray_GenericInplaceBinaryFunction(PyArrayObject *m1, + PyObject *m2, PyObject *op) +{ + if (op == NULL) { + Py_INCREF(Py_NotImplemented); + return Py_NotImplemented; + } + return PyObject_CallFunction(op, "OOO", m1, m2, m1); +} + +static PyObject * +PyArray_GenericInplaceUnaryFunction(PyArrayObject *m1, PyObject *op) +{ + if (op == NULL) { + Py_INCREF(Py_NotImplemented); + return Py_NotImplemented; + } + return PyObject_CallFunction(op, "OO", m1, m1); +} + +static PyObject * +array_add(PyArrayObject *m1, PyObject *m2) +{ + return PyArray_GenericBinaryFunction(m1, m2, n_ops.add); +} + +static PyObject * +array_subtract(PyArrayObject *m1, PyObject *m2) +{ + return PyArray_GenericBinaryFunction(m1, m2, n_ops.subtract); +} + +static PyObject * +array_multiply(PyArrayObject *m1, PyObject *m2) +{ + return PyArray_GenericBinaryFunction(m1, m2, n_ops.multiply); +} + +static PyObject * +array_divide(PyArrayObject *m1, PyObject *m2) +{ + return PyArray_GenericBinaryFunction(m1, m2, n_ops.divide); +} + +static PyObject * +array_remainder(PyArrayObject *m1, PyObject *m2) +{ + return PyArray_GenericBinaryFunction(m1, m2, n_ops.remainder); +} + +static int +array_power_is_scalar(PyObject *o2, double* exp) +{ + PyObject *temp; + const int optimize_fpexps = 1; + + if (PyInt_Check(o2)) { + *exp = (double)PyInt_AsLong(o2); + return 1; + } + if (optimize_fpexps && PyFloat_Check(o2)) { + *exp = PyFloat_AsDouble(o2); + return 1; + } + if ((PyArray_IsZeroDim(o2) && + ((PyArray_ISINTEGER(o2) || + (optimize_fpexps && PyArray_ISFLOAT(o2))))) || + PyArray_IsScalar(o2, Integer) || + (optimize_fpexps && PyArray_IsScalar(o2, Floating))) { + temp = o2->ob_type->tp_as_number->nb_float(o2); + if (temp != NULL) { + *exp = PyFloat_AsDouble(o2); + Py_DECREF(temp); + return 1; + } + } +#if (PY_VERSION_HEX >= 0x02050000) + if (PyIndex_Check(o2)) { + PyObject* value = PyNumber_Index(o2); + Py_ssize_t val; + if (value==NULL) { + if (PyErr_Occurred()) { + PyErr_Clear(); + } + return 0; + } + val = PyInt_AsSsize_t(value); + if (val == -1 && PyErr_Occurred()) { + PyErr_Clear(); + return 0; + } + *exp = (double) val; + return 1; + } +#endif + return 0; +} + +/* optimize float array or complex array to a scalar power */ +static PyObject * +fast_scalar_power(PyArrayObject *a1, PyObject *o2, int inplace) +{ + double exp; + + if (PyArray_Check(a1) && array_power_is_scalar(o2, &exp)) { + PyObject *fastop = NULL; + if (PyArray_ISFLOAT(a1) || PyArray_ISCOMPLEX(a1)) { + if (exp == 1.0) { + /* we have to do this one special, as the + "copy" method of array objects isn't set + up early enough to be added + by PyArray_SetNumericOps. + */ + if (inplace) { + Py_INCREF(a1); + return (PyObject *)a1; + } else { + return PyArray_Copy(a1); + } + } + else if (exp == -1.0) { + fastop = n_ops.reciprocal; + } + else if (exp == 0.0) { + fastop = n_ops.ones_like; + } + else if (exp == 0.5) { + fastop = n_ops.sqrt; + } + else if (exp == 2.0) { + fastop = n_ops.square; + } + else { + return NULL; + } + + if (inplace) { + return PyArray_GenericInplaceUnaryFunction(a1, fastop); + } else { + return PyArray_GenericUnaryFunction(a1, fastop); + } + } + else if (exp==2.0) { + fastop = n_ops.multiply; + if (inplace) { + return PyArray_GenericInplaceBinaryFunction + (a1, (PyObject *)a1, fastop); + } + else { + return PyArray_GenericBinaryFunction + (a1, (PyObject *)a1, fastop); + } + } + } + return NULL; +} + +static PyObject * +array_power(PyArrayObject *a1, PyObject *o2, PyObject *NPY_UNUSED(modulo)) +{ + /* modulo is ignored! */ + PyObject *value; + value = fast_scalar_power(a1, o2, 0); + if (!value) { + value = PyArray_GenericBinaryFunction(a1, o2, n_ops.power); + } + return value; +} + + +static PyObject * +array_negative(PyArrayObject *m1) +{ + return PyArray_GenericUnaryFunction(m1, n_ops.negative); +} + +static PyObject * +array_absolute(PyArrayObject *m1) +{ + return PyArray_GenericUnaryFunction(m1, n_ops.absolute); +} + +static PyObject * +array_invert(PyArrayObject *m1) +{ + return PyArray_GenericUnaryFunction(m1, n_ops.invert); +} + +static PyObject * +array_left_shift(PyArrayObject *m1, PyObject *m2) +{ + return PyArray_GenericBinaryFunction(m1, m2, n_ops.left_shift); +} + +static PyObject * +array_right_shift(PyArrayObject *m1, PyObject *m2) +{ + return PyArray_GenericBinaryFunction(m1, m2, n_ops.right_shift); +} + +static PyObject * +array_bitwise_and(PyArrayObject *m1, PyObject *m2) +{ + return PyArray_GenericBinaryFunction(m1, m2, n_ops.bitwise_and); +} + +static PyObject * +array_bitwise_or(PyArrayObject *m1, PyObject *m2) +{ + return PyArray_GenericBinaryFunction(m1, m2, n_ops.bitwise_or); +} + +static PyObject * +array_bitwise_xor(PyArrayObject *m1, PyObject *m2) +{ + return PyArray_GenericBinaryFunction(m1, m2, n_ops.bitwise_xor); +} + +static PyObject * +array_inplace_add(PyArrayObject *m1, PyObject *m2) +{ + return PyArray_GenericInplaceBinaryFunction(m1, m2, n_ops.add); +} + +static PyObject * +array_inplace_subtract(PyArrayObject *m1, PyObject *m2) +{ + return PyArray_GenericInplaceBinaryFunction(m1, m2, n_ops.subtract); +} + +static PyObject * +array_inplace_multiply(PyArrayObject *m1, PyObject *m2) +{ + return PyArray_GenericInplaceBinaryFunction(m1, m2, n_ops.multiply); +} + +static PyObject * +array_inplace_divide(PyArrayObject *m1, PyObject *m2) +{ + return PyArray_GenericInplaceBinaryFunction(m1, m2, n_ops.divide); +} + +static PyObject * +array_inplace_remainder(PyArrayObject *m1, PyObject *m2) +{ + return PyArray_GenericInplaceBinaryFunction(m1, m2, n_ops.remainder); +} + +static PyObject * +array_inplace_power(PyArrayObject *a1, PyObject *o2, PyObject *NPY_UNUSED(modulo)) +{ + /* modulo is ignored! */ + PyObject *value; + value = fast_scalar_power(a1, o2, 1); + if (!value) { + value = PyArray_GenericInplaceBinaryFunction(a1, o2, n_ops.power); + } + return value; +} + +static PyObject * +array_inplace_left_shift(PyArrayObject *m1, PyObject *m2) +{ + return PyArray_GenericInplaceBinaryFunction(m1, m2, n_ops.left_shift); +} + +static PyObject * +array_inplace_right_shift(PyArrayObject *m1, PyObject *m2) +{ + return PyArray_GenericInplaceBinaryFunction(m1, m2, n_ops.right_shift); +} + +static PyObject * +array_inplace_bitwise_and(PyArrayObject *m1, PyObject *m2) +{ + return PyArray_GenericInplaceBinaryFunction(m1, m2, n_ops.bitwise_and); +} + +static PyObject * +array_inplace_bitwise_or(PyArrayObject *m1, PyObject *m2) +{ + return PyArray_GenericInplaceBinaryFunction(m1, m2, n_ops.bitwise_or); +} + +static PyObject * +array_inplace_bitwise_xor(PyArrayObject *m1, PyObject *m2) +{ + return PyArray_GenericInplaceBinaryFunction(m1, m2, n_ops.bitwise_xor); +} + +static PyObject * +array_floor_divide(PyArrayObject *m1, PyObject *m2) +{ + return PyArray_GenericBinaryFunction(m1, m2, n_ops.floor_divide); +} + +static PyObject * +array_true_divide(PyArrayObject *m1, PyObject *m2) +{ + return PyArray_GenericBinaryFunction(m1, m2, n_ops.true_divide); +} + +static PyObject * +array_inplace_floor_divide(PyArrayObject *m1, PyObject *m2) +{ + return PyArray_GenericInplaceBinaryFunction(m1, m2, + n_ops.floor_divide); +} + +static PyObject * +array_inplace_true_divide(PyArrayObject *m1, PyObject *m2) +{ + return PyArray_GenericInplaceBinaryFunction(m1, m2, + n_ops.true_divide); +} + +/* Array evaluates as "TRUE" if any of the elements are non-zero*/ +NPY_NO_EXPORT int +array_any_nonzero(PyArrayObject *mp) +{ + intp index; + PyArrayIterObject *it; + Bool anyTRUE = FALSE; + + it = (PyArrayIterObject *)PyArray_IterNew((PyObject *)mp); + if (it == NULL) { + return anyTRUE; + } + index = it->size; + while(index--) { + if (mp->descr->f->nonzero(it->dataptr, mp)) { + anyTRUE = TRUE; + break; + } + PyArray_ITER_NEXT(it); + } + Py_DECREF(it); + return anyTRUE; +} + +static int +_array_nonzero(PyArrayObject *mp) +{ + intp n; + + n = PyArray_SIZE(mp); + if (n == 1) { + return mp->descr->f->nonzero(mp->data, mp); + } + else if (n == 0) { + return 0; + } + else { + PyErr_SetString(PyExc_ValueError, + "The truth value of an array " \ + "with more than one element is ambiguous. " \ + "Use a.any() or a.all()"); + return -1; + } +} + + + +static PyObject * +array_divmod(PyArrayObject *op1, PyObject *op2) +{ + PyObject *divp, *modp, *result; + + divp = array_floor_divide(op1, op2); + if (divp == NULL) { + return NULL; + } + modp = array_remainder(op1, op2); + if (modp == NULL) { + Py_DECREF(divp); + return NULL; + } + result = Py_BuildValue("OO", divp, modp); + Py_DECREF(divp); + Py_DECREF(modp); + return result; +} + + +NPY_NO_EXPORT PyObject * +array_int(PyArrayObject *v) +{ + PyObject *pv, *pv2; + if (PyArray_SIZE(v) != 1) { + PyErr_SetString(PyExc_TypeError, "only length-1 arrays can be"\ + " converted to Python scalars"); + return NULL; + } + pv = v->descr->f->getitem(v->data, v); + if (pv == NULL) { + return NULL; + } + if (pv->ob_type->tp_as_number == 0) { + PyErr_SetString(PyExc_TypeError, "cannot convert to an int; "\ + "scalar object is not a number"); + Py_DECREF(pv); + return NULL; + } + if (pv->ob_type->tp_as_number->nb_int == 0) { + PyErr_SetString(PyExc_TypeError, "don't know how to convert "\ + "scalar number to int"); + Py_DECREF(pv); + return NULL; + } + + pv2 = pv->ob_type->tp_as_number->nb_int(pv); + Py_DECREF(pv); + return pv2; +} + +static PyObject * +array_float(PyArrayObject *v) +{ + PyObject *pv, *pv2; + if (PyArray_SIZE(v) != 1) { + PyErr_SetString(PyExc_TypeError, "only length-1 arrays can "\ + "be converted to Python scalars"); + return NULL; + } + pv = v->descr->f->getitem(v->data, v); + if (pv == NULL) { + return NULL; + } + if (pv->ob_type->tp_as_number == 0) { + PyErr_SetString(PyExc_TypeError, "cannot convert to a "\ + "float; scalar object is not a number"); + Py_DECREF(pv); + return NULL; + } + if (pv->ob_type->tp_as_number->nb_float == 0) { + PyErr_SetString(PyExc_TypeError, "don't know how to convert "\ + "scalar number to float"); + Py_DECREF(pv); + return NULL; + } + pv2 = pv->ob_type->tp_as_number->nb_float(pv); + Py_DECREF(pv); + return pv2; +} + +static PyObject * +array_long(PyArrayObject *v) +{ + PyObject *pv, *pv2; + if (PyArray_SIZE(v) != 1) { + PyErr_SetString(PyExc_TypeError, "only length-1 arrays can "\ + "be converted to Python scalars"); + return NULL; + } + pv = v->descr->f->getitem(v->data, v); + if (pv->ob_type->tp_as_number == 0) { + PyErr_SetString(PyExc_TypeError, "cannot convert to an int; "\ + "scalar object is not a number"); + return NULL; + } + if (pv->ob_type->tp_as_number->nb_long == 0) { + PyErr_SetString(PyExc_TypeError, "don't know how to convert "\ + "scalar number to long"); + return NULL; + } + pv2 = pv->ob_type->tp_as_number->nb_long(pv); + Py_DECREF(pv); + return pv2; +} + +static PyObject * +array_oct(PyArrayObject *v) +{ + PyObject *pv, *pv2; + if (PyArray_SIZE(v) != 1) { + PyErr_SetString(PyExc_TypeError, "only length-1 arrays can "\ + "be converted to Python scalars"); + return NULL; + } + pv = v->descr->f->getitem(v->data, v); + if (pv->ob_type->tp_as_number == 0) { + PyErr_SetString(PyExc_TypeError, "cannot convert to an int; "\ + "scalar object is not a number"); + return NULL; + } + if (pv->ob_type->tp_as_number->nb_oct == 0) { + PyErr_SetString(PyExc_TypeError, "don't know how to convert "\ + "scalar number to oct"); + return NULL; + } + pv2 = pv->ob_type->tp_as_number->nb_oct(pv); + Py_DECREF(pv); + return pv2; +} + +static PyObject * +array_hex(PyArrayObject *v) +{ + PyObject *pv, *pv2; + if (PyArray_SIZE(v) != 1) { + PyErr_SetString(PyExc_TypeError, "only length-1 arrays can "\ + "be converted to Python scalars"); + return NULL; + } + pv = v->descr->f->getitem(v->data, v); + if (pv->ob_type->tp_as_number == 0) { + PyErr_SetString(PyExc_TypeError, "cannot convert to an int; "\ + "scalar object is not a number"); + return NULL; + } + if (pv->ob_type->tp_as_number->nb_hex == 0) { + PyErr_SetString(PyExc_TypeError, "don't know how to convert "\ + "scalar number to hex"); + return NULL; + } + pv2 = pv->ob_type->tp_as_number->nb_hex(pv); + Py_DECREF(pv); + return pv2; +} + +static PyObject * +_array_copy_nice(PyArrayObject *self) +{ + return PyArray_Return((PyArrayObject *) PyArray_Copy(self)); +} + +#if PY_VERSION_HEX >= 0x02050000 +static PyObject * +array_index(PyArrayObject *v) +{ + if (!PyArray_ISINTEGER(v) || PyArray_SIZE(v) != 1) { + PyErr_SetString(PyExc_TypeError, "only integer arrays with " \ + "one element can be converted to an index"); + return NULL; + } + return v->descr->f->getitem(v->data, v); +} +#endif + + +NPY_NO_EXPORT PyNumberMethods array_as_number = { + (binaryfunc)array_add, /*nb_add*/ + (binaryfunc)array_subtract, /*nb_subtract*/ + (binaryfunc)array_multiply, /*nb_multiply*/ + (binaryfunc)array_divide, /*nb_divide*/ + (binaryfunc)array_remainder, /*nb_remainder*/ + (binaryfunc)array_divmod, /*nb_divmod*/ + (ternaryfunc)array_power, /*nb_power*/ + (unaryfunc)array_negative, /*nb_neg*/ + (unaryfunc)_array_copy_nice, /*nb_pos*/ + (unaryfunc)array_absolute, /*(unaryfunc)array_abs,*/ + (inquiry)_array_nonzero, /*nb_nonzero*/ + (unaryfunc)array_invert, /*nb_invert*/ + (binaryfunc)array_left_shift, /*nb_lshift*/ + (binaryfunc)array_right_shift, /*nb_rshift*/ + (binaryfunc)array_bitwise_and, /*nb_and*/ + (binaryfunc)array_bitwise_xor, /*nb_xor*/ + (binaryfunc)array_bitwise_or, /*nb_or*/ + 0, /*nb_coerce*/ + (unaryfunc)array_int, /*nb_int*/ + (unaryfunc)array_long, /*nb_long*/ + (unaryfunc)array_float, /*nb_float*/ + (unaryfunc)array_oct, /*nb_oct*/ + (unaryfunc)array_hex, /*nb_hex*/ + + /* + * This code adds augmented assignment functionality + * that was made available in Python 2.0 + */ + (binaryfunc)array_inplace_add, /*inplace_add*/ + (binaryfunc)array_inplace_subtract, /*inplace_subtract*/ + (binaryfunc)array_inplace_multiply, /*inplace_multiply*/ + (binaryfunc)array_inplace_divide, /*inplace_divide*/ + (binaryfunc)array_inplace_remainder, /*inplace_remainder*/ + (ternaryfunc)array_inplace_power, /*inplace_power*/ + (binaryfunc)array_inplace_left_shift, /*inplace_lshift*/ + (binaryfunc)array_inplace_right_shift, /*inplace_rshift*/ + (binaryfunc)array_inplace_bitwise_and, /*inplace_and*/ + (binaryfunc)array_inplace_bitwise_xor, /*inplace_xor*/ + (binaryfunc)array_inplace_bitwise_or, /*inplace_or*/ + + (binaryfunc)array_floor_divide, /*nb_floor_divide*/ + (binaryfunc)array_true_divide, /*nb_true_divide*/ + (binaryfunc)array_inplace_floor_divide, /*nb_inplace_floor_divide*/ + (binaryfunc)array_inplace_true_divide, /*nb_inplace_true_divide*/ + +#if PY_VERSION_HEX >= 0x02050000 + (unaryfunc)array_index, /* nb_index */ +#endif + +}; diff --git a/numpy/core/src/arraynumber.h b/numpy/core/src/arraynumber.h new file mode 100644 index 000000000..8c004a198 --- /dev/null +++ b/numpy/core/src/arraynumber.h @@ -0,0 +1,19 @@ +#ifndef _NPY_ARRAY_NUMBER_H_ +#define _NPY_ARRAY_NUMBER_H_ + +extern NPY_NO_EXPORT NumericOps n_ops; +extern NPY_NO_EXPORT PyNumberMethods array_as_number; + +NPY_NO_EXPORT int +array_any_nonzero(PyArrayObject *mp); + +NPY_NO_EXPORT PyObject * +array_int(PyArrayObject *v); + +NPY_NO_EXPORT int +PyArray_SetNumericOps(PyObject *dict); + +NPY_NO_EXPORT PyObject * +PyArray_GetNumericOps(void); + +#endif diff --git a/numpy/core/src/arrayobject.c b/numpy/core/src/arrayobject.c index 1d9256b28..be4932551 100644 --- a/numpy/core/src/arrayobject.c +++ b/numpy/core/src/arrayobject.c @@ -34,6 +34,7 @@ maintainer email: oliphant.travis@ieee.org #include "arraydescr.h" #include "arrayiterators.h" #include "arraymapping.h" +#include "arraygetset.h" #ifndef Py_UNICODE_WIDE #include "ucsnarrow.h" #endif @@ -652,9 +653,6 @@ PyArray_PyIntAsIntp(PyObject *o) return (intp) long_value; } - -static PyObject *array_int(PyArrayObject *v); - /*NUMPY_API*/ NPY_NO_EXPORT int PyArray_PyIntAsInt(PyObject *o) @@ -2221,805 +2219,6 @@ static PyBufferProcs array_as_buffer = { /************************************************************************* - **************** Implement Number Protocol **************************** - *************************************************************************/ - -NPY_NO_EXPORT NumericOps n_ops; /* NB: static objects initialized to zero */ - -/* Dictionary can contain any of the numeric operations, by name. - Those not present will not be changed -*/ - -#define SET(op) temp=PyDict_GetItemString(dict, #op); \ - if (temp != NULL) { \ - if (!(PyCallable_Check(temp))) return -1; \ - Py_XDECREF(n_ops.op); \ - n_ops.op = temp; \ - } - - -/*NUMPY_API - Set internal structure with number functions that all arrays will use -*/ -NPY_NO_EXPORT int -PyArray_SetNumericOps(PyObject *dict) -{ - PyObject *temp = NULL; - SET(add); - SET(subtract); - SET(multiply); - SET(divide); - SET(remainder); - SET(power); - SET(square); - SET(reciprocal); - SET(ones_like); - SET(sqrt); - SET(negative); - SET(absolute); - SET(invert); - SET(left_shift); - SET(right_shift); - SET(bitwise_and); - SET(bitwise_or); - SET(bitwise_xor); - SET(less); - SET(less_equal); - SET(equal); - SET(not_equal); - SET(greater); - SET(greater_equal); - SET(floor_divide); - SET(true_divide); - SET(logical_or); - SET(logical_and); - SET(floor); - SET(ceil); - SET(maximum); - SET(minimum); - SET(rint); - SET(conjugate); - return 0; -} - -#define GET(op) if (n_ops.op && \ - (PyDict_SetItemString(dict, #op, n_ops.op)==-1)) \ - goto fail; - -/*NUMPY_API - Get dictionary showing number functions that all arrays will use -*/ -NPY_NO_EXPORT PyObject * -PyArray_GetNumericOps(void) -{ - PyObject *dict; - if ((dict = PyDict_New())==NULL) - return NULL; - GET(add); - GET(subtract); - GET(multiply); - GET(divide); - GET(remainder); - GET(power); - GET(square); - GET(reciprocal); - GET(ones_like); - GET(sqrt); - GET(negative); - GET(absolute); - GET(invert); - GET(left_shift); - GET(right_shift); - GET(bitwise_and); - GET(bitwise_or); - GET(bitwise_xor); - GET(less); - GET(less_equal); - GET(equal); - GET(not_equal); - GET(greater); - GET(greater_equal); - GET(floor_divide); - GET(true_divide); - GET(logical_or); - GET(logical_and); - GET(floor); - GET(ceil); - GET(maximum); - GET(minimum); - GET(rint); - GET(conjugate); - return dict; - - fail: - Py_DECREF(dict); - return NULL; -} - -static PyObject * -_get_keywords(int rtype, PyArrayObject *out) -{ - PyObject *kwds = NULL; - if (rtype != PyArray_NOTYPE || out != NULL) { - kwds = PyDict_New(); - if (rtype != PyArray_NOTYPE) { - PyArray_Descr *descr; - descr = PyArray_DescrFromType(rtype); - if (descr) { - PyDict_SetItemString(kwds, "dtype", (PyObject *)descr); - Py_DECREF(descr); - } - } - if (out != NULL) { - PyDict_SetItemString(kwds, "out", (PyObject *)out); - } - } - return kwds; -} - -NPY_NO_EXPORT PyObject * -PyArray_GenericReduceFunction(PyArrayObject *m1, PyObject *op, int axis, - int rtype, PyArrayObject *out) -{ - PyObject *args, *ret = NULL, *meth; - PyObject *kwds; - if (op == NULL) { - Py_INCREF(Py_NotImplemented); - return Py_NotImplemented; - } - args = Py_BuildValue("(Oi)", m1, axis); - kwds = _get_keywords(rtype, out); - meth = PyObject_GetAttrString(op, "reduce"); - if (meth && PyCallable_Check(meth)) { - ret = PyObject_Call(meth, args, kwds); - } - Py_DECREF(args); - Py_DECREF(meth); - Py_XDECREF(kwds); - return ret; -} - - -NPY_NO_EXPORT PyObject * -PyArray_GenericAccumulateFunction(PyArrayObject *m1, PyObject *op, int axis, - int rtype, PyArrayObject *out) -{ - PyObject *args, *ret = NULL, *meth; - PyObject *kwds; - if (op == NULL) { - Py_INCREF(Py_NotImplemented); - return Py_NotImplemented; - } - args = Py_BuildValue("(Oi)", m1, axis); - kwds = _get_keywords(rtype, out); - meth = PyObject_GetAttrString(op, "accumulate"); - if (meth && PyCallable_Check(meth)) { - ret = PyObject_Call(meth, args, kwds); - } - Py_DECREF(args); - Py_DECREF(meth); - Py_XDECREF(kwds); - return ret; -} - - -NPY_NO_EXPORT PyObject * -PyArray_GenericBinaryFunction(PyArrayObject *m1, PyObject *m2, PyObject *op) -{ - if (op == NULL) { - Py_INCREF(Py_NotImplemented); - return Py_NotImplemented; - } - return PyObject_CallFunction(op, "OO", m1, m2); -} - -NPY_NO_EXPORT PyObject * -PyArray_GenericUnaryFunction(PyArrayObject *m1, PyObject *op) -{ - if (op == NULL) { - Py_INCREF(Py_NotImplemented); - return Py_NotImplemented; - } - return PyObject_CallFunction(op, "(O)", m1); -} - -static PyObject * -PyArray_GenericInplaceBinaryFunction(PyArrayObject *m1, - PyObject *m2, PyObject *op) -{ - if (op == NULL) { - Py_INCREF(Py_NotImplemented); - return Py_NotImplemented; - } - return PyObject_CallFunction(op, "OOO", m1, m2, m1); -} - -static PyObject * -PyArray_GenericInplaceUnaryFunction(PyArrayObject *m1, PyObject *op) -{ - if (op == NULL) { - Py_INCREF(Py_NotImplemented); - return Py_NotImplemented; - } - return PyObject_CallFunction(op, "OO", m1, m1); -} - -static PyObject * -array_add(PyArrayObject *m1, PyObject *m2) -{ - return PyArray_GenericBinaryFunction(m1, m2, n_ops.add); -} - -static PyObject * -array_subtract(PyArrayObject *m1, PyObject *m2) -{ - return PyArray_GenericBinaryFunction(m1, m2, n_ops.subtract); -} - -static PyObject * -array_multiply(PyArrayObject *m1, PyObject *m2) -{ - return PyArray_GenericBinaryFunction(m1, m2, n_ops.multiply); -} - -static PyObject * -array_divide(PyArrayObject *m1, PyObject *m2) -{ - return PyArray_GenericBinaryFunction(m1, m2, n_ops.divide); -} - -static PyObject * -array_remainder(PyArrayObject *m1, PyObject *m2) -{ - return PyArray_GenericBinaryFunction(m1, m2, n_ops.remainder); -} - -static int -array_power_is_scalar(PyObject *o2, double* exp) -{ - PyObject *temp; - const int optimize_fpexps = 1; - - if (PyInt_Check(o2)) { - *exp = (double)PyInt_AsLong(o2); - return 1; - } - if (optimize_fpexps && PyFloat_Check(o2)) { - *exp = PyFloat_AsDouble(o2); - return 1; - } - if ((PyArray_IsZeroDim(o2) && - ((PyArray_ISINTEGER(o2) || - (optimize_fpexps && PyArray_ISFLOAT(o2))))) || - PyArray_IsScalar(o2, Integer) || - (optimize_fpexps && PyArray_IsScalar(o2, Floating))) { - temp = o2->ob_type->tp_as_number->nb_float(o2); - if (temp != NULL) { - *exp = PyFloat_AsDouble(o2); - Py_DECREF(temp); - return 1; - } - } -#if (PY_VERSION_HEX >= 0x02050000) - if (PyIndex_Check(o2)) { - PyObject* value = PyNumber_Index(o2); - Py_ssize_t val; - if (value==NULL) { - if (PyErr_Occurred()) { - PyErr_Clear(); - } - return 0; - } - val = PyInt_AsSsize_t(value); - if (val == -1 && PyErr_Occurred()) { - PyErr_Clear(); - return 0; - } - *exp = (double) val; - return 1; - } -#endif - return 0; -} - -/* optimize float array or complex array to a scalar power */ -static PyObject * -fast_scalar_power(PyArrayObject *a1, PyObject *o2, int inplace) -{ - double exp; - - if (PyArray_Check(a1) && array_power_is_scalar(o2, &exp)) { - PyObject *fastop = NULL; - if (PyArray_ISFLOAT(a1) || PyArray_ISCOMPLEX(a1)) { - if (exp == 1.0) { - /* we have to do this one special, as the - "copy" method of array objects isn't set - up early enough to be added - by PyArray_SetNumericOps. - */ - if (inplace) { - Py_INCREF(a1); - return (PyObject *)a1; - } else { - return PyArray_Copy(a1); - } - } - else if (exp == -1.0) { - fastop = n_ops.reciprocal; - } - else if (exp == 0.0) { - fastop = n_ops.ones_like; - } - else if (exp == 0.5) { - fastop = n_ops.sqrt; - } - else if (exp == 2.0) { - fastop = n_ops.square; - } - else { - return NULL; - } - - if (inplace) { - return PyArray_GenericInplaceUnaryFunction(a1, fastop); - } else { - return PyArray_GenericUnaryFunction(a1, fastop); - } - } - else if (exp==2.0) { - fastop = n_ops.multiply; - if (inplace) { - return PyArray_GenericInplaceBinaryFunction - (a1, (PyObject *)a1, fastop); - } - else { - return PyArray_GenericBinaryFunction - (a1, (PyObject *)a1, fastop); - } - } - } - return NULL; -} - -static PyObject * -array_power(PyArrayObject *a1, PyObject *o2, PyObject *NPY_UNUSED(modulo)) -{ - /* modulo is ignored! */ - PyObject *value; - value = fast_scalar_power(a1, o2, 0); - if (!value) { - value = PyArray_GenericBinaryFunction(a1, o2, n_ops.power); - } - return value; -} - - -static PyObject * -array_negative(PyArrayObject *m1) -{ - return PyArray_GenericUnaryFunction(m1, n_ops.negative); -} - -static PyObject * -array_absolute(PyArrayObject *m1) -{ - return PyArray_GenericUnaryFunction(m1, n_ops.absolute); -} - -static PyObject * -array_invert(PyArrayObject *m1) -{ - return PyArray_GenericUnaryFunction(m1, n_ops.invert); -} - -static PyObject * -array_left_shift(PyArrayObject *m1, PyObject *m2) -{ - return PyArray_GenericBinaryFunction(m1, m2, n_ops.left_shift); -} - -static PyObject * -array_right_shift(PyArrayObject *m1, PyObject *m2) -{ - return PyArray_GenericBinaryFunction(m1, m2, n_ops.right_shift); -} - -static PyObject * -array_bitwise_and(PyArrayObject *m1, PyObject *m2) -{ - return PyArray_GenericBinaryFunction(m1, m2, n_ops.bitwise_and); -} - -static PyObject * -array_bitwise_or(PyArrayObject *m1, PyObject *m2) -{ - return PyArray_GenericBinaryFunction(m1, m2, n_ops.bitwise_or); -} - -static PyObject * -array_bitwise_xor(PyArrayObject *m1, PyObject *m2) -{ - return PyArray_GenericBinaryFunction(m1, m2, n_ops.bitwise_xor); -} - -static PyObject * -array_inplace_add(PyArrayObject *m1, PyObject *m2) -{ - return PyArray_GenericInplaceBinaryFunction(m1, m2, n_ops.add); -} - -static PyObject * -array_inplace_subtract(PyArrayObject *m1, PyObject *m2) -{ - return PyArray_GenericInplaceBinaryFunction(m1, m2, n_ops.subtract); -} - -static PyObject * -array_inplace_multiply(PyArrayObject *m1, PyObject *m2) -{ - return PyArray_GenericInplaceBinaryFunction(m1, m2, n_ops.multiply); -} - -static PyObject * -array_inplace_divide(PyArrayObject *m1, PyObject *m2) -{ - return PyArray_GenericInplaceBinaryFunction(m1, m2, n_ops.divide); -} - -static PyObject * -array_inplace_remainder(PyArrayObject *m1, PyObject *m2) -{ - return PyArray_GenericInplaceBinaryFunction(m1, m2, n_ops.remainder); -} - -static PyObject * -array_inplace_power(PyArrayObject *a1, PyObject *o2, PyObject *NPY_UNUSED(modulo)) -{ - /* modulo is ignored! */ - PyObject *value; - value = fast_scalar_power(a1, o2, 1); - if (!value) { - value = PyArray_GenericInplaceBinaryFunction(a1, o2, n_ops.power); - } - return value; -} - -static PyObject * -array_inplace_left_shift(PyArrayObject *m1, PyObject *m2) -{ - return PyArray_GenericInplaceBinaryFunction(m1, m2, n_ops.left_shift); -} - -static PyObject * -array_inplace_right_shift(PyArrayObject *m1, PyObject *m2) -{ - return PyArray_GenericInplaceBinaryFunction(m1, m2, n_ops.right_shift); -} - -static PyObject * -array_inplace_bitwise_and(PyArrayObject *m1, PyObject *m2) -{ - return PyArray_GenericInplaceBinaryFunction(m1, m2, n_ops.bitwise_and); -} - -static PyObject * -array_inplace_bitwise_or(PyArrayObject *m1, PyObject *m2) -{ - return PyArray_GenericInplaceBinaryFunction(m1, m2, n_ops.bitwise_or); -} - -static PyObject * -array_inplace_bitwise_xor(PyArrayObject *m1, PyObject *m2) -{ - return PyArray_GenericInplaceBinaryFunction(m1, m2, n_ops.bitwise_xor); -} - -static PyObject * -array_floor_divide(PyArrayObject *m1, PyObject *m2) -{ - return PyArray_GenericBinaryFunction(m1, m2, n_ops.floor_divide); -} - -static PyObject * -array_true_divide(PyArrayObject *m1, PyObject *m2) -{ - return PyArray_GenericBinaryFunction(m1, m2, n_ops.true_divide); -} - -static PyObject * -array_inplace_floor_divide(PyArrayObject *m1, PyObject *m2) -{ - return PyArray_GenericInplaceBinaryFunction(m1, m2, - n_ops.floor_divide); -} - -static PyObject * -array_inplace_true_divide(PyArrayObject *m1, PyObject *m2) -{ - return PyArray_GenericInplaceBinaryFunction(m1, m2, - n_ops.true_divide); -} - -/* Array evaluates as "TRUE" if any of the elements are non-zero*/ -static int -array_any_nonzero(PyArrayObject *mp) -{ - intp index; - PyArrayIterObject *it; - Bool anyTRUE = FALSE; - - it = (PyArrayIterObject *)PyArray_IterNew((PyObject *)mp); - if (it == NULL) { - return anyTRUE; - } - index = it->size; - while(index--) { - if (mp->descr->f->nonzero(it->dataptr, mp)) { - anyTRUE = TRUE; - break; - } - PyArray_ITER_NEXT(it); - } - Py_DECREF(it); - return anyTRUE; -} - -static int -_array_nonzero(PyArrayObject *mp) -{ - intp n; - - n = PyArray_SIZE(mp); - if (n == 1) { - return mp->descr->f->nonzero(mp->data, mp); - } - else if (n == 0) { - return 0; - } - else { - PyErr_SetString(PyExc_ValueError, - "The truth value of an array " \ - "with more than one element is ambiguous. " \ - "Use a.any() or a.all()"); - return -1; - } -} - - - -static PyObject * -array_divmod(PyArrayObject *op1, PyObject *op2) -{ - PyObject *divp, *modp, *result; - - divp = array_floor_divide(op1, op2); - if (divp == NULL) { - return NULL; - } - modp = array_remainder(op1, op2); - if (modp == NULL) { - Py_DECREF(divp); - return NULL; - } - result = Py_BuildValue("OO", divp, modp); - Py_DECREF(divp); - Py_DECREF(modp); - return result; -} - - -static PyObject * -array_int(PyArrayObject *v) -{ - PyObject *pv, *pv2; - if (PyArray_SIZE(v) != 1) { - PyErr_SetString(PyExc_TypeError, "only length-1 arrays can be"\ - " converted to Python scalars"); - return NULL; - } - pv = v->descr->f->getitem(v->data, v); - if (pv == NULL) { - return NULL; - } - if (pv->ob_type->tp_as_number == 0) { - PyErr_SetString(PyExc_TypeError, "cannot convert to an int; "\ - "scalar object is not a number"); - Py_DECREF(pv); - return NULL; - } - if (pv->ob_type->tp_as_number->nb_int == 0) { - PyErr_SetString(PyExc_TypeError, "don't know how to convert "\ - "scalar number to int"); - Py_DECREF(pv); - return NULL; - } - - pv2 = pv->ob_type->tp_as_number->nb_int(pv); - Py_DECREF(pv); - return pv2; -} - -static PyObject * -array_float(PyArrayObject *v) -{ - PyObject *pv, *pv2; - if (PyArray_SIZE(v) != 1) { - PyErr_SetString(PyExc_TypeError, "only length-1 arrays can "\ - "be converted to Python scalars"); - return NULL; - } - pv = v->descr->f->getitem(v->data, v); - if (pv == NULL) { - return NULL; - } - if (pv->ob_type->tp_as_number == 0) { - PyErr_SetString(PyExc_TypeError, "cannot convert to a "\ - "float; scalar object is not a number"); - Py_DECREF(pv); - return NULL; - } - if (pv->ob_type->tp_as_number->nb_float == 0) { - PyErr_SetString(PyExc_TypeError, "don't know how to convert "\ - "scalar number to float"); - Py_DECREF(pv); - return NULL; - } - pv2 = pv->ob_type->tp_as_number->nb_float(pv); - Py_DECREF(pv); - return pv2; -} - -static PyObject * -array_long(PyArrayObject *v) -{ - PyObject *pv, *pv2; - if (PyArray_SIZE(v) != 1) { - PyErr_SetString(PyExc_TypeError, "only length-1 arrays can "\ - "be converted to Python scalars"); - return NULL; - } - pv = v->descr->f->getitem(v->data, v); - if (pv->ob_type->tp_as_number == 0) { - PyErr_SetString(PyExc_TypeError, "cannot convert to an int; "\ - "scalar object is not a number"); - return NULL; - } - if (pv->ob_type->tp_as_number->nb_long == 0) { - PyErr_SetString(PyExc_TypeError, "don't know how to convert "\ - "scalar number to long"); - return NULL; - } - pv2 = pv->ob_type->tp_as_number->nb_long(pv); - Py_DECREF(pv); - return pv2; -} - -static PyObject * -array_oct(PyArrayObject *v) -{ - PyObject *pv, *pv2; - if (PyArray_SIZE(v) != 1) { - PyErr_SetString(PyExc_TypeError, "only length-1 arrays can "\ - "be converted to Python scalars"); - return NULL; - } - pv = v->descr->f->getitem(v->data, v); - if (pv->ob_type->tp_as_number == 0) { - PyErr_SetString(PyExc_TypeError, "cannot convert to an int; "\ - "scalar object is not a number"); - return NULL; - } - if (pv->ob_type->tp_as_number->nb_oct == 0) { - PyErr_SetString(PyExc_TypeError, "don't know how to convert "\ - "scalar number to oct"); - return NULL; - } - pv2 = pv->ob_type->tp_as_number->nb_oct(pv); - Py_DECREF(pv); - return pv2; -} - -static PyObject * -array_hex(PyArrayObject *v) -{ - PyObject *pv, *pv2; - if (PyArray_SIZE(v) != 1) { - PyErr_SetString(PyExc_TypeError, "only length-1 arrays can "\ - "be converted to Python scalars"); - return NULL; - } - pv = v->descr->f->getitem(v->data, v); - if (pv->ob_type->tp_as_number == 0) { - PyErr_SetString(PyExc_TypeError, "cannot convert to an int; "\ - "scalar object is not a number"); - return NULL; - } - if (pv->ob_type->tp_as_number->nb_hex == 0) { - PyErr_SetString(PyExc_TypeError, "don't know how to convert "\ - "scalar number to hex"); - return NULL; - } - pv2 = pv->ob_type->tp_as_number->nb_hex(pv); - Py_DECREF(pv); - return pv2; -} - -static PyObject * -_array_copy_nice(PyArrayObject *self) -{ - return PyArray_Return((PyArrayObject *) PyArray_Copy(self)); -} - -#if PY_VERSION_HEX >= 0x02050000 -static PyObject * -array_index(PyArrayObject *v) -{ - if (!PyArray_ISINTEGER(v) || PyArray_SIZE(v) != 1) { - PyErr_SetString(PyExc_TypeError, "only integer arrays with " \ - "one element can be converted to an index"); - return NULL; - } - return v->descr->f->getitem(v->data, v); -} -#endif - - -static PyNumberMethods array_as_number = { - (binaryfunc)array_add, /*nb_add*/ - (binaryfunc)array_subtract, /*nb_subtract*/ - (binaryfunc)array_multiply, /*nb_multiply*/ - (binaryfunc)array_divide, /*nb_divide*/ - (binaryfunc)array_remainder, /*nb_remainder*/ - (binaryfunc)array_divmod, /*nb_divmod*/ - (ternaryfunc)array_power, /*nb_power*/ - (unaryfunc)array_negative, /*nb_neg*/ - (unaryfunc)_array_copy_nice, /*nb_pos*/ - (unaryfunc)array_absolute, /*(unaryfunc)array_abs,*/ - (inquiry)_array_nonzero, /*nb_nonzero*/ - (unaryfunc)array_invert, /*nb_invert*/ - (binaryfunc)array_left_shift, /*nb_lshift*/ - (binaryfunc)array_right_shift, /*nb_rshift*/ - (binaryfunc)array_bitwise_and, /*nb_and*/ - (binaryfunc)array_bitwise_xor, /*nb_xor*/ - (binaryfunc)array_bitwise_or, /*nb_or*/ - 0, /*nb_coerce*/ - (unaryfunc)array_int, /*nb_int*/ - (unaryfunc)array_long, /*nb_long*/ - (unaryfunc)array_float, /*nb_float*/ - (unaryfunc)array_oct, /*nb_oct*/ - (unaryfunc)array_hex, /*nb_hex*/ - - /* - * This code adds augmented assignment functionality - * that was made available in Python 2.0 - */ - (binaryfunc)array_inplace_add, /*inplace_add*/ - (binaryfunc)array_inplace_subtract, /*inplace_subtract*/ - (binaryfunc)array_inplace_multiply, /*inplace_multiply*/ - (binaryfunc)array_inplace_divide, /*inplace_divide*/ - (binaryfunc)array_inplace_remainder, /*inplace_remainder*/ - (ternaryfunc)array_inplace_power, /*inplace_power*/ - (binaryfunc)array_inplace_left_shift, /*inplace_lshift*/ - (binaryfunc)array_inplace_right_shift, /*inplace_rshift*/ - (binaryfunc)array_inplace_bitwise_and, /*inplace_and*/ - (binaryfunc)array_inplace_bitwise_xor, /*inplace_xor*/ - (binaryfunc)array_inplace_bitwise_or, /*inplace_or*/ - - (binaryfunc)array_floor_divide, /*nb_floor_divide*/ - (binaryfunc)array_true_divide, /*nb_true_divide*/ - (binaryfunc)array_inplace_floor_divide, /*nb_inplace_floor_divide*/ - (binaryfunc)array_inplace_true_divide, /*nb_inplace_true_divide*/ - -#if PY_VERSION_HEX >= 0x02050000 - (unaryfunc)array_index, /* nb_index */ -#endif - -}; - -/****************** End of Buffer Protocol *******************************/ - - -/************************************************************************* **************** Implement Sequence Protocol ************************** *************************************************************************/ @@ -5244,877 +4443,6 @@ array_iter(PyArrayObject *arr) return PySeqIter_New((PyObject *)arr); } - -/******************* array attribute get and set routines ******************/ - -static PyObject * -array_ndim_get(PyArrayObject *self) -{ - return PyInt_FromLong(self->nd); -} - -static PyObject * -array_flags_get(PyArrayObject *self) -{ - return PyArray_NewFlagsObject((PyObject *)self); -} - -static PyObject * -array_shape_get(PyArrayObject *self) -{ - return PyArray_IntTupleFromIntp(self->nd, self->dimensions); -} - - -static int -array_shape_set(PyArrayObject *self, PyObject *val) -{ - int nd; - PyObject *ret; - - /* Assumes C-order */ - ret = PyArray_Reshape(self, val); - if (ret == NULL) { - return -1; - } - if (PyArray_DATA(ret) != PyArray_DATA(self)) { - Py_DECREF(ret); - PyErr_SetString(PyExc_AttributeError, - "incompatible shape for a non-contiguous "\ - "array"); - return -1; - } - - /* Free old dimensions and strides */ - PyDimMem_FREE(self->dimensions); - nd = PyArray_NDIM(ret); - self->nd = nd; - if (nd > 0) { - /* create new dimensions and strides */ - self->dimensions = PyDimMem_NEW(2*nd); - if (self->dimensions == NULL) { - Py_DECREF(ret); - PyErr_SetString(PyExc_MemoryError,""); - return -1; - } - self->strides = self->dimensions + nd; - memcpy(self->dimensions, PyArray_DIMS(ret), nd*sizeof(intp)); - memcpy(self->strides, PyArray_STRIDES(ret), nd*sizeof(intp)); - } - else { - self->dimensions = NULL; - self->strides = NULL; - } - Py_DECREF(ret); - PyArray_UpdateFlags(self, CONTIGUOUS | FORTRAN); - return 0; -} - - -static PyObject * -array_strides_get(PyArrayObject *self) -{ - return PyArray_IntTupleFromIntp(self->nd, self->strides); -} - -static int -array_strides_set(PyArrayObject *self, PyObject *obj) -{ - PyArray_Dims newstrides = {NULL, 0}; - PyArrayObject *new; - intp numbytes = 0; - intp offset = 0; - Py_ssize_t buf_len; - char *buf; - - if (!PyArray_IntpConverter(obj, &newstrides) || - newstrides.ptr == NULL) { - PyErr_SetString(PyExc_TypeError, "invalid strides"); - return -1; - } - if (newstrides.len != self->nd) { - PyErr_Format(PyExc_ValueError, "strides must be " \ - " same length as shape (%d)", self->nd); - goto fail; - } - new = self; - while(new->base && PyArray_Check(new->base)) { - new = (PyArrayObject *)(new->base); - } - /* - * Get the available memory through the buffer interface on - * new->base or if that fails from the current new - */ - if (new->base && PyObject_AsReadBuffer(new->base, - (const void **)&buf, - &buf_len) >= 0) { - offset = self->data - buf; - numbytes = buf_len + offset; - } - else { - PyErr_Clear(); - numbytes = PyArray_MultiplyList(new->dimensions, - new->nd)*new->descr->elsize; - offset = self->data - new->data; - } - - if (!PyArray_CheckStrides(self->descr->elsize, self->nd, numbytes, - offset, - self->dimensions, newstrides.ptr)) { - PyErr_SetString(PyExc_ValueError, "strides is not "\ - "compatible with available memory"); - goto fail; - } - memcpy(self->strides, newstrides.ptr, sizeof(intp)*newstrides.len); - PyArray_UpdateFlags(self, CONTIGUOUS | FORTRAN); - PyDimMem_FREE(newstrides.ptr); - return 0; - - fail: - PyDimMem_FREE(newstrides.ptr); - return -1; -} - - - -static PyObject * -array_priority_get(PyArrayObject *self) -{ - if (PyArray_CheckExact(self)) { - return PyFloat_FromDouble(PyArray_PRIORITY); - } - else { - return PyFloat_FromDouble(PyArray_SUBTYPE_PRIORITY); - } -} - -static PyObject * -array_typestr_get(PyArrayObject *self) -{ - return arraydescr_protocol_typestr_get(self->descr); -} - -static PyObject * -array_descr_get(PyArrayObject *self) -{ - Py_INCREF(self->descr); - return (PyObject *)self->descr; -} - -static PyObject * -array_protocol_descr_get(PyArrayObject *self) -{ - PyObject *res; - PyObject *dobj; - - res = arraydescr_protocol_descr_get(self->descr); - if (res) { - return res; - } - PyErr_Clear(); - - /* get default */ - dobj = PyTuple_New(2); - if (dobj == NULL) { - return NULL; - } - PyTuple_SET_ITEM(dobj, 0, PyString_FromString("")); - PyTuple_SET_ITEM(dobj, 1, array_typestr_get(self)); - res = PyList_New(1); - if (res == NULL) { - Py_DECREF(dobj); - return NULL; - } - PyList_SET_ITEM(res, 0, dobj); - return res; -} - -static PyObject * -array_protocol_strides_get(PyArrayObject *self) -{ - if PyArray_ISCONTIGUOUS(self) { - Py_INCREF(Py_None); - return Py_None; - } - return PyArray_IntTupleFromIntp(self->nd, self->strides); -} - - - -static PyObject * -array_dataptr_get(PyArrayObject *self) -{ - return Py_BuildValue("NO", - PyLong_FromVoidPtr(self->data), - (self->flags & WRITEABLE ? Py_False : - Py_True)); -} - -static PyObject * -array_ctypes_get(PyArrayObject *self) -{ - PyObject *_numpy_internal; - PyObject *ret; - _numpy_internal = PyImport_ImportModule("numpy.core._internal"); - if (_numpy_internal == NULL) { - return NULL; - } - ret = PyObject_CallMethod(_numpy_internal, "_ctypes", "ON", self, - PyLong_FromVoidPtr(self->data)); - Py_DECREF(_numpy_internal); - return ret; -} - -static PyObject * -array_interface_get(PyArrayObject *self) -{ - PyObject *dict; - PyObject *obj; - - dict = PyDict_New(); - if (dict == NULL) { - return NULL; - } - - /* dataptr */ - obj = array_dataptr_get(self); - PyDict_SetItemString(dict, "data", obj); - Py_DECREF(obj); - - obj = array_protocol_strides_get(self); - PyDict_SetItemString(dict, "strides", obj); - Py_DECREF(obj); - - obj = array_protocol_descr_get(self); - PyDict_SetItemString(dict, "descr", obj); - Py_DECREF(obj); - - obj = arraydescr_protocol_typestr_get(self->descr); - PyDict_SetItemString(dict, "typestr", obj); - Py_DECREF(obj); - - obj = array_shape_get(self); - PyDict_SetItemString(dict, "shape", obj); - Py_DECREF(obj); - - obj = PyInt_FromLong(3); - PyDict_SetItemString(dict, "version", obj); - Py_DECREF(obj); - - return dict; -} - -static PyObject * -array_data_get(PyArrayObject *self) -{ - intp nbytes; - if (!(PyArray_ISONESEGMENT(self))) { - PyErr_SetString(PyExc_AttributeError, "cannot get single-"\ - "segment buffer for discontiguous array"); - return NULL; - } - nbytes = PyArray_NBYTES(self); - if PyArray_ISWRITEABLE(self) { - return PyBuffer_FromReadWriteObject((PyObject *)self, 0, (Py_ssize_t) nbytes); - } - else { - return PyBuffer_FromObject((PyObject *)self, 0, (Py_ssize_t) nbytes); - } -} - -static int -array_data_set(PyArrayObject *self, PyObject *op) -{ - void *buf; - Py_ssize_t buf_len; - int writeable=1; - - if (PyObject_AsWriteBuffer(op, &buf, &buf_len) < 0) { - writeable = 0; - if (PyObject_AsReadBuffer(op, (const void **)&buf, &buf_len) < 0) { - PyErr_SetString(PyExc_AttributeError, - "object does not have single-segment " \ - "buffer interface"); - return -1; - } - } - if (!PyArray_ISONESEGMENT(self)) { - PyErr_SetString(PyExc_AttributeError, "cannot set single-" \ - "segment buffer for discontiguous array"); - return -1; - } - if (PyArray_NBYTES(self) > buf_len) { - PyErr_SetString(PyExc_AttributeError, "not enough data for array"); - return -1; - } - if (self->flags & OWNDATA) { - PyArray_XDECREF(self); - PyDataMem_FREE(self->data); - } - if (self->base) { - if (self->flags & UPDATEIFCOPY) { - ((PyArrayObject *)self->base)->flags |= WRITEABLE; - self->flags &= ~UPDATEIFCOPY; - } - Py_DECREF(self->base); - } - Py_INCREF(op); - self->base = op; - self->data = buf; - self->flags = CARRAY; - if (!writeable) { - self->flags &= ~WRITEABLE; - } - return 0; -} - - -static PyObject * -array_itemsize_get(PyArrayObject *self) -{ - return PyInt_FromLong((long) self->descr->elsize); -} - -static PyObject * -array_size_get(PyArrayObject *self) -{ - intp size=PyArray_SIZE(self); -#if SIZEOF_INTP <= SIZEOF_LONG - return PyInt_FromLong((long) size); -#else - if (size > MAX_LONG || size < MIN_LONG) { - return PyLong_FromLongLong(size); - } - else { - return PyInt_FromLong((long) size); - } -#endif -} - -static PyObject * -array_nbytes_get(PyArrayObject *self) -{ - intp nbytes = PyArray_NBYTES(self); -#if SIZEOF_INTP <= SIZEOF_LONG - return PyInt_FromLong((long) nbytes); -#else - if (nbytes > MAX_LONG || nbytes < MIN_LONG) { - return PyLong_FromLongLong(nbytes); - } - else { - return PyInt_FromLong((long) nbytes); - } -#endif -} - - -/* - * If the type is changed. - * Also needing change: strides, itemsize - * - * Either itemsize is exactly the same or the array is single-segment - * (contiguous or fortran) with compatibile dimensions The shape and strides - * will be adjusted in that case as well. - */ - -static int -array_descr_set(PyArrayObject *self, PyObject *arg) -{ - PyArray_Descr *newtype = NULL; - intp newdim; - int index; - char *msg = "new type not compatible with array."; - - if (!(PyArray_DescrConverter(arg, &newtype)) || - newtype == NULL) { - PyErr_SetString(PyExc_TypeError, "invalid data-type for array"); - return -1; - } - if (PyDataType_FLAGCHK(newtype, NPY_ITEM_HASOBJECT) || - PyDataType_FLAGCHK(newtype, NPY_ITEM_IS_POINTER) || - PyDataType_FLAGCHK(self->descr, NPY_ITEM_HASOBJECT) || - PyDataType_FLAGCHK(self->descr, NPY_ITEM_IS_POINTER)) { - PyErr_SetString(PyExc_TypeError, \ - "Cannot change data-type for object " \ - "array."); - Py_DECREF(newtype); - return -1; - } - - if (newtype->elsize == 0) { - PyErr_SetString(PyExc_TypeError, - "data-type must not be 0-sized"); - Py_DECREF(newtype); - return -1; - } - - - if ((newtype->elsize != self->descr->elsize) && - (self->nd == 0 || !PyArray_ISONESEGMENT(self) || - newtype->subarray)) { - goto fail; - } - if (PyArray_ISCONTIGUOUS(self)) { - index = self->nd - 1; - } - else { - index = 0; - } - if (newtype->elsize < self->descr->elsize) { - /* - * if it is compatible increase the size of the - * dimension at end (or at the front for FORTRAN) - */ - if (self->descr->elsize % newtype->elsize != 0) { - goto fail; - } - newdim = self->descr->elsize / newtype->elsize; - self->dimensions[index] *= newdim; - self->strides[index] = newtype->elsize; - } - else if (newtype->elsize > self->descr->elsize) { - /* - * Determine if last (or first if FORTRAN) dimension - * is compatible - */ - newdim = self->dimensions[index] * self->descr->elsize; - if ((newdim % newtype->elsize) != 0) { - goto fail; - } - self->dimensions[index] = newdim / newtype->elsize; - self->strides[index] = newtype->elsize; - } - - /* fall through -- adjust type*/ - Py_DECREF(self->descr); - if (newtype->subarray) { - /* - * create new array object from data and update - * dimensions, strides and descr from it - */ - PyArrayObject *temp; - /* - * We would decref newtype here. - * temp will steal a reference to it - */ - temp = (PyArrayObject *) - PyArray_NewFromDescr(&PyArray_Type, newtype, self->nd, - self->dimensions, self->strides, - self->data, self->flags, NULL); - if (temp == NULL) { - return -1; - } - PyDimMem_FREE(self->dimensions); - self->dimensions = temp->dimensions; - self->nd = temp->nd; - self->strides = temp->strides; - newtype = temp->descr; - Py_INCREF(temp->descr); - /* Fool deallocator not to delete these*/ - temp->nd = 0; - temp->dimensions = NULL; - Py_DECREF(temp); - } - - self->descr = newtype; - PyArray_UpdateFlags(self, UPDATE_ALL); - return 0; - - fail: - PyErr_SetString(PyExc_ValueError, msg); - Py_DECREF(newtype); - return -1; -} - -static PyObject * -array_struct_get(PyArrayObject *self) -{ - PyArrayInterface *inter; - - inter = (PyArrayInterface *)_pya_malloc(sizeof(PyArrayInterface)); - if (inter==NULL) { - return PyErr_NoMemory(); - } - inter->two = 2; - inter->nd = self->nd; - inter->typekind = self->descr->kind; - inter->itemsize = self->descr->elsize; - inter->flags = self->flags; - /* reset unused flags */ - inter->flags &= ~(UPDATEIFCOPY | OWNDATA); - if (PyArray_ISNOTSWAPPED(self)) inter->flags |= NOTSWAPPED; - /* - * Copy shape and strides over since these can be reset - *when the array is "reshaped". - */ - if (self->nd > 0) { - inter->shape = (intp *)_pya_malloc(2*sizeof(intp)*self->nd); - if (inter->shape == NULL) { - _pya_free(inter); - return PyErr_NoMemory(); - } - inter->strides = inter->shape + self->nd; - memcpy(inter->shape, self->dimensions, sizeof(intp)*self->nd); - memcpy(inter->strides, self->strides, sizeof(intp)*self->nd); - } - else { - inter->shape = NULL; - inter->strides = NULL; - } - inter->data = self->data; - if (self->descr->names) { - inter->descr = arraydescr_protocol_descr_get(self->descr); - if (inter->descr == NULL) { - PyErr_Clear(); - } - else { - inter->flags &= ARR_HAS_DESCR; - } - } - else { - inter->descr = NULL; - } - Py_INCREF(self); - return PyCObject_FromVoidPtrAndDesc(inter, self, gentype_struct_free); -} - -static PyObject * -array_base_get(PyArrayObject *self) -{ - if (self->base == NULL) { - Py_INCREF(Py_None); - return Py_None; - } - else { - Py_INCREF(self->base); - return self->base; - } -} - - -NPY_NO_EXPORT int -_zerofill(PyArrayObject *ret) -{ - if (PyDataType_REFCHK(ret->descr)) { - PyObject *zero = PyInt_FromLong(0); - PyArray_FillObjectArray(ret, zero); - Py_DECREF(zero); - if (PyErr_Occurred()) { - Py_DECREF(ret); - return -1; - } - } - else { - intp n = PyArray_NBYTES(ret); - memset(ret->data, 0, n); - } - return 0; -} - - -/* - * Create a view of a complex array with an equivalent data-type - * except it is real instead of complex. - */ -static PyArrayObject * -_get_part(PyArrayObject *self, int imag) -{ - PyArray_Descr *type; - PyArrayObject *ret; - int offset; - - type = PyArray_DescrFromType(self->descr->type_num - - PyArray_NUM_FLOATTYPE); - offset = (imag ? type->elsize : 0); - - if (!PyArray_ISNBO(self->descr->byteorder)) { - PyArray_Descr *new; - new = PyArray_DescrNew(type); - new->byteorder = self->descr->byteorder; - Py_DECREF(type); - type = new; - } - ret = (PyArrayObject *) - PyArray_NewFromDescr(self->ob_type, - type, - self->nd, - self->dimensions, - self->strides, - self->data + offset, - self->flags, (PyObject *)self); - if (ret == NULL) { - return NULL; - } - ret->flags &= ~CONTIGUOUS; - ret->flags &= ~FORTRAN; - Py_INCREF(self); - ret->base = (PyObject *)self; - return ret; -} - -static PyObject * -array_real_get(PyArrayObject *self) -{ - PyArrayObject *ret; - - if (PyArray_ISCOMPLEX(self)) { - ret = _get_part(self, 0); - return (PyObject *)ret; - } - else { - Py_INCREF(self); - return (PyObject *)self; - } -} - - -static int -array_real_set(PyArrayObject *self, PyObject *val) -{ - PyArrayObject *ret; - PyArrayObject *new; - int rint; - - if (PyArray_ISCOMPLEX(self)) { - ret = _get_part(self, 0); - if (ret == NULL) { - return -1; - } - } - else { - Py_INCREF(self); - ret = self; - } - new = (PyArrayObject *)PyArray_FromAny(val, NULL, 0, 0, 0, NULL); - if (new == NULL) { - Py_DECREF(ret); - return -1; - } - rint = PyArray_MoveInto(ret, new); - Py_DECREF(ret); - Py_DECREF(new); - return rint; -} - -static PyObject * -array_imag_get(PyArrayObject *self) -{ - PyArrayObject *ret; - - if (PyArray_ISCOMPLEX(self)) { - ret = _get_part(self, 1); - } - else { - Py_INCREF(self->descr); - ret = (PyArrayObject *)PyArray_NewFromDescr(self->ob_type, - self->descr, - self->nd, - self->dimensions, - NULL, NULL, - PyArray_ISFORTRAN(self), - (PyObject *)self); - if (ret == NULL) { - return NULL; - } - if (_zerofill(ret) < 0) { - return NULL; - } - ret->flags &= ~WRITEABLE; - } - return (PyObject *) ret; -} - -static int -array_imag_set(PyArrayObject *self, PyObject *val) -{ - if (PyArray_ISCOMPLEX(self)) { - PyArrayObject *ret; - PyArrayObject *new; - int rint; - - ret = _get_part(self, 1); - if (ret == NULL) { - return -1; - } - new = (PyArrayObject *)PyArray_FromAny(val, NULL, 0, 0, 0, NULL); - if (new == NULL) { - Py_DECREF(ret); - return -1; - } - rint = PyArray_MoveInto(ret, new); - Py_DECREF(ret); - Py_DECREF(new); - return rint; - } - else { - PyErr_SetString(PyExc_TypeError, "array does not have "\ - "imaginary part to set"); - return -1; - } -} - -static PyObject * -array_flat_get(PyArrayObject *self) -{ - return PyArray_IterNew((PyObject *)self); -} - -static int -array_flat_set(PyArrayObject *self, PyObject *val) -{ - PyObject *arr = NULL; - int retval = -1; - PyArrayIterObject *selfit = NULL, *arrit = NULL; - PyArray_Descr *typecode; - int swap; - PyArray_CopySwapFunc *copyswap; - - typecode = self->descr; - Py_INCREF(typecode); - arr = PyArray_FromAny(val, typecode, - 0, 0, FORCECAST | FORTRAN_IF(self), NULL); - if (arr == NULL) { - return -1; - } - arrit = (PyArrayIterObject *)PyArray_IterNew(arr); - if (arrit == NULL) { - goto exit; - } - selfit = (PyArrayIterObject *)PyArray_IterNew((PyObject *)self); - if (selfit == NULL) { - goto exit; - } - if (arrit->size == 0) { - retval = 0; - goto exit; - } - swap = PyArray_ISNOTSWAPPED(self) != PyArray_ISNOTSWAPPED(arr); - copyswap = self->descr->f->copyswap; - if (PyDataType_REFCHK(self->descr)) { - while (selfit->index < selfit->size) { - PyArray_Item_XDECREF(selfit->dataptr, self->descr); - PyArray_Item_INCREF(arrit->dataptr, PyArray_DESCR(arr)); - memmove(selfit->dataptr, arrit->dataptr, sizeof(PyObject **)); - if (swap) { - copyswap(selfit->dataptr, NULL, swap, self); - } - PyArray_ITER_NEXT(selfit); - PyArray_ITER_NEXT(arrit); - if (arrit->index == arrit->size) { - PyArray_ITER_RESET(arrit); - } - } - retval = 0; - goto exit; - } - - while(selfit->index < selfit->size) { - memmove(selfit->dataptr, arrit->dataptr, self->descr->elsize); - if (swap) { - copyswap(selfit->dataptr, NULL, swap, self); - } - PyArray_ITER_NEXT(selfit); - PyArray_ITER_NEXT(arrit); - if (arrit->index == arrit->size) { - PyArray_ITER_RESET(arrit); - } - } - retval = 0; - - exit: - Py_XDECREF(selfit); - Py_XDECREF(arrit); - Py_XDECREF(arr); - return retval; -} - -static PyObject * -array_transpose_get(PyArrayObject *self) -{ - return PyArray_Transpose(self, NULL); -} - -/* If this is None, no function call is made - --- default sub-class behavior -*/ -static PyObject * -array_finalize_get(PyArrayObject *NPY_UNUSED(self)) -{ - Py_INCREF(Py_None); - return Py_None; -} - -static PyGetSetDef array_getsetlist[] = { - {"ndim", - (getter)array_ndim_get, - NULL, NULL, NULL}, - {"flags", - (getter)array_flags_get, - NULL, NULL, NULL}, - {"shape", - (getter)array_shape_get, - (setter)array_shape_set, - NULL, NULL}, - {"strides", - (getter)array_strides_get, - (setter)array_strides_set, - NULL, NULL}, - {"data", - (getter)array_data_get, - (setter)array_data_set, - NULL, NULL}, - {"itemsize", - (getter)array_itemsize_get, - NULL, NULL, NULL}, - {"size", - (getter)array_size_get, - NULL, NULL, NULL}, - {"nbytes", - (getter)array_nbytes_get, - NULL, NULL, NULL}, - {"base", - (getter)array_base_get, - NULL, NULL, NULL}, - {"dtype", - (getter)array_descr_get, - (setter)array_descr_set, - NULL, NULL}, - {"real", - (getter)array_real_get, - (setter)array_real_set, - NULL, NULL}, - {"imag", - (getter)array_imag_get, - (setter)array_imag_set, - NULL, NULL}, - {"flat", - (getter)array_flat_get, - (setter)array_flat_set, - NULL, NULL}, - {"ctypes", - (getter)array_ctypes_get, - NULL, NULL, NULL}, - {"T", - (getter)array_transpose_get, - NULL, NULL, NULL}, - {"__array_interface__", - (getter)array_interface_get, - NULL, NULL, NULL}, - {"__array_struct__", - (getter)array_struct_get, - NULL, NULL, NULL}, - {"__array_priority__", - (getter)array_priority_get, - NULL, NULL, NULL}, - {"__array_finalize__", - (getter)array_finalize_get, - NULL, NULL, NULL}, - {NULL, NULL, NULL, NULL, NULL}, /* Sentinel */ -}; - -/****************** end of attribute get and set routines *******************/ - - static PyObject * array_alloc(PyTypeObject *type, Py_ssize_t NPY_UNUSED(nitems)) { diff --git a/numpy/core/src/arrayobject.h b/numpy/core/src/arrayobject.h index bedbf6223..cd66e9108 100644 --- a/numpy/core/src/arrayobject.h +++ b/numpy/core/src/arrayobject.h @@ -42,7 +42,6 @@ typedef struct { PyObject *conjugate; } NumericOps; -extern NPY_NO_EXPORT NumericOps n_ops; extern NPY_NO_EXPORT PyArray_Descr **userdescrs; @@ -146,4 +145,7 @@ set_typeinfo(PyObject *dict); extern NPY_NO_EXPORT PyArray_Descr LONG_Descr; extern NPY_NO_EXPORT PyArray_Descr INT_Descr; +/* Number protocol */ +#include "arraynumber.h" + #endif |