Skip to content

Commit

Permalink
ENH: core: Add dtype= and order= parameters to zeros_like, ones_like,…
Browse files Browse the repository at this point in the history
… and empty_like
  • Loading branch information
mwiebe committed Jan 28, 2011
1 parent 6510cce commit c9d1849
Show file tree
Hide file tree
Showing 10 changed files with 249 additions and 109 deletions.
52 changes: 52 additions & 0 deletions numpy/add_newdocs.py
Expand Up @@ -413,6 +413,58 @@
""")

add_newdoc('numpy.core.multiarray', 'empty_like',
"""
empty_like(a, dtype=None, order='K')
Return a new array with the same shape and type as a given array.
Parameters
----------
a : array_like
The shape and data-type of `a` define these same attributes of the
returned array.
dtype : data-type, optional
Overrides the data type of the result.
order : {'C', 'F', 'A', or 'K'}, optional
Overrides the memory layout of the result. 'C' means C-order,
'F' means F-order, 'A' means 'F' if ``a`` is Fortran contiguous,
'C' otherwise. 'K' means match the layout of ``a`` as closely
as possible.
Returns
-------
out : ndarray
Array of uninitialized (arbitrary) data with the same
shape and type as `a`.
See Also
--------
ones_like : Return an array of ones with shape and type of input.
zeros_like : Return an array of zeros with shape and type of input.
empty : Return a new uninitialized array.
ones : Return a new array setting values to one.
zeros : Return a new array setting values to zero.
Notes
-----
This function does *not* initialize the returned array; to do that use
`zeros_like` or `ones_like` instead. It may be marginally faster than
the functions that do set the array values.
Examples
--------
>>> a = ([1,2,3], [4,5,6]) # a is array-like
>>> np.empty_like(a)
array([[-1073741821, -1073741821, 3], #random
[ 0, 0, -1073741821]])
>>> a = np.array([[1., 2., 3.],[4.,5.,6.]])
>>> np.empty_like(a)
array([[ -2.00000715e+000, 1.48219694e-323, -2.00000572e+000],#random
[ 4.38791518e-305, -2.00000715e+000, 4.17269252e-309]])
""")


add_newdoc('numpy.core.multiarray', 'scalar',
"""
Expand Down
80 changes: 12 additions & 68 deletions numpy/core/numeric.py
Expand Up @@ -62,17 +62,24 @@ class ComplexWarning(RuntimeWarning):


# originally from Fernando Perez's IPython
def zeros_like(a):
def zeros_like(a, dtype=None, order='K'):
"""
Return an array of zeros with the same shape and type as a given array.
Equivalent to ``a.copy().fill(0)``.
With default paramters, is equivalent to ``a.copy().fill(0)``.
Parameters
----------
a : array_like
The shape and data-type of `a` define these same attributes of
the returned array.
dtype : data-type, optional
Overrides the data type of the result.
order : {'C', 'F', 'A', or 'K'}, optional
Overrides the memory layout of the result. 'C' means C-order,
'F' means F-order, 'A' means 'F' if ``a`` is Fortran contiguous,
'C' otherwise. 'K' means match the layout of ``a`` as closely
as possible.
Returns
-------
Expand Down Expand Up @@ -105,72 +112,8 @@ def zeros_like(a):
array([ 0., 0., 0.])
"""
if isinstance(a, ndarray):
res = ndarray.__new__(type(a), a.shape, a.dtype, order=a.flags.fnc)
res.fill(0)
return res
try:
wrap = a.__array_wrap__
except AttributeError:
wrap = None
a = asarray(a)
res = zeros(a.shape, a.dtype)
if wrap:
res = wrap(res)
return res

def empty_like(a):
"""
Return a new array with the same shape and type as a given array.
Parameters
----------
a : array_like
The shape and data-type of `a` define these same attributes of the
returned array.
Returns
-------
out : ndarray
Array of random data with the same shape and type as `a`.
See Also
--------
ones_like : Return an array of ones with shape and type of input.
zeros_like : Return an array of zeros with shape and type of input.
empty : Return a new uninitialized array.
ones : Return a new array setting values to one.
zeros : Return a new array setting values to zero.
Notes
-----
This function does *not* initialize the returned array; to do that use
`zeros_like` or `ones_like` instead. It may be marginally faster than
the functions that do set the array values.
Examples
--------
>>> a = ([1,2,3], [4,5,6]) # a is array-like
>>> np.empty_like(a)
array([[-1073741821, -1073741821, 3], #random
[ 0, 0, -1073741821]])
>>> a = np.array([[1., 2., 3.],[4.,5.,6.]])
>>> np.empty_like(a)
array([[ -2.00000715e+000, 1.48219694e-323, -2.00000572e+000],#random
[ 4.38791518e-305, -2.00000715e+000, 4.17269252e-309]])
"""
if isinstance(a, ndarray):
res = ndarray.__new__(type(a), a.shape, a.dtype, order=a.flags.fnc)
return res
try:
wrap = a.__array_wrap__
except AttributeError:
wrap = None
a = asarray(a)
res = empty(a.shape, a.dtype)
if wrap:
res = wrap(res)
res = empty_like(a, dtype=dtype, order=order)
res.fill(0)
return res

