diff options
-rw-r--r-- | .github/workflows/wheels.yml | 2 | ||||
-rw-r--r-- | README.md | 2 | ||||
-rw-r--r-- | doc/source/user/c-info.ufunc-tutorial.rst | 241 | ||||
-rw-r--r-- | numpy/core/_add_newdocs.py | 19 | ||||
-rw-r--r-- | numpy/core/setup.py | 7 | ||||
-rw-r--r-- | numpy/core/src/multiarray/dragon4.c | 13 | ||||
-rw-r--r-- | numpy/core/src/umath/ufunc_object.c | 8 | ||||
-rw-r--r-- | numpy/core/tests/test_scalarprint.py | 1 | ||||
-rw-r--r-- | numpy/core/tests/test_ufunc.py | 11 |
9 files changed, 168 insertions, 136 deletions
diff --git a/.github/workflows/wheels.yml b/.github/workflows/wheels.yml index afebe7f93..b17b478ab 100644 --- a/.github/workflows/wheels.yml +++ b/.github/workflows/wheels.yml @@ -3,7 +3,7 @@ # # if: github.repository == 'numpy/numpy' # -# in the get_commit_message job. Be sure to include [cd build] in your commit +# in the get_commit_message job. Be sure to include [wheel build] in your commit # message to trigger the build. All files related to wheel building are located # at tools/wheels/ name: Wheel builder @@ -49,7 +49,7 @@ Code of Conduct ---------------------- NumPy is a community-driven open source project developed by a diverse group of -[contributors](https://numpy.org/gallery/team.html). The NumPy leadership has made a strong +[contributors](https://numpy.org/teams/). The NumPy leadership has made a strong commitment to creating an open, inclusive, and positive community. Please read the [NumPy Code of Conduct](https://numpy.org/code-of-conduct/) for guidance on how to interact with others in a way that makes our community thrive. diff --git a/doc/source/user/c-info.ufunc-tutorial.rst b/doc/source/user/c-info.ufunc-tutorial.rst index 9bd01b963..3a406479b 100644 --- a/doc/source/user/c-info.ufunc-tutorial.rst +++ b/doc/source/user/c-info.ufunc-tutorial.rst @@ -71,11 +71,11 @@ Example Non-ufunc extension pair: ufunc; adding new For comparison and general edification of the reader we provide -a simple implementation of a C extension of logit that uses no +a simple implementation of a C extension of ``logit`` that uses no numpy. To do this we need two files. The first is the C file which contains -the actual code, and the second is the setup.py file used to create +the actual code, and the second is the ``setup.py`` file used to create the module. .. code-block:: c @@ -99,8 +99,7 @@ the module. /* This declares the logit function */ - static PyObject* spam_logit(PyObject *self, PyObject *args); - + static PyObject *spam_logit(PyObject *self, PyObject *args); /* * This tells Python what methods this module has. @@ -113,13 +112,12 @@ the module. {NULL, NULL, 0, NULL} }; - /* * This actually defines the logit function for * input args from Python. */ - static PyObject* spam_logit(PyObject *self, PyObject *args) + static PyObject *spam_logit(PyObject *self, PyObject *args) { double p; @@ -136,7 +134,6 @@ the module. return Py_BuildValue("d", p); } - /* This initiates the module using the above definitions. */ static struct PyModuleDef moduledef = { PyModuleDef_HEAD_INIT, @@ -160,10 +157,10 @@ the module. return m; } -To use the setup.py file, place setup.py and spammodule.c in the same -folder. Then python setup.py build will build the module to import, -or setup.py install will install the module to your site-packages -directory. +To use the ``setup.py file``, place ``setup.py`` and ``spammodule.c`` +in the same folder. Then ``python setup.py build`` will build the module to +import, or ``python setup.py install`` will install the module to your +site-packages directory. .. code-block:: python @@ -203,9 +200,9 @@ directory. Once the spam module is imported into python, you can call logit -via spam.logit. Note that the function used above cannot be applied -as-is to numpy arrays. To do so we must call numpy.vectorize on it. -For example, if a python interpreter is opened in the file containing +via ``spam.logit``. Note that the function used above cannot be applied +as-is to numpy arrays. To do so we must call :py:func:`numpy.vectorize` +on it. For example, if a python interpreter is opened in the file containing the spam library or spam has been installed, one can perform the following commands: @@ -225,10 +222,10 @@ TypeError: only length-1 arrays can be converted to Python scalars array([ -inf, -2.07944154, -1.25276297, -0.69314718, -0.22314355, 0.22314355, 0.69314718, 1.25276297, 2.07944154, inf]) -THE RESULTING LOGIT FUNCTION IS NOT FAST! numpy.vectorize simply -loops over spam.logit. The loop is done at the C level, but the numpy +THE RESULTING LOGIT FUNCTION IS NOT FAST! ``numpy.vectorize`` simply +loops over ``spam.logit``. The loop is done at the C level, but the numpy array is constantly being parsed and build back up. This is expensive. -When the author compared numpy.vectorize(spam.logit) against the +When the author compared ``numpy.vectorize(spam.logit)`` against the logit ufuncs constructed below, the logit ufuncs were almost exactly 4 times faster. Larger or smaller speedups are, of course, possible depending on the nature of the function. @@ -242,13 +239,14 @@ Example NumPy ufunc for one dtype .. index:: pair: ufunc; adding new -For simplicity we give a ufunc for a single dtype, the 'f8' double. -As in the previous section, we first give the .c file and then the -setup.py file used to create the module containing the ufunc. +For simplicity we give a ufunc for a single dtype, the ``'f8'`` +``double``. As in the previous section, we first give the ``.c`` file +and then the ``setup.py`` file used to create the module containing the +ufunc. The place in the code corresponding to the actual computations for -the ufunc are marked with /\*BEGIN main ufunc computation\*/ and -/\*END main ufunc computation\*/. The code in between those lines is +the ufunc are marked with ``/\* BEGIN main ufunc computation \*/`` and +``/\* END main ufunc computation \*/``. The code in between those lines is the primary thing that must be changed to create your own ufunc. .. code-block:: c @@ -277,13 +275,13 @@ the primary thing that must be changed to create your own ufunc. */ static PyMethodDef LogitMethods[] = { - {NULL, NULL, 0, NULL} + {NULL, NULL, 0, NULL} }; /* The loop definition must precede the PyMODINIT_FUNC. */ - static void double_logit(char **args, npy_intp *dimensions, - npy_intp* steps, void* data) + static void double_logit(char **args, const npy_intp *dimensions, + const npy_intp *steps, void *data) { npy_intp i; npy_intp n = dimensions[0]; @@ -293,25 +291,23 @@ the primary thing that must be changed to create your own ufunc. double tmp; for (i = 0; i < n; i++) { - /*BEGIN main ufunc computation*/ + /* BEGIN main ufunc computation */ tmp = *(double *)in; - tmp /= 1-tmp; + tmp /= 1 - tmp; *((double *)out) = log(tmp); - /*END main ufunc computation*/ + /* END main ufunc computation */ in += in_step; out += out_step; } } - /*This a pointer to the above function*/ + /* This a pointer to the above function */ PyUFuncGenericFunction funcs[1] = {&double_logit}; /* These are the input and return dtypes of logit.*/ static char types[2] = {NPY_DOUBLE, NPY_DOUBLE}; - static void *data[1] = {NULL}; - static struct PyModuleDef moduledef = { PyModuleDef_HEAD_INIT, "npufunc", @@ -335,7 +331,7 @@ the primary thing that must be changed to create your own ufunc. import_array(); import_umath(); - logit = PyUFunc_FromFuncAndData(funcs, data, types, 1, 1, 1, + logit = PyUFunc_FromFuncAndData(funcs, NULL, types, 1, 1, 1, PyUFunc_None, "logit", "logit_docstring", 0); @@ -347,21 +343,23 @@ the primary thing that must be changed to create your own ufunc. return m; } -This is a setup.py file for the above code. As before, the module -can be build via calling python setup.py build at the command prompt, -or installed to site-packages via python setup.py install. +This is a ``setup.py file`` for the above code. As before, the module +can be build via calling ``python setup.py build`` at the command prompt, +or installed to site-packages via ``python setup.py install``. The module +can also be placed into a local folder e.g. ``npufunc_directory`` below +using ``python setup.py build_ext --inplace``. .. code-block:: python ''' - setup.py file for logit.c + setup.py file for single_type_logit.c Note that since this is a numpy extension we use numpy.distutils instead of distutils from the python standard library. Calling $python setup.py build_ext --inplace - will build the extension library in the current file. + will build the extension library in the npufunc_directory. Calling $python setup.py build @@ -382,7 +380,6 @@ or installed to site-packages via python setup.py install. def configuration(parent_package='', top_path=None): - import numpy from numpy.distutils.misc_util import Configuration config = Configuration('npufunc_directory', @@ -418,13 +415,13 @@ Example NumPy ufunc with multiple dtypes We finally give an example of a full ufunc, with inner loops for half-floats, floats, doubles, and long doubles. As in the previous -sections we first give the .c file and then the corresponding -setup.py file. +sections we first give the ``.c`` file and then the corresponding +``setup.py`` file. The places in the code corresponding to the actual computations for -the ufunc are marked with /\*BEGIN main ufunc computation\*/ and -/\*END main ufunc computation\*/. The code in between those lines is -the primary thing that must be changed to create your own ufunc. +the ufunc are marked with ``/\* BEGIN main ufunc computation \*/`` and +``/\* END main ufunc computation \*/``. The code in between those lines +is the primary thing that must be changed to create your own ufunc. .. code-block:: c @@ -455,37 +452,36 @@ the primary thing that must be changed to create your own ufunc. * */ - static PyMethodDef LogitMethods[] = { - {NULL, NULL, 0, NULL} + {NULL, NULL, 0, NULL} }; /* The loop definitions must precede the PyMODINIT_FUNC. */ - static void long_double_logit(char **args, npy_intp *dimensions, - npy_intp* steps, void* data) + static void long_double_logit(char **args, const npy_intp *dimensions, + const npy_intp *steps, void *data) { npy_intp i; npy_intp n = dimensions[0]; - char *in = args[0], *out=args[1]; + char *in = args[0], *out = args[1]; npy_intp in_step = steps[0], out_step = steps[1]; long double tmp; for (i = 0; i < n; i++) { - /*BEGIN main ufunc computation*/ + /* BEGIN main ufunc computation */ tmp = *(long double *)in; - tmp /= 1-tmp; + tmp /= 1 - tmp; *((long double *)out) = logl(tmp); - /*END main ufunc computation*/ + /* END main ufunc computation */ in += in_step; out += out_step; } } - static void double_logit(char **args, npy_intp *dimensions, - npy_intp* steps, void* data) + static void double_logit(char **args, const npy_intp *dimensions, + const npy_intp *steps, void *data) { npy_intp i; npy_intp n = dimensions[0]; @@ -495,33 +491,33 @@ the primary thing that must be changed to create your own ufunc. double tmp; for (i = 0; i < n; i++) { - /*BEGIN main ufunc computation*/ + /* BEGIN main ufunc computation */ tmp = *(double *)in; - tmp /= 1-tmp; + tmp /= 1 - tmp; *((double *)out) = log(tmp); - /*END main ufunc computation*/ + /* END main ufunc computation */ in += in_step; out += out_step; } } - static void float_logit(char **args, npy_intp *dimensions, - npy_intp* steps, void* data) + static void float_logit(char **args, const npy_intp *dimensions, + const npy_intp *steps, void *data) { npy_intp i; npy_intp n = dimensions[0]; - char *in=args[0], *out = args[1]; + char *in = args[0], *out = args[1]; npy_intp in_step = steps[0], out_step = steps[1]; float tmp; for (i = 0; i < n; i++) { - /*BEGIN main ufunc computation*/ + /* BEGIN main ufunc computation */ tmp = *(float *)in; - tmp /= 1-tmp; + tmp /= 1 - tmp; *((float *)out) = logf(tmp); - /*END main ufunc computation*/ + /* END main ufunc computation */ in += in_step; out += out_step; @@ -529,8 +525,8 @@ the primary thing that must be changed to create your own ufunc. } - static void half_float_logit(char **args, npy_intp *dimensions, - npy_intp* steps, void* data) + static void half_float_logit(char **args, const npy_intp *dimensions, + const npy_intp *steps, void *data) { npy_intp i; npy_intp n = dimensions[0]; @@ -541,13 +537,12 @@ the primary thing that must be changed to create your own ufunc. for (i = 0; i < n; i++) { - /*BEGIN main ufunc computation*/ - tmp = *(npy_half *)in; - tmp = npy_half_to_float(tmp); - tmp /= 1-tmp; + /* BEGIN main ufunc computation */ + tmp = npy_half_to_float(*(npy_half *)in); + tmp /= 1 - tmp; tmp = logf(tmp); *((npy_half *)out) = npy_float_to_half(tmp); - /*END main ufunc computation*/ + /* END main ufunc computation */ in += in_step; out += out_step; @@ -562,10 +557,9 @@ the primary thing that must be changed to create your own ufunc. &long_double_logit}; static char types[8] = {NPY_HALF, NPY_HALF, - NPY_FLOAT, NPY_FLOAT, - NPY_DOUBLE,NPY_DOUBLE, - NPY_LONGDOUBLE, NPY_LONGDOUBLE}; - static void *data[4] = {NULL, NULL, NULL, NULL}; + NPY_FLOAT, NPY_FLOAT, + NPY_DOUBLE, NPY_DOUBLE, + NPY_LONGDOUBLE, NPY_LONGDOUBLE}; static struct PyModuleDef moduledef = { PyModuleDef_HEAD_INIT, @@ -590,7 +584,7 @@ the primary thing that must be changed to create your own ufunc. import_array(); import_umath(); - logit = PyUFunc_FromFuncAndData(funcs, data, types, 4, 1, 1, + logit = PyUFunc_FromFuncAndData(funcs, NULL, types, 4, 1, 1, PyUFunc_None, "logit", "logit_docstring", 0); @@ -602,14 +596,14 @@ the primary thing that must be changed to create your own ufunc. return m; } -This is a setup.py file for the above code. As before, the module -can be build via calling python setup.py build at the command prompt, -or installed to site-packages via python setup.py install. +This is a ``setup.py`` file for the above code. As before, the module +can be build via calling ``python setup.py build`` at the command prompt, +or installed to site-packages via ``python setup.py install``. .. code-block:: python ''' - setup.py file for logit.c + setup.py file for multi_type_logit.c Note that since this is a numpy extension we use numpy.distutils instead of distutils from the python standard library. @@ -637,9 +631,7 @@ or installed to site-packages via python setup.py install. def configuration(parent_package='', top_path=None): - import numpy - from numpy.distutils.misc_util import Configuration - from numpy.distutils.misc_util import get_info + from numpy.distutils.misc_util import Configuration, get_info #Necessary for the half-float d-type. info = get_info('npymath') @@ -676,10 +668,10 @@ Example NumPy ufunc with multiple arguments/return values Our final example is a ufunc with multiple arguments. It is a modification of the code for a logit ufunc for data with a single dtype. We -compute (A*B, logit(A*B)). +compute ``(A * B, logit(A * B))``. We only give the C code as the setup.py file is exactly the same as -the setup.py file in `Example NumPy ufunc for one dtype`_, except that +the ``setup.py`` file in `Example NumPy ufunc for one dtype`_, except that the line .. code-block:: python @@ -692,9 +684,9 @@ is replaced with config.add_extension('npufunc', ['multi_arg_logit.c']) -The C file is given below. The ufunc generated takes two arguments A -and B. It returns a tuple whose first element is A*B and whose second -element is logit(A*B). Note that it automatically supports broadcasting, +The C file is given below. The ufunc generated takes two arguments ``A`` +and ``B``. It returns a tuple whose first element is ``A * B`` and whose second +element is ``logit(A * B)``. Note that it automatically supports broadcasting, as well as all other properties of a ufunc. .. code-block:: c @@ -716,19 +708,17 @@ as well as all other properties of a ufunc. * * Details explaining the Python-C API can be found under * 'Extending and Embedding' and 'Python/C API' at - * docs.python.org . - * + * docs.python.org. */ - static PyMethodDef LogitMethods[] = { - {NULL, NULL, 0, NULL} + {NULL, NULL, 0, NULL} }; /* The loop definition must precede the PyMODINIT_FUNC. */ - static void double_logitprod(char **args, npy_intp *dimensions, - npy_intp* steps, void* data) + static void double_logitprod(char **args, const npy_intp *dimensions, + const npy_intp *steps, void *data) { npy_intp i; npy_intp n = dimensions[0]; @@ -740,12 +730,12 @@ as well as all other properties of a ufunc. double tmp; for (i = 0; i < n; i++) { - /*BEGIN main ufunc computation*/ + /* BEGIN main ufunc computation */ tmp = *(double *)in1; tmp *= *(double *)in2; *((double *)out1) = tmp; - *((double *)out2) = log(tmp/(1-tmp)); - /*END main ufunc computation*/ + *((double *)out2) = log(tmp / (1 - tmp)); + /* END main ufunc computation */ in1 += in1_step; in2 += in2_step; @@ -754,7 +744,6 @@ as well as all other properties of a ufunc. } } - /*This a pointer to the above function*/ PyUFuncGenericFunction funcs[1] = {&double_logitprod}; @@ -763,9 +752,6 @@ as well as all other properties of a ufunc. static char types[4] = {NPY_DOUBLE, NPY_DOUBLE, NPY_DOUBLE, NPY_DOUBLE}; - - static void *data[1] = {NULL}; - static struct PyModuleDef moduledef = { PyModuleDef_HEAD_INIT, "npufunc", @@ -789,7 +775,7 @@ as well as all other properties of a ufunc. import_array(); import_umath(); - logit = PyUFunc_FromFuncAndData(funcs, data, types, 1, 2, 2, + logit = PyUFunc_FromFuncAndData(funcs, NULL, types, 1, 2, 2, PyUFunc_None, "logit", "logit_docstring", 0); @@ -809,13 +795,13 @@ Example NumPy ufunc with structured array dtype arguments This example shows how to create a ufunc for a structured array dtype. For the example we show a trivial ufunc for adding two arrays with dtype -'u8,u8,u8'. The process is a bit different from the other examples since +``'u8,u8,u8'``. The process is a bit different from the other examples since a call to :c:func:`PyUFunc_FromFuncAndData` doesn't fully register ufuncs for custom dtypes and structured array dtypes. We need to also call :c:func:`PyUFunc_RegisterLoopForDescr` to finish setting up the ufunc. -We only give the C code as the setup.py file is exactly the same as -the setup.py file in `Example NumPy ufunc for one dtype`_, except that +We only give the C code as the ``setup.py`` file is exactly the same as +the ``setup.py`` file in `Example NumPy ufunc for one dtype`_, except that the line .. code-block:: python @@ -839,7 +825,6 @@ The C file is given below. #include "numpy/npy_3kcompat.h" #include <math.h> - /* * add_triplet.c * This is the C code for creating your own @@ -847,7 +832,7 @@ The C file is given below. * * Details explaining the Python-C API can be found under * 'Extending and Embedding' and 'Python/C API' at - * docs.python.org . + * docs.python.org. */ static PyMethodDef StructUfuncTestMethods[] = { @@ -856,25 +841,25 @@ The C file is given below. /* The loop definition must precede the PyMODINIT_FUNC. */ - static void add_uint64_triplet(char **args, npy_intp *dimensions, - npy_intp* steps, void* data) + static void add_uint64_triplet(char **args, const npy_intp *dimensions, + const npy_intp *steps, void *data) { npy_intp i; - npy_intp is1=steps[0]; - npy_intp is2=steps[1]; - npy_intp os=steps[2]; - npy_intp n=dimensions[0]; + npy_intp is1 = steps[0]; + npy_intp is2 = steps[1]; + npy_intp os = steps[2]; + npy_intp n = dimensions[0]; uint64_t *x, *y, *z; - char *i1=args[0]; - char *i2=args[1]; - char *op=args[2]; + char *i1 = args[0]; + char *i2 = args[1]; + char *op = args[2]; for (i = 0; i < n; i++) { - x = (uint64_t*)i1; - y = (uint64_t*)i2; - z = (uint64_t*)op; + x = (uint64_t *)i1; + y = (uint64_t *)i2; + z = (uint64_t *)op; z[0] = x[0] + y[0]; z[1] = x[1] + y[1]; @@ -892,8 +877,6 @@ The C file is given below. /* These are the input and return dtypes of add_uint64_triplet. */ static char types[3] = {NPY_UINT64, NPY_UINT64, NPY_UINT64}; - static void *data[1] = {NULL}; - static struct PyModuleDef moduledef = { PyModuleDef_HEAD_INIT, "struct_ufunc_test", @@ -924,11 +907,11 @@ The C file is given below. /* Create a new ufunc object */ add_triplet = PyUFunc_FromFuncAndData(NULL, NULL, NULL, 0, 2, 1, - PyUFunc_None, "add_triplet", - "add_triplet_docstring", 0); + PyUFunc_None, "add_triplet", + "add_triplet_docstring", 0); dtype_dict = Py_BuildValue("[(s, s), (s, s), (s, s)]", - "f0", "u8", "f1", "u8", "f2", "u8"); + "f0", "u8", "f1", "u8", "f2", "u8"); PyArray_DescrConverter(dtype_dict, &dtype); Py_DECREF(dtype_dict); @@ -938,10 +921,10 @@ The C file is given below. /* Register ufunc for structured dtype */ PyUFunc_RegisterLoopForDescr(add_triplet, - dtype, - &add_uint64_triplet, - dtypes, - NULL); + dtype, + &add_uint64_triplet, + dtypes, + NULL); d = PyModule_GetDict(m); @@ -963,9 +946,9 @@ adapted from the umath module static PyUFuncGenericFunction atan2_functions[] = { PyUFunc_ff_f, PyUFunc_dd_d, PyUFunc_gg_g, PyUFunc_OO_O_method}; - static void* atan2_data[] = { - (void *)atan2f,(void *) atan2, - (void *)atan2l,(void *)"arctan2"}; + static void *atan2_data[] = { + (void *)atan2f, (void *)atan2, + (void *)atan2l, (void *)"arctan2"}; static char atan2_signatures[] = { NPY_FLOAT, NPY_FLOAT, NPY_FLOAT, NPY_DOUBLE, NPY_DOUBLE, NPY_DOUBLE, diff --git a/numpy/core/_add_newdocs.py b/numpy/core/_add_newdocs.py index 523da75b3..a8d73af3f 100644 --- a/numpy/core/_add_newdocs.py +++ b/numpy/core/_add_newdocs.py @@ -2392,6 +2392,12 @@ add_newdoc('numpy.core.multiarray', 'ndarray', ('dtype', """ Data-type of the array's elements. + .. warning:: + + Setting ``arr.dtype`` is discouraged and may be deprecated in the + future. Setting will replace the ``dtype`` without modifying the + memory (see also `ndarray.view` and `ndarray.astype`). + Parameters ---------- None @@ -2402,6 +2408,8 @@ add_newdoc('numpy.core.multiarray', 'ndarray', ('dtype', See Also -------- + ndarray.astype : Cast the values contained in the array to a new data-type. + ndarray.view : Create a view of the same data but a different data-type. numpy.dtype Examples @@ -2627,6 +2635,11 @@ add_newdoc('numpy.core.multiarray', 'ndarray', ('shape', the array and the remaining dimensions. Reshaping an array in-place will fail if a copy is required. + .. warning:: + + Setting ``arr.shape`` is discouraged and may be deprecated in the + future. Using `ndarray.reshape` is the preferred approach. + Examples -------- >>> x = np.array([1, 2, 3, 4]) @@ -2697,6 +2710,12 @@ add_newdoc('numpy.core.multiarray', 'ndarray', ('strides', A more detailed explanation of strides can be found in the "ndarray.rst" file in the NumPy reference guide. + .. warning:: + + Setting ``arr.strides`` is discouraged and may be deprecated in the + future. `numpy.lib.stride_tricks.as_strided` should be preferred + to create a new view of the same data in a safer way. + Notes ----- Imagine an array of 32-bit integers (each 4 bytes):: diff --git a/numpy/core/setup.py b/numpy/core/setup.py index 0f2f3c210..a67a4cab6 100644 --- a/numpy/core/setup.py +++ b/numpy/core/setup.py @@ -24,6 +24,11 @@ NPY_RELAXED_STRIDES_CHECKING = (os.environ.get('NPY_RELAXED_STRIDES_CHECKING', " NPY_RELAXED_STRIDES_DEBUG = (os.environ.get('NPY_RELAXED_STRIDES_DEBUG', "0") != "0") NPY_RELAXED_STRIDES_DEBUG = NPY_RELAXED_STRIDES_DEBUG and NPY_RELAXED_STRIDES_CHECKING +# Set NPY_DISABLE_SVML=1 in the environment to disable the vendored SVML +# library. This option only has significance on a Linux x86_64 host and is most +# useful to avoid improperly requiring SVML when cross compiling. +NPY_DISABLE_SVML = (os.environ.get('NPY_DISABLE_SVML', "0") == "1") + # XXX: ugly, we use a class to avoid calling twice some expensive functions in # config.h/numpyconfig.h. I don't see a better way because distutils force # config.h generation inside an Extension class, and as such sharing @@ -68,6 +73,8 @@ def can_link_svml(): """SVML library is supported only on x86_64 architecture and currently only on linux """ + if NPY_DISABLE_SVML: + return False machine = platform.machine() system = platform.system() return "x86_64" in machine and system == "Linux" diff --git a/numpy/core/src/multiarray/dragon4.c b/numpy/core/src/multiarray/dragon4.c index ce0293615..5d245b106 100644 --- a/numpy/core/src/multiarray/dragon4.c +++ b/numpy/core/src/multiarray/dragon4.c @@ -1809,9 +1809,16 @@ FormatPositional(char *buffer, npy_uint32 bufferSize, BigInt *mantissa, pos--; numFractionDigits--; } - if (trim_mode == TrimMode_LeaveOneZero && buffer[pos-1] == '.') { - buffer[pos++] = '0'; - numFractionDigits++; + if (buffer[pos-1] == '.') { + /* in TrimMode_LeaveOneZero, add trailing 0 back */ + if (trim_mode == TrimMode_LeaveOneZero){ + buffer[pos++] = '0'; + numFractionDigits++; + } + /* in TrimMode_DptZeros, remove trailing decimal point */ + else if (trim_mode == TrimMode_DptZeros) { + pos--; + } } } diff --git a/numpy/core/src/umath/ufunc_object.c b/numpy/core/src/umath/ufunc_object.c index 52b354353..83e18a363 100644 --- a/numpy/core/src/umath/ufunc_object.c +++ b/numpy/core/src/umath/ufunc_object.c @@ -2764,9 +2764,13 @@ reducelike_promote_and_resolve(PyUFuncObject *ufunc, * The first operand and output should be the same array, so they should * be identical. The second argument can be different for reductions, * but is checked to be identical for accumulate and reduceat. + * Ideally, the type-resolver ensures that all are identical, but we do + * not enforce this here strictly. Otherwise correct handling of + * byte-order changes (or metadata) requires a lot of care; see gh-20699. */ - if (out_descrs[0] != out_descrs[2] || ( - enforce_uniform_args && out_descrs[0] != out_descrs[1])) { + if (!PyArray_EquivTypes(out_descrs[0], out_descrs[2]) || ( + enforce_uniform_args && !PyArray_EquivTypes( + out_descrs[0], out_descrs[1]))) { PyErr_Format(PyExc_TypeError, "the resolved dtypes are not compatible with %s.%s. " "Resolved (%R, %R, %R)", diff --git a/numpy/core/tests/test_scalarprint.py b/numpy/core/tests/test_scalarprint.py index ee21d4aa5..4deb5a0a4 100644 --- a/numpy/core/tests/test_scalarprint.py +++ b/numpy/core/tests/test_scalarprint.py @@ -306,6 +306,7 @@ class TestRealScalars: assert_equal(fpos(tp('1.2'), unique=False, precision=4, trim='-'), "1.2" if tp != np.float16 else "1.2002") assert_equal(fpos(tp('1.'), trim='-'), "1") + assert_equal(fpos(tp('1.001'), precision=1, trim='-'), "1") @pytest.mark.skipif(not platform.machine().startswith("ppc64"), reason="only applies to ppc float128 values") diff --git a/numpy/core/tests/test_ufunc.py b/numpy/core/tests/test_ufunc.py index 76e4cdcfd..9a9d46da0 100644 --- a/numpy/core/tests/test_ufunc.py +++ b/numpy/core/tests/test_ufunc.py @@ -2148,6 +2148,17 @@ class TestUfunc: # It would be safe, but not equiv casting: ufunc(a, c, out=out, casting="equiv") + def test_reducelike_byteorder_resolution(self): + # See gh-20699, byte-order changes need some extra care in the type + # resolution to make the following succeed: + arr_be = np.arange(10, dtype=">i8") + arr_le = np.arange(10, dtype="<i8") + + assert np.add.reduce(arr_be) == np.add.reduce(arr_le) + assert_array_equal(np.add.accumulate(arr_be), np.add.accumulate(arr_le)) + assert_array_equal( + np.add.reduceat(arr_be, [1]), np.add.reduceat(arr_le, [1])) + def test_reducelike_out_promotes(self): # Check that the out argument to reductions is considered for # promotion. See also gh-20455. |