diff options
Diffstat (limited to 'numpy')
-rw-r--r-- | numpy/core/SConscript | 1 | ||||
-rw-r--r-- | numpy/core/setup.py | 2 | ||||
-rw-r--r-- | numpy/core/src/multiarray/array_assign.c | 191 | ||||
-rw-r--r-- | numpy/core/src/multiarray/array_assign.h | 71 | ||||
-rw-r--r-- | numpy/core/src/multiarray/convert_datatype.c | 95 | ||||
-rw-r--r-- | numpy/core/src/multiarray/convert_datatype.h | 5 | ||||
-rw-r--r-- | numpy/core/src/multiarray/na_mask.c | 5 | ||||
-rw-r--r-- | numpy/core/src/umath/ufunc_object.c | 55 |
8 files changed, 383 insertions, 42 deletions
diff --git a/numpy/core/SConscript b/numpy/core/SConscript index 339b604a9..60fde8e30 100644 --- a/numpy/core/SConscript +++ b/numpy/core/SConscript @@ -443,6 +443,7 @@ if ENABLE_SEPARATE_COMPILATION: multiarray_src = [pjoin('src', 'multiarray', 'multiarraymodule.c'), pjoin('src', 'multiarray', 'hashdescr.c'), pjoin('src', 'multiarray', 'arrayobject.c'), + pjoin('src', 'multiarray', 'array_assign.c'), pjoin('src', 'multiarray', 'datetime.c'), pjoin('src', 'multiarray', 'datetime_strings.c'), pjoin('src', 'multiarray', 'datetime_busday.c'), diff --git a/numpy/core/setup.py b/numpy/core/setup.py index afe52f54f..c721cf219 100644 --- a/numpy/core/setup.py +++ b/numpy/core/setup.py @@ -700,6 +700,7 @@ def configuration(parent_package='',top_path=None): multiarray_deps = [ join('src', 'multiarray', 'arrayobject.h'), join('src', 'multiarray', 'arraytypes.h'), + join('src', 'multiarray', 'array_assign.h'), join('src', 'multiarray', 'buffer.h'), join('src', 'multiarray', 'calculation.h'), join('src', 'multiarray', 'common.h'), @@ -750,6 +751,7 @@ def configuration(parent_package='',top_path=None): multiarray_src = [ join('src', 'multiarray', 'arrayobject.c'), join('src', 'multiarray', 'arraytypes.c.src'), + join('src', 'multiarray', 'array_assign.c'), join('src', 'multiarray', 'buffer.c'), join('src', 'multiarray', 'calculation.c'), join('src', 'multiarray', 'common.c'), diff --git a/numpy/core/src/multiarray/array_assign.c b/numpy/core/src/multiarray/array_assign.c new file mode 100644 index 000000000..7ef80ca3b --- /dev/null +++ b/numpy/core/src/multiarray/array_assign.c @@ -0,0 +1,191 @@ +/* + * This file implements several array assignment routines. + * + * Written by Mark Wiebe (mwwiebe@gmail.com) + * Copyright (c) 2011 by Enthought, Inc. + * + * See LICENSE.txt for the license. + */ + +#define PY_SSIZE_T_CLEAN +#include <Python.h> + +#define NPY_NO_DEPRECATED_API +#define _MULTIARRAYMODULE +#include <numpy/ndarraytypes.h> + +#include "npy_config.h" +#include "numpy/npy_3kcompat.h" + +#include "convert_datatype.h" +#include "methods.h" +#include "lowlevel_strided_loops.h" +#include "array_assign.h" + + +/* + * Assigns the scalar value to every element of the destination raw array. + * + * Returns 0 on success, -1 on failure. + */ +static int +raw_array_assign_scalar(int ndim, npy_intp *shape, + PyArray_Descr *dst_dtype, char *dst_data, npy_intp *dst_strides, + PyArray_Descr *src_dtype, char *src_data) +{ + int idim; + npy_intp shape_it[NPY_MAXDIMS], dst_strides_it[NPY_MAXDIMS]; + npy_intp coord[NPY_MAXDIMS]; + NPY_BEGIN_THREADS_DEF; + + PyArray_StridedTransferFn *stransfer = NULL; + NpyAuxData *transferdata = NULL; + int aligned = 1, needs_api = 0; + npy_intp src_itemsize = src_dtype->elsize; + + /* Check alignment */ + if (dst_dtype->alignment > 1) { + npy_intp align_check = (npy_intp)dst_data; + for (idim = 0; idim < ndim; ++idim) { + align_check |= dst_strides[idim]; + } + if ((align_check & (dst_dtype->alignment - 1)) != 0) { + aligned = 0; + } + } + if (((npy_intp)src_data & (src_dtype->alignment - 1)) != 0) { + aligned = 0; + } + + /* Use raw iteration with no heap allocation */ + if (PyArray_PrepareOneRawArrayIter( + ndim, shape, + dst_data, dst_strides, + &ndim, shape_it, + &dst_data, dst_strides_it) < 0) { + return -1; + } + + /* Get the function to do the casting */ + if (PyArray_GetDTypeTransferFunction(aligned, + 0, dst_strides_it[0], + src_dtype, dst_dtype, + 0, + &stransfer, &transferdata, + &needs_api) != NPY_SUCCEED) { + return -1; + } + + if (!needs_api) { + NPY_BEGIN_THREADS; + } + + NPY_RAW_ITER_START(idim, ndim, coord, shape_it) { + /* Process the innermost dimension */ + stransfer(dst_data, dst_strides_it[0], src_data, 0, + shape_it[0], src_itemsize, transferdata); + } NPY_RAW_ITER_ONE_NEXT(idim, ndim, coord, + shape_it, dst_data, dst_strides_it); + + if (!needs_api) { + NPY_END_THREADS; + } + + NPY_AUXDATA_FREE(transferdata); + + return (needs_api && PyErr_Occurred()) ? -1 : 0; +} + +/* See array_assign.h for documentation */ +NPY_NO_EXPORT int +array_assign_scalar(PyArrayObject *dst, + PyArray_Descr *src_dtype, char *src_data, + PyArrayObject *wheremask, + NPY_CASTING casting, npy_bool overwritena) +{ + int copied_src_data = 0, dst_has_maskna = PyArray_HASMASKNA(dst); + + /* Check the casting rule */ + if (!can_cast_scalar_to(src_dtype, src_data, + PyArray_DESCR(dst), casting)) { + PyObject *errmsg; + errmsg = PyUString_FromString("Cannot cast scalar from "); + PyUString_ConcatAndDel(&errmsg, + PyObject_Repr((PyObject *)src_dtype)); + PyUString_ConcatAndDel(&errmsg, + PyUString_FromString(" to ")); + PyUString_ConcatAndDel(&errmsg, + PyObject_Repr((PyObject *)PyArray_DESCR(dst))); + PyUString_ConcatAndDel(&errmsg, + PyUString_FromFormat(" according to the rule %s", + npy_casting_to_string(casting))); + PyErr_SetObject(PyExc_TypeError, errmsg); + return -1; + } + + /* + * Make a copy of the src data if it's a different dtype than 'dst' + * or isn't aligned, and the destination we're copying to has + * more than one element. + */ + if ((!PyArray_EquivTypes(PyArray_DESCR(dst), src_dtype) || + ((npy_intp)src_data & (src_dtype->alignment - 1)) != 0) && + PyArray_SIZE(dst) > 1) { + char *tmp_src_data; + + /* Allocate a new buffer to store the copied src data */ + tmp_src_data = PyArray_malloc(PyArray_DESCR(dst)->elsize); + copied_src_data = 1; + if (PyArray_CastRawArrays(1, src_data, tmp_src_data, 0, 0, + src_dtype, PyArray_DESCR(dst), 0) != NPY_SUCCEED) { + goto fail; + } + + /* Replace src_data/src_dtype */ + src_data = tmp_src_data; + src_dtype = PyArray_DESCR(dst); + } + + if (wheremask == NULL) { + /* This is the case of a straightforward value assignment */ + if (overwritena || !dst_has_maskna) { + /* If we're assigning to an array with a mask, set to all exposed */ + if (dst_has_maskna) { + if (PyArray_AssignMaskNA(dst, 1) < 0) { + goto fail; + } + } + + /* TODO: continuing here */ + if (raw_array_assign_scalar(PyArray_NDIM(dst), PyArray_DIMS(dst), + PyArray_DESCR(dst), PyArray_DATA(dst), PyArray_STRIDES(dst), + src_dtype, src_data) < 0) { + goto fail; + } + } + /* This is value assignment without overwriting NA values */ + else { + } + } + else { + /* This is the case of a straightforward masked assignment */ + if (overwritena || !dst_has_maskna) { + } + /* This is masked value assignment without overwriting NA values */ + else { + } + } + + if (copied_src_data) { + PyArray_free(src_data); + } + + return 0; + +fail: + if (copied_src_data) { + PyArray_free(src_data); + } + + return -1; +} diff --git a/numpy/core/src/multiarray/array_assign.h b/numpy/core/src/multiarray/array_assign.h new file mode 100644 index 000000000..68263c157 --- /dev/null +++ b/numpy/core/src/multiarray/array_assign.h @@ -0,0 +1,71 @@ +#ifndef _NPY_PRIVATE__ARRAY_ASSIGN_H_ +#define _NPY_PRIVATE__ARRAY_ASSIGN_H_ + +/* + * Assigns a scalar value specified by 'src_dtype' and 'src_data' + * to elements of 'dst'. + * + * dst: The destination array. + * src_dtype: The data type of the source scalar. + * src_data: The memory element of the source scalar. + * wheremask: If non-NULL, a boolean mask specifying where to copy. + * casting: An exception is raised if the assignment violates this + * casting rule. + * overwritena: If 1, overwrites everything in 'dst', if 0, it + * does not overwrite elements in 'dst' which are NA. + * + * Returns 0 on success, -1 on failure. + */ +NPY_NO_EXPORT int +array_assign_scalar(PyArrayObject *dst, + PyArray_Descr *src_dtype, char *src_data, + PyArrayObject *wheremask, + NPY_CASTING casting, npy_bool overwritena); + +/* + * An array assignment function for copying arrays, broadcasting 'src' into + * 'dst'. This function makes a temporary copy of 'src' if 'src' and + * 'dst' overlap, to be able to handle views of the same data with + * different strides. + * + * dst: The destination array. + * src: The source array. + * wheremask: If non-NULL, a boolean mask specifying where to copy. + * casting: An exception is raised if the copy violates this + * casting rule. + * overwritena: If 1, overwrites everything in 'dst', if 0, it + * does not overwrite elements in 'dst' which are NA. + * + * Returns 0 on success, -1 on failure. + */ +NPY_NO_EXPORT int +array_assign_broadcast(PyArrayObject *dst, PyArrayObject *src, + PyArrayObject *wheremask, + NPY_CASTING casting, npy_bool overwritena); + +/* + * An array assignment function for copying arrays, treating the + * arrays as flat according to their respective ordering rules. + * This function makes a temporary copy of 'src' if 'src' and + * 'dst' overlap, to be able to handle views of the same data with + * different strides. + * + * dst: The destination array. + * dst_order: The rule for how 'dst' is to be made flat. + * src: The source array. + * src_order: The rule for how 'src' is to be made flat. + * wheremask: If non-NULL, a boolean mask specifying where to copy. + * casting: An exception is raised if the copy violates this + * casting rule. + * overwritena: If 1, overwrites everything in 'dst', if 0, it + * does not overwrite elements in 'dst' which are NA. + * + * Returns 0 on success, -1 on failure. + */ +NPY_NO_EXPORT int +array_assign_flat(PyArrayObject *dst, NPY_ORDER dst_order, + PyArrayObject *src, NPY_ORDER src_order, + PyArrayObject *wheremask, + NPY_CASTING casting, npy_bool overwritena); + +#endif diff --git a/numpy/core/src/multiarray/convert_datatype.c b/numpy/core/src/multiarray/convert_datatype.c index e5cd965aa..fa0d6b4bb 100644 --- a/numpy/core/src/multiarray/convert_datatype.c +++ b/numpy/core/src/multiarray/convert_datatype.c @@ -639,6 +639,62 @@ PyArray_CanCastTypeTo(PyArray_Descr *from, PyArray_Descr *to, static int min_scalar_type_num(char *valueptr, int type_num, int *is_small_unsigned); +NPY_NO_EXPORT npy_bool +can_cast_scalar_to(PyArray_Descr *scal_type, char *scal_data, + PyArray_Descr *to, NPY_CASTING casting) +{ + int swap; + int is_small_unsigned = 0, type_num; + npy_bool ret; + PyArray_Descr *dtype; + + /* An aligned memory buffer large enough to hold any type */ + npy_longlong value[4]; + + if (casting == NPY_UNSAFE_CASTING) { + return 1; + } + + /* + * If the scalar isn't a number, or the rule is stricter than + * NPY_SAFE_CASTING, use the straight type-based rules + */ + if (!PyTypeNum_ISNUMBER(scal_type->type_num) || + casting < NPY_SAFE_CASTING) { + return PyArray_CanCastTypeTo(scal_type, to, casting); + } + + swap = !PyArray_ISNBO(scal_type->byteorder); + scal_type->f->copyswap(&value, scal_data, swap, NULL); + + type_num = min_scalar_type_num((char *)&value, scal_type->type_num, + &is_small_unsigned); + + /* + * If we've got a small unsigned scalar, and the 'to' type + * is not unsigned, then make it signed to allow the value + * to be cast more appropriately. + */ + if (is_small_unsigned && !(PyTypeNum_ISUNSIGNED(to->type_num))) { + type_num = type_num_unsigned_to_signed(type_num); + } + + dtype = PyArray_DescrFromType(type_num); + if (dtype == NULL) { + return 0; + } +#if 0 + printf("min scalar cast "); + PyObject_Print(dtype, stdout, 0); + printf(" to "); + PyObject_Print(to, stdout, 0); + printf("\n"); +#endif + ret = PyArray_CanCastTypeTo(dtype, to, casting); + Py_DECREF(dtype); + return ret; +} + /*NUMPY_API * Returns 1 if the array object may be cast to the given data type using * the casting rule, 0 otherwise. This differs from PyArray_CanCastTo in @@ -652,47 +708,12 @@ PyArray_CanCastArrayTo(PyArrayObject *arr, PyArray_Descr *to, PyArray_Descr *from = PyArray_DESCR(arr); /* If it's not a scalar, use the standard rules */ - if (PyArray_NDIM(arr) > 0 || !PyTypeNum_ISNUMBER(from->type_num)) { + if (PyArray_NDIM(arr) > 0) { return PyArray_CanCastTypeTo(from, to, casting); } /* Otherwise, check the value */ else { - int swap = !PyArray_ISNBO(from->byteorder); - int is_small_unsigned = 0, type_num; - npy_bool ret; - PyArray_Descr *dtype; - - /* An aligned memory buffer large enough to hold any type */ - npy_longlong value[4]; - - from->f->copyswap(&value, PyArray_BYTES(arr), swap, NULL); - - type_num = min_scalar_type_num((char *)&value, from->type_num, - &is_small_unsigned); - - /* - * If we've got a small unsigned scalar, and the 'to' type - * is not unsigned, then make it signed to allow the value - * to be cast more appropriately. - */ - if (is_small_unsigned && !(PyTypeNum_ISUNSIGNED(to->type_num))) { - type_num = type_num_unsigned_to_signed(type_num); - } - - dtype = PyArray_DescrFromType(type_num); - if (dtype == NULL) { - return 0; - } -#if 0 - printf("min scalar cast "); - PyObject_Print(dtype, stdout, 0); - printf(" to "); - PyObject_Print(to, stdout, 0); - printf("\n"); -#endif - ret = PyArray_CanCastTypeTo(dtype, to, casting); - Py_DECREF(dtype); - return ret; + return can_cast_scalar_to(from, PyArray_DATA(arr), to, casting); } } diff --git a/numpy/core/src/multiarray/convert_datatype.h b/numpy/core/src/multiarray/convert_datatype.h index 71001b1c4..bf77d699a 100644 --- a/numpy/core/src/multiarray/convert_datatype.h +++ b/numpy/core/src/multiarray/convert_datatype.h @@ -13,6 +13,11 @@ PyArray_ConvertToCommonType(PyObject *op, int *retn); NPY_NO_EXPORT int PyArray_ValidType(int type); +/* Like PyArray_CanCastArrayTo */ +NPY_NO_EXPORT npy_bool +can_cast_scalar_to(PyArray_Descr *scal_type, char *scal_data, + PyArray_Descr *to, NPY_CASTING casting); + /* * This function calls Py_DECREF on flex_dtype, and replaces it with * a new dtype that has been adapted based on the values in data_dtype diff --git a/numpy/core/src/multiarray/na_mask.c b/numpy/core/src/multiarray/na_mask.c index bfc79a4eb..286fe5c1b 100644 --- a/numpy/core/src/multiarray/na_mask.c +++ b/numpy/core/src/multiarray/na_mask.c @@ -477,6 +477,8 @@ PyArray_ReduceMaskNAArray(int ndim, npy_intp *shape, npy_intp src_strides_it[NPY_MAXDIMS]; npy_intp dst_strides_it[NPY_MAXDIMS]; + char *saved_dst_data = dst_data; + /* Confirm that dst is not larger than src */ for (idim = 0; idim < ndim; ++idim) { if (src_strides[idim] == 0 && dst_strides[idim] != 0) { @@ -513,6 +515,8 @@ PyArray_ReduceMaskNAArray(int ndim, npy_intp *shape, { int i; printf("Dump of raw iter:\n"); + printf("dst data: %p\n", dst_data); + printf("original dst data: %p\n", saved_dst_data); printf("ndim: %d\n", ndim); printf("shape: "); for (i = 0; i < ndim; ++i) printf("%d ", (int)shape[i]); @@ -561,6 +565,7 @@ PyArray_ReduceMaskNAArray(int ndim, npy_intp *shape, printf("s%d/d%d>>", (int)*src_d, (int)*dst_d); *dst_d &= *src_d; printf("d%d ", (int)*dst_d); +printf("%p ", dst_d); src_d += src_strides_it[0]; dst_d += dst_strides_it[0]; } diff --git a/numpy/core/src/umath/ufunc_object.c b/numpy/core/src/umath/ufunc_object.c index 3586e2ac2..9102f92b1 100644 --- a/numpy/core/src/umath/ufunc_object.c +++ b/numpy/core/src/umath/ufunc_object.c @@ -2705,9 +2705,9 @@ allocate_or_conform_reduce_result(PyArrayObject *arr, PyArrayObject *out, npy_bool *axis_flags, PyArray_Descr * otype_dtype, int addmask) { - if (out == NULL) { - PyArrayObject *result; + PyArrayObject *result; + if (out == NULL) { Py_INCREF(otype_dtype); result = allocate_reduce_result(arr, axis_flags, otype_dtype); @@ -2718,12 +2718,12 @@ allocate_or_conform_reduce_result(PyArrayObject *arr, PyArrayObject *out, return NULL; } } - - return result; } else { - return conform_reduce_result(PyArray_NDIM(arr), axis_flags, out); + result = conform_reduce_result(PyArray_NDIM(arr), axis_flags, out); } + + return result; } /* @@ -3077,6 +3077,13 @@ PyUFunc_Reduce(PyUFuncObject *self, PyArrayObject *arr, PyArrayObject *out, goto fail; } +if (ndim == 2 && PyArray_HASMASKNA(result)) { + printf ("after reduce maskna %d %d %d\n", + (int)PyArray_MASKNA_DATA(result)[0], + (int)PyArray_MASKNA_DATA(result)[1], + (int)PyArray_MASKNA_DATA(result)[2]); +} + /* Short circuit any calculation if the result 0-dim NA */ if (PyArray_SIZE(result) == 1 && !NpyMaskValue_IsExposed( @@ -3125,6 +3132,12 @@ PyUFunc_Reduce(PyUFuncObject *self, PyArrayObject *arr, PyArrayObject *out, goto fail; } +if (ndim == 2 && PyArray_HASMASKNA(result)) { + printf ("after initialize reduce result maskna %d %d %d\n", + (int)PyArray_MASKNA_DATA(result)[0], + (int)PyArray_MASKNA_DATA(result)[1], + (int)PyArray_MASKNA_DATA(result)[2]); +} /* Now we can do a loop applying the ufunc in a straightforward manner */ op[0] = result; op[1] = arr_view; @@ -3220,6 +3233,12 @@ PyUFunc_Reduce(PyUFuncObject *self, PyArrayObject *arr, PyArrayObject *out, } /* Masked reduction */ else { +if (ndim == 2 && PyArray_HASMASKNA(result)) { + printf ("before inner loop %d %d %d\n", + (int)PyArray_MASKNA_DATA(result)[0], + (int)PyArray_MASKNA_DATA(result)[1], + (int)PyArray_MASKNA_DATA(result)[2]); +} do { /* Turn the two items into three for the inner loop */ dataptr_copy[0] = dataptr[0]; @@ -3236,6 +3255,12 @@ PyUFunc_Reduce(PyUFuncObject *self, PyArrayObject *arr, PyArrayObject *out, stride_copy, stride[2], maskedinnerloopdata); } while (iternext(iter)); } +if (ndim == 2 && PyArray_HASMASKNA(result)) { + printf ("after inner loop %d %d %d\n", + (int)PyArray_MASKNA_DATA(result)[0], + (int)PyArray_MASKNA_DATA(result)[1], + (int)PyArray_MASKNA_DATA(result)[2]); +} if (!needs_api) { NPY_END_THREADS; @@ -3250,7 +3275,27 @@ finish: /* Strip out the extra 'one' dimensions in the result */ if (out == NULL) { + int print = PyArray_NDIM(result) == 2 && PyArray_HASMASKNA(result); +if (print) { + printf("maskna data %p\n", PyArray_MASKNA_DATA(result)); + printf("maskna strides %d %d\n", (int)PyArray_MASKNA_STRIDES(result)[0],(int)PyArray_MASKNA_STRIDES(result)[1]); + printf ("maskna %d %d %d\n", + (int)PyArray_MASKNA_DATA(result)[0], + (int)PyArray_MASKNA_DATA(result)[1], + (int)PyArray_MASKNA_DATA(result)[2]); + PyObject_Print(result, stdout, 0); + printf("\n"); +} strip_flagged_dimensions(result, axis_flags); +if (print) { + printf("maskna stride %d\n", (int)PyArray_MASKNA_STRIDES(result)[0]); + printf ("maskna %d %d %d\n", + (int)PyArray_MASKNA_DATA(result)[0], + (int)PyArray_MASKNA_DATA(result)[1], + (int)PyArray_MASKNA_DATA(result)[2]); + PyObject_Print(result, stdout, 0); + printf("\n\n"); +} } else { Py_DECREF(result); |