# end Fernando's utilities
Expand Down Expand Up @@ -199,6 +142,7 @@ def extend_all(module):
zeros = multiarray.zeros
count_nonzero = multiarray.count_nonzero
empty = multiarray.empty
empty_like = multiarray.empty_like
fromstring = multiarray.fromstring
fromiter = multiarray.fromiter
fromfile = multiarray.fromfile
Expand Down
1 change: 1 addition & 0 deletions numpy/core/src/multiarray/ctors.c
Expand Up @@ -1140,6 +1140,7 @@ PyArray_NewFromDescr(PyTypeObject *subtype, PyArray_Descr *descr, int nd,
}
else {
self->dimensions = self->strides = NULL;
self->flags |= FORTRAN;
}

if (data == NULL) {
Expand Down
2 changes: 1 addition & 1 deletion numpy/core/src/multiarray/methods.c
Expand Up @@ -915,7 +915,7 @@ array_getarray(PyArrayObject *self, PyObject *args)
static PyObject *
array_copy(PyArrayObject *self, PyObject *args, PyObject *kwds)
{
PyArray_ORDER order=PyArray_CORDER;
PyArray_ORDER order = PyArray_CORDER;
static char *kwlist[] = {"order", NULL};

if (!PyArg_ParseTupleAndKeywords(args, kwds, "|O&", kwlist,
Expand Down
71 changes: 59 additions & 12 deletions numpy/core/src/multiarray/multiarraymodule.c
Expand Up @@ -1208,8 +1208,9 @@ NPY_NO_EXPORT int
PyArray_OrderConverter(PyObject *object, NPY_ORDER *val)
{
char *str;
/* Leave the desired default from the caller for NULL/Py_None */
if (object == NULL || object == Py_None) {
*val = NPY_ANYORDER;
return PY_SUCCEED;
}
else if (PyUnicode_Check(object)) {
PyObject *tmp;
Expand Down Expand Up @@ -1513,7 +1514,7 @@ _array_fromobject(PyObject *NPY_UNUSED(ignored), PyObject *args, PyObject *kws)
int ndmin = 0, nd;
PyArray_Descr *type = NULL;
PyArray_Descr *oldtype = NULL;
NPY_ORDER order=NPY_ANYORDER;
NPY_ORDER order = NPY_ANYORDER;
int flags = 0;

if (PyTuple_GET_SIZE(args) > 2) {
Expand Down Expand Up @@ -1623,12 +1624,20 @@ array_empty(PyObject *NPY_UNUSED(ignored), PyObject *args, PyObject *kwds)
PyArray_OrderConverter, &order)) {
goto fail;
}
if (order == NPY_FORTRANORDER) {
fortran = TRUE;
}
else {
fortran = FALSE;

switch (order) {
case NPY_CORDER:
fortran = FALSE;
break;
case NPY_FORTRANORDER:
fortran = TRUE;
break;
default:
PyErr_SetString(PyExc_ValueError,
"only 'C' or 'F' order is permitted");
goto fail;
}

ret = PyArray_Empty(shape.len, shape.ptr, typecode, fortran);
PyDimMem_FREE(shape.ptr);
return ret;
Expand All @@ -1639,6 +1648,33 @@ array_empty(PyObject *NPY_UNUSED(ignored), PyObject *args, PyObject *kwds)
return NULL;
}

static PyObject *
array_empty_like(PyObject *NPY_UNUSED(ignored), PyObject *args, PyObject *kwds)
{

static char *kwlist[] = {"prototype","dtype","order",NULL};
PyArrayObject *prototype = NULL;
PyArray_Descr *dtype = NULL;
NPY_ORDER order = NPY_KEEPORDER;
PyObject *ret = NULL;

if (!PyArg_ParseTupleAndKeywords(args, kwds, "O&|O&O&", kwlist,
PyArray_Converter, &prototype,
PyArray_DescrConverter2, &dtype,
PyArray_OrderConverter, &order)) {
goto fail;
}
/* steals the reference to dtype if it's not NULL */
ret = PyArray_NewLikeArray(prototype, order, dtype);
Py_DECREF(prototype);
return ret;

fail:
Py_XDECREF(prototype);
Py_XDECREF(dtype);
return NULL;
}

/*
* This function is needed for supporting Pickles of
* numpy scalar objects.
Expand Down Expand Up @@ -1719,12 +1755,20 @@ array_zeros(PyObject *NPY_UNUSED(ignored), PyObject *args, PyObject *kwds)
PyArray_OrderConverter, &order)) {
goto fail;
}
if (order == NPY_FORTRANORDER) {
fortran = TRUE;
}
else {
fortran = FALSE;

switch (order) {
case NPY_CORDER:
fortran = FALSE;
break;
case NPY_FORTRANORDER:
fortran = TRUE;
break;
default:
PyErr_SetString(PyExc_ValueError,
"only 'C' or 'F' order is permitted");
goto fail;
}

ret = PyArray_Zeros(shape.len, shape.ptr, typecode, (int) fortran);
PyDimMem_FREE(shape.ptr);
return ret;
Expand Down Expand Up @@ -3040,6 +3084,9 @@ static struct PyMethodDef array_module_methods[] = {
{"empty",
(PyCFunction)array_empty,
METH_VARARGS|METH_KEYWORDS, NULL},
{"empty_like",
(PyCFunction)array_empty_like,
METH_VARARGS|METH_KEYWORDS, NULL},
{"scalar",
(PyCFunction)array_scalar,
METH_VARARGS|METH_KEYWORDS, NULL},
Expand Down
7 changes: 1 addition & 6 deletions numpy/core/src/multiarray/new_iterator.c.src
Expand Up @@ -3917,11 +3917,6 @@ npyiter_reverse_axis_ordering(NpyIter *iter)
npy_intp *first, *last;
char *perm;

/* Need at least two dimensions for reversing to change things */
if (ndim < 2) {
return;
}

size = NIT_AXISDATA_SIZEOF(itflags, ndim, niter)/NPY_SIZEOF_INTP;
first = (npy_intp*)NIT_AXISDATA(iter);
last = first + (ndim-1)*size;
Expand All @@ -3939,7 +3934,7 @@ npyiter_reverse_axis_ordering(NpyIter *iter)

/* Store the perm we applied */
perm = NIT_PERM(iter);
for(i = ndim-1; i >= 0; --i, ++first) {
for(i = ndim-1; i >= 0; --i, ++perm) {
*perm = (char)i;
}

Expand Down
18 changes: 9 additions & 9 deletions numpy/core/src/multiarray/shape.c
Expand Up @@ -174,7 +174,7 @@ PyArray_Resize(PyArrayObject *self, PyArray_Dims *newshape, int refcheck,
*/
NPY_NO_EXPORT PyObject *
PyArray_Newshape(PyArrayObject *self, PyArray_Dims *newdims,
NPY_ORDER fortran)
NPY_ORDER order)
{
intp i;
intp *dimensions = newdims->ptr;
Expand All @@ -185,8 +185,8 @@ PyArray_Newshape(PyArrayObject *self, PyArray_Dims *newdims,
intp newstrides[MAX_DIMS];
int flags;

if (fortran == PyArray_ANYORDER) {
fortran = PyArray_ISFORTRAN(self);
if (order == PyArray_ANYORDER) {
order = PyArray_ISFORTRAN(self);
}
/* Quick check to make sure anything actually needs to be done */
if (n == self->nd) {
Expand Down Expand Up @@ -233,20 +233,20 @@ PyArray_Newshape(PyArrayObject *self, PyArray_Dims *newdims,
*/
if (!(PyArray_ISONESEGMENT(self)) ||
(((PyArray_CHKFLAGS(self, NPY_CONTIGUOUS) &&
fortran == NPY_FORTRANORDER) ||
order == NPY_FORTRANORDER) ||
(PyArray_CHKFLAGS(self, NPY_FORTRAN) &&
fortran == NPY_CORDER)) && (self->nd > 1))) {
order == NPY_CORDER)) && (self->nd > 1))) {
int success = 0;
success = _attempt_nocopy_reshape(self,n,dimensions,
newstrides,fortran);
newstrides,order);
if (success) {
/* no need to copy the array after all */
strides = newstrides;
flags = self->flags;
}
else {
PyObject *new;
new = PyArray_NewCopy(self, fortran);
new = PyArray_NewCopy(self, order);
if (new == NULL) {
return NULL;
}
Expand All @@ -260,7 +260,7 @@ PyArray_Newshape(PyArrayObject *self, PyArray_Dims *newdims,

/* Make sure the flags argument is set. */
if (n > 1) {
if (fortran == NPY_FORTRANORDER) {
if (order == NPY_FORTRANORDER) {
flags &= ~NPY_CONTIGUOUS;
flags |= NPY_FORTRAN;
}
Expand All @@ -275,7 +275,7 @@ PyArray_Newshape(PyArrayObject *self, PyArray_Dims *newdims,
* replace any 0-valued strides with
* appropriate value to preserve contiguousness
*/
if (fortran == PyArray_FORTRANORDER) {
if (order == NPY_FORTRANORDER) {
if (strides[0] == 0) {
strides[0] = self->descr->elsize;
}
Expand Down

0 comments on commit c9d1849

Please sign in to comment.